xref: /reactos/dll/win32/msi/msi.c (revision 1734f297)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "msi.h"
32 #include "msidefs.h"
33 #include "msiquery.h"
34 #include "wincrypt.h"
35 #include "winver.h"
36 #include "winuser.h"
37 #include "shlobj.h"
38 #include "shobjidl.h"
39 #include "objidl.h"
40 #include "wintrust.h"
41 #include "softpub.h"
42 
43 #include "msipriv.h"
44 #include "winemsi_s.h"
45 
46 #include "initguid.h"
47 #include "msxml2.h"
48 
49 #include "wine/debug.h"
50 #include "wine/exception.h"
51 
52 WINE_DEFAULT_DEBUG_CHANNEL(msi);
53 
54 BOOL is_wow64;
55 
56 UINT msi_locate_product(LPCWSTR szProduct, MSIINSTALLCONTEXT *context)
57 {
58     HKEY hkey = NULL;
59 
60     *context = MSIINSTALLCONTEXT_NONE;
61     if (!szProduct) return ERROR_UNKNOWN_PRODUCT;
62 
63     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
64                               &hkey, FALSE) == ERROR_SUCCESS)
65         *context = MSIINSTALLCONTEXT_USERMANAGED;
66     else if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
67                                    &hkey, FALSE) == ERROR_SUCCESS)
68         *context = MSIINSTALLCONTEXT_MACHINE;
69     else if (MSIREG_OpenProductKey(szProduct, NULL,
70                                    MSIINSTALLCONTEXT_USERUNMANAGED,
71                                    &hkey, FALSE) == ERROR_SUCCESS)
72         *context = MSIINSTALLCONTEXT_USERUNMANAGED;
73 
74     RegCloseKey(hkey);
75 
76     if (*context == MSIINSTALLCONTEXT_NONE)
77         return ERROR_UNKNOWN_PRODUCT;
78 
79     return ERROR_SUCCESS;
80 }
81 
82 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
83 {
84     UINT r;
85     LPWSTR szwProd = NULL;
86 
87     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
88 
89     if( szProduct )
90     {
91         szwProd = strdupAtoW( szProduct );
92         if( !szwProd )
93             return ERROR_OUTOFMEMORY;
94     }
95 
96     r = MsiOpenProductW( szwProd, phProduct );
97 
98     msi_free( szwProd );
99 
100     return r;
101 }
102 
103 static UINT MSI_OpenProductW(LPCWSTR szProduct, MSIPACKAGE **package)
104 {
105     UINT r;
106     HKEY props;
107     LPWSTR path;
108     MSIINSTALLCONTEXT context;
109 
110     TRACE("%s %p\n", debugstr_w(szProduct), package);
111 
112     r = msi_locate_product(szProduct, &context);
113     if (r != ERROR_SUCCESS)
114         return r;
115 
116     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &props, FALSE);
117     if (r != ERROR_SUCCESS)
118         return ERROR_UNKNOWN_PRODUCT;
119 
120     if (context == MSIINSTALLCONTEXT_USERMANAGED)
121         path = msi_reg_get_val_str(props, L"ManagedLocalPackage");
122     else
123         path = msi_reg_get_val_str(props, L"LocalPackage");
124 
125     r = ERROR_UNKNOWN_PRODUCT;
126 
127     if (!path || GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
128         goto done;
129 
130     if (PathIsRelativeW(path))
131     {
132         r = ERROR_INSTALL_PACKAGE_OPEN_FAILED;
133         goto done;
134     }
135 
136     r = MSI_OpenPackageW(path, 0, package);
137 
138 done:
139     RegCloseKey(props);
140     msi_free(path);
141     return r;
142 }
143 
144 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
145 {
146     MSIPACKAGE *package = NULL;
147     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
148     UINT r;
149 
150     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
151         return ERROR_INVALID_PARAMETER;
152 
153     if (!phProduct)
154         return ERROR_INVALID_PARAMETER;
155 
156     r = MSI_OpenProductW(szProduct, &package);
157     if (r != ERROR_SUCCESS)
158         return r;
159 
160     *phProduct = alloc_msihandle(&package->hdr);
161     if (!*phProduct)
162         r = ERROR_NOT_ENOUGH_MEMORY;
163 
164     msiobj_release(&package->hdr);
165     return r;
166 }
167 
168 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
169                 LPCSTR szTransforms, LANGID lgidLanguage)
170 {
171     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
172           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
173     return ERROR_CALL_NOT_IMPLEMENTED;
174 }
175 
176 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
177                 LPCWSTR szTransforms, LANGID lgidLanguage)
178 {
179     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
180           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
181     return ERROR_CALL_NOT_IMPLEMENTED;
182 }
183 
184 UINT WINAPI MsiAdvertiseProductExA( const char *szPackagePath, const char *szScriptfilePath,
185                                     const char *szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions )
186 {
187     FIXME( "%s, %s, %s, %#x, %#lx, %#lx\n", debugstr_a(szPackagePath), debugstr_a(szScriptfilePath),
188            debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions );
189     return ERROR_CALL_NOT_IMPLEMENTED;
190 }
191 
192 UINT WINAPI MsiAdvertiseProductExW( const WCHAR *szPackagePath, const WCHAR *szScriptfilePath,
193                                     const WCHAR *szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions )
194 {
195     FIXME( "%s, %s, %s, %#x %#lx %#lx\n", debugstr_w(szPackagePath), debugstr_w(szScriptfilePath),
196            debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions );
197     return ERROR_CALL_NOT_IMPLEMENTED;
198 }
199 
200 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
201 {
202     LPWSTR szwPath = NULL, szwCommand = NULL;
203     UINT r = ERROR_OUTOFMEMORY;
204 
205     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
206 
207     if( szPackagePath )
208     {
209         szwPath = strdupAtoW( szPackagePath );
210         if( !szwPath )
211             goto end;
212     }
213 
214     if( szCommandLine )
215     {
216         szwCommand = strdupAtoW( szCommandLine );
217         if( !szwCommand )
218             goto end;
219     }
220 
221     r = MsiInstallProductW( szwPath, szwCommand );
222 
223 end:
224     msi_free( szwPath );
225     msi_free( szwCommand );
226 
227     return r;
228 }
229 
230 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
231 {
232     MSIPACKAGE *package = NULL;
233     const WCHAR *reinstallmode;
234     DWORD options = 0;
235     UINT r, len;
236 
237     TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
238 
239     if (!szPackagePath)
240         return ERROR_INVALID_PARAMETER;
241 
242     if (!*szPackagePath)
243         return ERROR_PATH_NOT_FOUND;
244 
245     reinstallmode = msi_get_command_line_option(szCommandLine, L"REINSTALLMODE", &len);
246     if (reinstallmode)
247     {
248         while (len > 0)
249         {
250             if (reinstallmode[--len] == 'v' || reinstallmode[len] == 'V')
251             {
252                 options |= WINE_OPENPACKAGEFLAGS_RECACHE;
253                 break;
254             }
255         }
256     }
257 
258     r = MSI_OpenPackageW( szPackagePath, options, &package );
259     if (r == ERROR_SUCCESS)
260     {
261         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
262         msiobj_release( &package->hdr );
263     }
264 
265     return r;
266 }
267 
268 UINT WINAPI MsiReinstallProductA( const char *szProduct, DWORD dwReinstallMode )
269 {
270     WCHAR *wszProduct;
271     UINT rc;
272 
273     TRACE( "%s, %#lx\n", debugstr_a(szProduct), dwReinstallMode );
274 
275     wszProduct = strdupAtoW(szProduct);
276     rc = MsiReinstallProductW(wszProduct, dwReinstallMode);
277     msi_free(wszProduct);
278     return rc;
279 }
280 
281 UINT WINAPI MsiReinstallProductW( const WCHAR *szProduct, DWORD dwReinstallMode )
282 {
283     TRACE( "%s, %#lx\n", debugstr_w(szProduct), dwReinstallMode );
284 
285     return MsiReinstallFeatureW(szProduct, L"ALL", dwReinstallMode);
286 }
287 
288 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
289         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
290 {
291     LPWSTR patch_package = NULL;
292     LPWSTR install_package = NULL;
293     LPWSTR command_line = NULL;
294     UINT r = ERROR_OUTOFMEMORY;
295 
296     TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
297           eInstallType, debugstr_a(szCommandLine));
298 
299     if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
300         goto done;
301 
302     if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
303         goto done;
304 
305     if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
306         goto done;
307 
308     r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
309 
310 done:
311     msi_free(patch_package);
312     msi_free(install_package);
313     msi_free(command_line);
314 
315     return r;
316 }
317 
318 static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR ***product_codes )
319 {
320     MSIHANDLE patch, info = 0;
321     UINT r, type;
322     DWORD size;
323     static WCHAR empty[] = L"";
324     WCHAR *codes = NULL;
325 
326     r = MsiOpenDatabaseW( szPatchPackage, MSIDBOPEN_READONLY, &patch );
327     if (r != ERROR_SUCCESS)
328         return r;
329 
330     r = MsiGetSummaryInformationW( patch, NULL, 0, &info );
331     if (r != ERROR_SUCCESS)
332         goto done;
333 
334     size = 0;
335     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, empty, &size );
336     if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
337     {
338         ERR("Failed to read product codes from patch\n");
339         r = ERROR_FUNCTION_FAILED;
340         goto done;
341     }
342 
343     codes = msi_alloc( ++size * sizeof(WCHAR) );
344     if (!codes)
345     {
346         r = ERROR_OUTOFMEMORY;
347         goto done;
348     }
349 
350     r = MsiSummaryInfoGetPropertyW( info, PID_TEMPLATE, &type, NULL, NULL, codes, &size );
351     if (r == ERROR_SUCCESS)
352         *product_codes = msi_split_string( codes, ';' );
353 
354 done:
355     MsiCloseHandle( info );
356     MsiCloseHandle( patch );
357     msi_free( codes );
358     return r;
359 }
360 
361 static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine)
362 {
363     UINT i, r = ERROR_FUNCTION_FAILED;
364     DWORD size;
365     LPCWSTR cmd_ptr = szCommandLine;
366     LPWSTR cmd, *codes = NULL;
367     BOOL succeeded = FALSE;
368 
369     if (!szPatchPackage || !szPatchPackage[0])
370         return ERROR_INVALID_PARAMETER;
371 
372     if (!szProductCode && (r = get_patch_product_codes( szPatchPackage, &codes )))
373         return r;
374 
375     if (!szCommandLine)
376         cmd_ptr = L"";
377 
378     size = lstrlenW(cmd_ptr) + lstrlenW(L"%s PATCH=\"%s\"") + lstrlenW(szPatchPackage) + 1;
379     cmd = msi_alloc(size * sizeof(WCHAR));
380     if (!cmd)
381     {
382         msi_free(codes);
383         return ERROR_OUTOFMEMORY;
384     }
385     swprintf(cmd, size, L"%s PATCH=\"%s\"", cmd_ptr, szPatchPackage);
386 
387     if (szProductCode)
388         r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
389     else
390     {
391         for (i = 0; codes[i]; i++)
392         {
393             r = MsiConfigureProductExW(codes[i], INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
394             if (r == ERROR_SUCCESS)
395             {
396                 TRACE("patch applied\n");
397                 succeeded = TRUE;
398             }
399         }
400 
401         if (succeeded)
402             r = ERROR_SUCCESS;
403     }
404 
405     msi_free(cmd);
406     msi_free(codes);
407     return r;
408 }
409 
410 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
411          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
412 {
413     TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
414           eInstallType, debugstr_w(szCommandLine));
415 
416     if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
417         eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
418     {
419         FIXME("Only reading target products from patch\n");
420         return ERROR_CALL_NOT_IMPLEMENTED;
421     }
422 
423     return MSI_ApplyPatchW(szPatchPackage, NULL, szCommandLine);
424 }
425 
426 UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR szPatchPackages,
427         LPCSTR szProductCode, LPCSTR szPropertiesList)
428 {
429     LPWSTR patch_packages = NULL;
430     LPWSTR product_code = NULL;
431     LPWSTR properties_list = NULL;
432     UINT r = ERROR_OUTOFMEMORY;
433 
434     TRACE("%s %s %s\n", debugstr_a(szPatchPackages), debugstr_a(szProductCode),
435           debugstr_a(szPropertiesList));
436 
437     if (!szPatchPackages || !szPatchPackages[0])
438         return ERROR_INVALID_PARAMETER;
439 
440     if (!(patch_packages = strdupAtoW(szPatchPackages)))
441         return ERROR_OUTOFMEMORY;
442 
443     if (szProductCode && !(product_code = strdupAtoW(szProductCode)))
444         goto done;
445 
446     if (szPropertiesList && !(properties_list = strdupAtoW(szPropertiesList)))
447         goto done;
448 
449     r = MsiApplyMultiplePatchesW(patch_packages, product_code, properties_list);
450 
451 done:
452     msi_free(patch_packages);
453     msi_free(product_code);
454     msi_free(properties_list);
455 
456     return r;
457 }
458 
459 UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
460         LPCWSTR szProductCode, LPCWSTR szPropertiesList)
461 {
462     UINT r = ERROR_SUCCESS;
463     LPCWSTR beg, end;
464 
465     TRACE("%s %s %s\n", debugstr_w(szPatchPackages), debugstr_w(szProductCode),
466           debugstr_w(szPropertiesList));
467 
468     if (!szPatchPackages || !szPatchPackages[0])
469         return ERROR_INVALID_PARAMETER;
470 
471     beg = end = szPatchPackages;
472     while (*beg)
473     {
474         DWORD len;
475         LPWSTR patch;
476 
477         while (*beg == ' ') beg++;
478         while (*end && *end != ';') end++;
479 
480         len = end - beg;
481         while (len && beg[len - 1] == ' ') len--;
482 
483         if (!len) return ERROR_INVALID_NAME;
484 
485         patch = msi_alloc((len + 1) * sizeof(WCHAR));
486         if (!patch)
487             return ERROR_OUTOFMEMORY;
488 
489         memcpy(patch, beg, len * sizeof(WCHAR));
490         patch[len] = '\0';
491 
492         r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
493         msi_free(patch);
494 
495         if (r != ERROR_SUCCESS || !*end)
496             break;
497 
498         beg = ++end;
499     }
500     return r;
501 }
502 
503 static void free_patchinfo( DWORD count, MSIPATCHSEQUENCEINFOW *info )
504 {
505     DWORD i;
506     for (i = 0; i < count; i++) msi_free( (WCHAR *)info[i].szPatchData );
507     msi_free( info );
508 }
509 
510 static MSIPATCHSEQUENCEINFOW *patchinfoAtoW( DWORD count, const MSIPATCHSEQUENCEINFOA *info )
511 {
512     DWORD i;
513     MSIPATCHSEQUENCEINFOW *ret;
514 
515     if (!(ret = msi_alloc( count * sizeof(MSIPATCHSEQUENCEINFOW) ))) return NULL;
516     for (i = 0; i < count; i++)
517     {
518         if (info[i].szPatchData && !(ret[i].szPatchData = strdupAtoW( info[i].szPatchData )))
519         {
520             free_patchinfo( i, ret );
521             return NULL;
522         }
523         ret[i].ePatchDataType = info[i].ePatchDataType;
524         ret[i].dwOrder = info[i].dwOrder;
525         ret[i].uStatus = info[i].uStatus;
526     }
527     return ret;
528 }
529 
530 UINT WINAPI MsiDetermineApplicablePatchesA( const char *szProductPackagePath, DWORD cPatchInfo,
531                                             MSIPATCHSEQUENCEINFOA *pPatchInfo )
532 {
533     UINT i, r;
534     WCHAR *package_path = NULL;
535     MSIPATCHSEQUENCEINFOW *psi;
536 
537     TRACE( "%s, %lu, %p\n", debugstr_a(szProductPackagePath), cPatchInfo, pPatchInfo );
538 
539     if (szProductPackagePath && !(package_path = strdupAtoW( szProductPackagePath )))
540         return ERROR_OUTOFMEMORY;
541 
542     if (!(psi = patchinfoAtoW( cPatchInfo, pPatchInfo )))
543     {
544         msi_free( package_path );
545         return ERROR_OUTOFMEMORY;
546     }
547     r = MsiDetermineApplicablePatchesW( package_path, cPatchInfo, psi );
548     if (r == ERROR_SUCCESS)
549     {
550         for (i = 0; i < cPatchInfo; i++)
551         {
552             pPatchInfo[i].dwOrder = psi[i].dwOrder;
553             pPatchInfo[i].uStatus = psi[i].uStatus;
554         }
555     }
556     msi_free( package_path );
557     free_patchinfo( cPatchInfo, psi );
558     return r;
559 }
560 
561 static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
562 {
563     MSISUMMARYINFO *si;
564     MSIDATABASE *patch_db;
565     UINT r;
566 
567     r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db );
568     if (r != ERROR_SUCCESS)
569     {
570         WARN("failed to open patch file %s\n", debugstr_w(patch));
571         return r;
572     }
573 
574     r = msi_get_suminfo( patch_db->storage, 0, &si );
575     if (r != ERROR_SUCCESS)
576     {
577         msiobj_release( &patch_db->hdr );
578         return ERROR_FUNCTION_FAILED;
579     }
580 
581     r = msi_check_patch_applicable( package, si );
582     if (r != ERROR_SUCCESS)
583         TRACE("patch not applicable\n");
584 
585     msiobj_release( &patch_db->hdr );
586     msiobj_release( &si->hdr );
587     return r;
588 }
589 
590 /* IXMLDOMDocument should be set to XPath mode already */
591 static UINT MSI_ApplicablePatchXML( MSIPACKAGE *package, IXMLDOMDocument *desc )
592 {
593     UINT r = ERROR_FUNCTION_FAILED;
594     IXMLDOMNodeList *list;
595     LPWSTR product_code;
596     IXMLDOMNode *node;
597     HRESULT hr;
598     BSTR s;
599 
600     product_code = msi_dup_property( package->db, L"ProductCode" );
601     if (!product_code)
602     {
603         /* FIXME: the property ProductCode should be written into the DB somewhere */
604         ERR("no product code to check\n");
605         return ERROR_SUCCESS;
606     }
607 
608     s = SysAllocString( L"MsiPatch/TargetProduct/TargetProductCode" );
609     hr = IXMLDOMDocument_selectNodes( desc, s, &list );
610     SysFreeString(s);
611     if (hr != S_OK)
612         return ERROR_INVALID_PATCH_XML;
613 
614     while (IXMLDOMNodeList_nextNode( list, &node ) == S_OK && r != ERROR_SUCCESS)
615     {
616         hr = IXMLDOMNode_get_text( node, &s );
617         IXMLDOMNode_Release( node );
618         if (hr == S_OK)
619         {
620             if (!wcscmp( s, product_code )) r = ERROR_SUCCESS;
621             SysFreeString( s );
622         }
623     }
624     IXMLDOMNodeList_Release( list );
625 
626     if (r != ERROR_SUCCESS)
627         TRACE("patch not applicable\n");
628 
629     msi_free( product_code );
630     return r;
631 }
632 
633 static UINT determine_patch_sequence( MSIPACKAGE *package, DWORD count, MSIPATCHSEQUENCEINFOW *info )
634 {
635     IXMLDOMDocument *desc = NULL;
636     DWORD i;
637 
638     if (count > 1)
639         FIXME("patch ordering not supported\n");
640 
641     for (i = 0; i < count; i++)
642     {
643         switch (info[i].ePatchDataType)
644         {
645         case MSIPATCH_DATATYPE_PATCHFILE:
646         {
647             if (MSI_ApplicablePatchW( package, info[i].szPatchData ) != ERROR_SUCCESS)
648             {
649                 info[i].dwOrder = ~0u;
650                 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
651             }
652             else
653             {
654                 info[i].dwOrder = i;
655                 info[i].uStatus = ERROR_SUCCESS;
656             }
657             break;
658         }
659         case MSIPATCH_DATATYPE_XMLPATH:
660         case MSIPATCH_DATATYPE_XMLBLOB:
661         {
662             VARIANT_BOOL b;
663             HRESULT hr;
664             BSTR s;
665 
666             if (!desc)
667             {
668                 hr = CoCreateInstance( &CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
669                     &IID_IXMLDOMDocument, (void**)&desc );
670                 if (hr != S_OK)
671                 {
672                     ERR( "failed to create DOMDocument30 instance, %#lx\n", hr );
673                     return ERROR_FUNCTION_FAILED;
674                 }
675             }
676 
677             s = SysAllocString( info[i].szPatchData );
678             if (info[i].ePatchDataType == MSIPATCH_DATATYPE_XMLPATH)
679             {
680                 VARIANT src;
681 
682                 V_VT(&src) = VT_BSTR;
683                 V_BSTR(&src) = s;
684                 hr = IXMLDOMDocument_load( desc, src, &b );
685             }
686             else
687                 hr = IXMLDOMDocument_loadXML( desc, s, &b );
688             SysFreeString( s );
689             if ( hr != S_OK )
690             {
691                 ERR("failed to parse patch description\n");
692                 IXMLDOMDocument_Release( desc );
693                 break;
694             }
695 
696             if (MSI_ApplicablePatchXML( package, desc ) != ERROR_SUCCESS)
697             {
698                 info[i].dwOrder = ~0u;
699                 info[i].uStatus = ERROR_PATCH_TARGET_NOT_FOUND;
700             }
701             else
702             {
703                 info[i].dwOrder = i;
704                 info[i].uStatus = ERROR_SUCCESS;
705             }
706             break;
707         }
708         default:
709         {
710             FIXME("unknown patch data type %u\n", info[i].ePatchDataType);
711             info[i].dwOrder = i;
712             info[i].uStatus = ERROR_SUCCESS;
713             break;
714         }
715         }
716 
717         TRACE("szPatchData: %s\n", debugstr_w(info[i].szPatchData));
718         TRACE("ePatchDataType: %u\n", info[i].ePatchDataType);
719         TRACE("dwOrder: %lu\n", info[i].dwOrder);
720         TRACE("uStatus: %u\n", info[i].uStatus);
721     }
722 
723     if (desc) IXMLDOMDocument_Release( desc );
724 
725     return ERROR_SUCCESS;
726 }
727 
728 UINT WINAPI MsiDetermineApplicablePatchesW( const WCHAR *szProductPackagePath, DWORD cPatchInfo,
729                                             MSIPATCHSEQUENCEINFOW *pPatchInfo )
730 {
731     UINT r;
732     MSIPACKAGE *package;
733 
734     TRACE( "%s, %lu, %p\n", debugstr_w(szProductPackagePath), cPatchInfo, pPatchInfo );
735 
736     r = MSI_OpenPackageW( szProductPackagePath, 0, &package );
737     if (r != ERROR_SUCCESS)
738     {
739         ERR("failed to open package %u\n", r);
740         return r;
741     }
742     r = determine_patch_sequence( package, cPatchInfo, pPatchInfo );
743     msiobj_release( &package->hdr );
744     return r;
745 }
746 
747 UINT WINAPI MsiDeterminePatchSequenceA( const char *product, const char *usersid, MSIINSTALLCONTEXT context,
748                                         DWORD count, MSIPATCHSEQUENCEINFOA *patchinfo )
749 {
750     UINT i, r;
751     WCHAR *productW, *usersidW = NULL;
752     MSIPATCHSEQUENCEINFOW *patchinfoW;
753 
754     TRACE( "%s, %s, %d, %lu, %p\n", debugstr_a(product), debugstr_a(usersid), context, count, patchinfo );
755 
756     if (!product) return ERROR_INVALID_PARAMETER;
757     if (!(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
758     if (usersid && !(usersidW = strdupAtoW( usersid )))
759     {
760         msi_free( productW );
761         return ERROR_OUTOFMEMORY;
762     }
763     if (!(patchinfoW = patchinfoAtoW( count, patchinfo )))
764     {
765         msi_free( productW );
766         msi_free( usersidW );
767         return ERROR_OUTOFMEMORY;
768     }
769     r = MsiDeterminePatchSequenceW( productW, usersidW, context, count, patchinfoW );
770     if (r == ERROR_SUCCESS)
771     {
772         for (i = 0; i < count; i++)
773         {
774             patchinfo[i].dwOrder = patchinfoW[i].dwOrder;
775             patchinfo[i].uStatus = patchinfoW[i].uStatus;
776         }
777     }
778     msi_free( productW );
779     msi_free( usersidW );
780     free_patchinfo( count, patchinfoW );
781     return r;
782 }
783 
784 static UINT open_package( const WCHAR *product, const WCHAR *usersid,
785                           MSIINSTALLCONTEXT context, MSIPACKAGE **package )
786 {
787     UINT r;
788     HKEY props;
789     WCHAR *localpath, sourcepath[MAX_PATH], filename[MAX_PATH];
790 
791     r = MSIREG_OpenInstallProps( product, context, usersid, &props, FALSE );
792     if (r != ERROR_SUCCESS) return ERROR_BAD_CONFIGURATION;
793 
794     if ((localpath = msi_reg_get_val_str( props, L"LocalPackage" )))
795     {
796         lstrcpyW( sourcepath, localpath );
797         msi_free( localpath );
798     }
799     RegCloseKey( props );
800     if (!localpath || GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
801     {
802         DWORD sz = sizeof(sourcepath);
803         MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
804                                INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
805         sz = sizeof(filename);
806         MsiSourceListGetInfoW( product, usersid, context, MSICODE_PRODUCT,
807                                INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
808         lstrcatW( sourcepath, filename );
809     }
810     if (GetFileAttributesW( sourcepath ) == INVALID_FILE_ATTRIBUTES)
811         return ERROR_INSTALL_SOURCE_ABSENT;
812 
813     return MSI_OpenPackageW( sourcepath, 0, package );
814 }
815 
816 UINT WINAPI MsiDeterminePatchSequenceW( const WCHAR *product, const WCHAR *usersid, MSIINSTALLCONTEXT context,
817                                         DWORD count, MSIPATCHSEQUENCEINFOW *patchinfo )
818 {
819     UINT r;
820     MSIPACKAGE *package;
821 
822     TRACE( "%s, %s, %d, %lu, %p\n", debugstr_w(product), debugstr_w(usersid), context, count, patchinfo );
823 
824     if (!product) return ERROR_INVALID_PARAMETER;
825     r = open_package( product, usersid, context, &package );
826     if (r != ERROR_SUCCESS) return r;
827 
828     r = determine_patch_sequence( package, count, patchinfo );
829     msiobj_release( &package->hdr );
830     return r;
831 }
832 
833 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
834                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
835 {
836     MSIPACKAGE* package = NULL;
837     MSIINSTALLCONTEXT context;
838     UINT r;
839     DWORD sz;
840     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
841     LPWSTR commandline;
842 
843     TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
844           debugstr_w(szCommandLine));
845 
846     if (!szProduct || lstrlenW(szProduct) != GUID_SIZE - 1)
847         return ERROR_INVALID_PARAMETER;
848 
849     if (eInstallState == INSTALLSTATE_ADVERTISED ||
850         eInstallState == INSTALLSTATE_SOURCE)
851     {
852         FIXME("State %d not implemented\n", eInstallState);
853         return ERROR_CALL_NOT_IMPLEMENTED;
854     }
855 
856     r = msi_locate_product(szProduct, &context);
857     if (r != ERROR_SUCCESS)
858         return r;
859 
860     r = open_package(szProduct, NULL, context, &package);
861     if (r != ERROR_SUCCESS)
862         return r;
863 
864     sz = lstrlenW(L" Installed=1") + 1;
865 
866     if (szCommandLine)
867         sz += lstrlenW(szCommandLine);
868 
869     if (eInstallState != INSTALLSTATE_DEFAULT)
870         sz += lstrlenW(L" INSTALLLEVEL=32767");
871 
872     if (eInstallState == INSTALLSTATE_ABSENT)
873         sz += lstrlenW(L" REMOVE=ALL");
874 
875     if (context == MSIINSTALLCONTEXT_MACHINE)
876         sz += lstrlenW(L" ALLUSERS=1");
877 
878     commandline = msi_alloc(sz * sizeof(WCHAR));
879     if (!commandline)
880     {
881         r = ERROR_OUTOFMEMORY;
882         goto end;
883     }
884 
885     commandline[0] = 0;
886     if (szCommandLine)
887         lstrcpyW(commandline, szCommandLine);
888 
889     if (eInstallState != INSTALLSTATE_DEFAULT)
890         lstrcatW(commandline, L" INSTALLLEVEL=32767");
891 
892     if (eInstallState == INSTALLSTATE_ABSENT)
893         lstrcatW(commandline, L" REMOVE=ALL");
894 
895     if (context == MSIINSTALLCONTEXT_MACHINE)
896         lstrcatW(commandline, L" ALLUSERS=1");
897 
898     sz = sizeof(sourcepath);
899     MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
900                           INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
901 
902     sz = sizeof(filename);
903     MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT,
904                           INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
905 
906     lstrcatW(sourcepath, filename);
907 
908     r = MSI_InstallPackage( package, sourcepath, commandline );
909 
910     msi_free(commandline);
911 
912 end:
913     msiobj_release( &package->hdr );
914 
915     return r;
916 }
917 
918 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
919                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
920 {
921     LPWSTR szwProduct = NULL;
922     LPWSTR szwCommandLine = NULL;
923     UINT r = ERROR_OUTOFMEMORY;
924 
925     if( szProduct )
926     {
927         szwProduct = strdupAtoW( szProduct );
928         if( !szwProduct )
929             goto end;
930     }
931 
932     if( szCommandLine)
933     {
934         szwCommandLine = strdupAtoW( szCommandLine );
935         if( !szwCommandLine)
936             goto end;
937     }
938 
939     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
940                                 szwCommandLine );
941 end:
942     msi_free( szwProduct );
943     msi_free( szwCommandLine);
944 
945     return r;
946 }
947 
948 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
949                                  INSTALLSTATE eInstallState)
950 {
951     LPWSTR szwProduct = NULL;
952     UINT r;
953 
954     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
955 
956     if( szProduct )
957     {
958         szwProduct = strdupAtoW( szProduct );
959         if( !szwProduct )
960             return ERROR_OUTOFMEMORY;
961     }
962 
963     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
964     msi_free( szwProduct );
965 
966     return r;
967 }
968 
969 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
970                                  INSTALLSTATE eInstallState)
971 {
972     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
973 }
974 
975 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
976 {
977     LPWSTR szwComponent = NULL;
978     UINT r;
979     WCHAR szwBuffer[GUID_SIZE];
980 
981     TRACE("%s %p\n", debugstr_a(szComponent), szBuffer);
982 
983     if( szComponent )
984     {
985         szwComponent = strdupAtoW( szComponent );
986         if( !szwComponent )
987             return ERROR_OUTOFMEMORY;
988     }
989 
990     *szwBuffer = '\0';
991     r = MsiGetProductCodeW( szwComponent, szwBuffer );
992 
993     if(*szwBuffer)
994         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
995 
996     msi_free( szwComponent );
997 
998     return r;
999 }
1000 
1001 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
1002 {
1003     UINT rc, index;
1004     HKEY compkey, prodkey;
1005     WCHAR squashed_comp[SQUASHED_GUID_SIZE], squashed_prod[SQUASHED_GUID_SIZE];
1006     DWORD sz = ARRAY_SIZE(squashed_prod);
1007 
1008     TRACE("%s %p\n", debugstr_w(szComponent), szBuffer);
1009 
1010     if (!szComponent || !*szComponent)
1011         return ERROR_INVALID_PARAMETER;
1012 
1013     if (!squash_guid( szComponent, squashed_comp ))
1014         return ERROR_INVALID_PARAMETER;
1015 
1016     if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &compkey, FALSE) != ERROR_SUCCESS &&
1017         MSIREG_OpenUserDataComponentKey(szComponent, L"S-1-5-18", &compkey, FALSE) != ERROR_SUCCESS)
1018     {
1019         return ERROR_UNKNOWN_COMPONENT;
1020     }
1021 
1022     rc = RegEnumValueW( compkey, 0, squashed_prod, &sz, NULL, NULL, NULL, NULL );
1023     if (rc != ERROR_SUCCESS)
1024     {
1025         RegCloseKey(compkey);
1026         return ERROR_UNKNOWN_COMPONENT;
1027     }
1028 
1029     /* check simple case, only one product */
1030     rc = RegEnumValueW( compkey, 1, squashed_prod, &sz, NULL, NULL, NULL, NULL );
1031     if (rc == ERROR_NO_MORE_ITEMS)
1032     {
1033         rc = ERROR_SUCCESS;
1034         goto done;
1035     }
1036 
1037     index = 0;
1038     while ((rc = RegEnumValueW( compkey, index, squashed_prod, &sz, NULL, NULL, NULL, NULL )) !=
1039            ERROR_NO_MORE_ITEMS)
1040     {
1041         index++;
1042         sz = GUID_SIZE;
1043         unsquash_guid( squashed_prod, szBuffer );
1044 
1045         if (MSIREG_OpenProductKey(szBuffer, NULL,
1046                                   MSIINSTALLCONTEXT_USERMANAGED,
1047                                   &prodkey, FALSE) == ERROR_SUCCESS ||
1048             MSIREG_OpenProductKey(szBuffer, NULL,
1049                                   MSIINSTALLCONTEXT_USERUNMANAGED,
1050                                   &prodkey, FALSE) == ERROR_SUCCESS ||
1051             MSIREG_OpenProductKey(szBuffer, NULL,
1052                                   MSIINSTALLCONTEXT_MACHINE,
1053                                   &prodkey, FALSE) == ERROR_SUCCESS)
1054         {
1055             RegCloseKey(prodkey);
1056             rc = ERROR_SUCCESS;
1057             goto done;
1058         }
1059     }
1060 
1061     rc = ERROR_INSTALL_FAILURE;
1062 
1063 done:
1064     RegCloseKey(compkey);
1065     unsquash_guid( squashed_prod, szBuffer );
1066     return rc;
1067 }
1068 
1069 static WCHAR *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type )
1070 {
1071     LONG res;
1072 
1073     if ((res = RegQueryValueExW( hkey, name, NULL, type, NULL, NULL )) != ERROR_SUCCESS) return NULL;
1074 
1075     if (*type == REG_SZ) return msi_reg_get_val_str( hkey, name );
1076     if (*type == REG_DWORD)
1077     {
1078         WCHAR temp[11];
1079         DWORD val;
1080 
1081         if (!msi_reg_get_val_dword( hkey, name, &val )) return NULL;
1082         swprintf( temp, ARRAY_SIZE(temp), L"%u", val );
1083         return strdupW( temp );
1084     }
1085 
1086     ERR( "unhandled value type %lu\n", *type );
1087     return NULL;
1088 }
1089 
1090 static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
1091                                awstring *szValue, LPDWORD pcchValueBuf)
1092 {
1093     static WCHAR empty[] = L"";
1094     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
1095     UINT r = ERROR_UNKNOWN_PROPERTY;
1096     HKEY prodkey, userdata, source;
1097     WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE], packagecode[GUID_SIZE];
1098     BOOL badconfig = FALSE;
1099     LONG res;
1100     DWORD type = REG_NONE;
1101 
1102     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1103           debugstr_w(szAttribute), szValue, pcchValueBuf);
1104 
1105     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
1106         return ERROR_INVALID_PARAMETER;
1107 
1108     if (!squash_guid( szProduct, squashed_pc ))
1109         return ERROR_INVALID_PARAMETER;
1110 
1111     if ((r = MSIREG_OpenProductKey(szProduct, NULL,
1112                                    MSIINSTALLCONTEXT_USERMANAGED,
1113                                    &prodkey, FALSE)) != ERROR_SUCCESS &&
1114         (r = MSIREG_OpenProductKey(szProduct, NULL,
1115                                    MSIINSTALLCONTEXT_USERUNMANAGED,
1116                                    &prodkey, FALSE)) != ERROR_SUCCESS &&
1117         (r = MSIREG_OpenProductKey(szProduct, NULL,
1118                                    MSIINSTALLCONTEXT_MACHINE,
1119                                     &prodkey, FALSE)) == ERROR_SUCCESS)
1120     {
1121         context = MSIINSTALLCONTEXT_MACHINE;
1122     }
1123 
1124     if (!wcscmp( szAttribute, INSTALLPROPERTY_HELPLINKW ) ||
1125         !wcscmp( szAttribute, INSTALLPROPERTY_HELPTELEPHONEW ) ||
1126         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLDATEW ) ||
1127         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
1128         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
1129         !wcscmp( szAttribute, INSTALLPROPERTY_INSTALLSOURCEW ) ||
1130         !wcscmp( szAttribute, INSTALLPROPERTY_LOCALPACKAGEW ) ||
1131         !wcscmp( szAttribute, INSTALLPROPERTY_PUBLISHERW ) ||
1132         !wcscmp( szAttribute, INSTALLPROPERTY_URLINFOABOUTW ) ||
1133         !wcscmp( szAttribute, INSTALLPROPERTY_URLUPDATEINFOW ) ||
1134         !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONMINORW ) ||
1135         !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONMAJORW ) ||
1136         !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ) ||
1137         !wcscmp( szAttribute, INSTALLPROPERTY_PRODUCTIDW ) ||
1138         !wcscmp( szAttribute, INSTALLPROPERTY_REGCOMPANYW ) ||
1139         !wcscmp( szAttribute, INSTALLPROPERTY_REGOWNERW ))
1140     {
1141         if (!prodkey)
1142         {
1143             r = ERROR_UNKNOWN_PRODUCT;
1144             goto done;
1145         }
1146         if (MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE))
1147         {
1148             r = ERROR_UNKNOWN_PROPERTY;
1149             goto done;
1150         }
1151 
1152         if (!wcscmp( szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
1153             szAttribute = L"DisplayName";
1154         else if (!wcscmp( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
1155             szAttribute = L"DisplayVersion";
1156 
1157         val = reg_get_value(userdata, szAttribute, &type);
1158         if (!val)
1159             val = empty;
1160         RegCloseKey(userdata);
1161     }
1162     else if (!wcscmp( szAttribute, INSTALLPROPERTY_INSTANCETYPEW ) ||
1163              !wcscmp( szAttribute, INSTALLPROPERTY_TRANSFORMSW ) ||
1164              !wcscmp( szAttribute, INSTALLPROPERTY_LANGUAGEW ) ||
1165              !wcscmp( szAttribute, INSTALLPROPERTY_PRODUCTNAMEW ) ||
1166              !wcscmp( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ) ||
1167              !wcscmp( szAttribute, INSTALLPROPERTY_PACKAGECODEW ) ||
1168              !wcscmp( szAttribute, INSTALLPROPERTY_VERSIONW ) ||
1169              !wcscmp( szAttribute, INSTALLPROPERTY_PRODUCTICONW ) ||
1170              !wcscmp( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ) ||
1171              !wcscmp( szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
1172     {
1173         if (!prodkey)
1174         {
1175             r = ERROR_UNKNOWN_PRODUCT;
1176             goto done;
1177         }
1178 
1179         if (!wcscmp( szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
1180             szAttribute = L"Assignment";
1181 
1182         if (!wcscmp( szAttribute, INSTALLPROPERTY_PACKAGENAMEW ))
1183         {
1184             res = RegOpenKeyW(prodkey, L"SourceList", &source);
1185             if (res != ERROR_SUCCESS)
1186             {
1187                 r = ERROR_UNKNOWN_PRODUCT;
1188                 goto done;
1189             }
1190 
1191             val = reg_get_value(source, szAttribute, &type);
1192             if (!val)
1193                 val = empty;
1194 
1195             RegCloseKey(source);
1196         }
1197         else
1198         {
1199             val = reg_get_value(prodkey, szAttribute, &type);
1200             if (!val)
1201                 val = empty;
1202         }
1203 
1204         if (val != empty && type != REG_DWORD &&
1205             !wcscmp( szAttribute, INSTALLPROPERTY_PACKAGECODEW ))
1206         {
1207             if (lstrlenW( val ) != SQUASHED_GUID_SIZE - 1)
1208                 badconfig = TRUE;
1209             else
1210             {
1211                 unsquash_guid(val, packagecode);
1212                 msi_free(val);
1213                 val = strdupW(packagecode);
1214             }
1215         }
1216     }
1217 
1218     if (!val)
1219     {
1220         r = ERROR_UNKNOWN_PROPERTY;
1221         goto done;
1222     }
1223 
1224     if (pcchValueBuf)
1225     {
1226         int len = lstrlenW( val );
1227 
1228         /* If szBuffer (szValue->str) is NULL, there's no need to copy the value
1229          * out.  Also, *pcchValueBuf may be uninitialized in this case, so we
1230          * can't rely on its value.
1231          */
1232         if (szValue->str.a || szValue->str.w)
1233         {
1234             DWORD size = *pcchValueBuf;
1235             if (len < size)
1236                 r = msi_strcpy_to_awstring( val, len, szValue, &size );
1237             else
1238                 r = ERROR_MORE_DATA;
1239         }
1240 
1241         if (!badconfig)
1242             *pcchValueBuf = len;
1243     }
1244 
1245     if (badconfig)
1246         r = ERROR_BAD_CONFIGURATION;
1247 
1248     if (val != empty)
1249         msi_free(val);
1250 
1251 done:
1252     RegCloseKey(prodkey);
1253     return r;
1254 }
1255 
1256 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
1257                                LPSTR szBuffer, LPDWORD pcchValueBuf)
1258 {
1259     LPWSTR szwProduct, szwAttribute = NULL;
1260     UINT r = ERROR_OUTOFMEMORY;
1261     awstring buffer;
1262 
1263     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
1264           szBuffer, pcchValueBuf);
1265 
1266     szwProduct = strdupAtoW( szProduct );
1267     if( szProduct && !szwProduct )
1268         goto end;
1269 
1270     szwAttribute = strdupAtoW( szAttribute );
1271     if( szAttribute && !szwAttribute )
1272         goto end;
1273 
1274     buffer.unicode = FALSE;
1275     buffer.str.a = szBuffer;
1276 
1277     r = MSI_GetProductInfo( szwProduct, szwAttribute,
1278                             &buffer, pcchValueBuf );
1279 
1280 end:
1281     msi_free( szwProduct );
1282     msi_free( szwAttribute );
1283 
1284     return r;
1285 }
1286 
1287 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
1288                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
1289 {
1290     awstring buffer;
1291 
1292     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
1293           szBuffer, pcchValueBuf);
1294 
1295     buffer.unicode = TRUE;
1296     buffer.str.w = szBuffer;
1297 
1298     return MSI_GetProductInfo( szProduct, szAttribute,
1299                                &buffer, pcchValueBuf );
1300 }
1301 
1302 UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
1303                                  MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
1304                                  LPSTR szValue, LPDWORD pcchValue)
1305 {
1306     LPWSTR product = NULL;
1307     LPWSTR usersid = NULL;
1308     LPWSTR property = NULL;
1309     LPWSTR value = NULL;
1310     DWORD len = 0;
1311     UINT r;
1312 
1313     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
1314           debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
1315            szValue, pcchValue);
1316 
1317     if (szValue && !pcchValue)
1318         return ERROR_INVALID_PARAMETER;
1319 
1320     if (szProductCode) product = strdupAtoW(szProductCode);
1321     if (szUserSid) usersid = strdupAtoW(szUserSid);
1322     if (szProperty) property = strdupAtoW(szProperty);
1323 
1324     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1325                              NULL, &len);
1326     if (r != ERROR_SUCCESS)
1327         goto done;
1328 
1329     value = msi_alloc(++len * sizeof(WCHAR));
1330     if (!value)
1331     {
1332         r = ERROR_OUTOFMEMORY;
1333         goto done;
1334     }
1335 
1336     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1337                              value, &len);
1338     if (r != ERROR_SUCCESS)
1339         goto done;
1340 
1341     if (!pcchValue)
1342         goto done;
1343 
1344     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
1345     if (*pcchValue >= len)
1346         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
1347     else if (szValue)
1348     {
1349         r = ERROR_MORE_DATA;
1350         if (*pcchValue > 0)
1351             *szValue = '\0';
1352     }
1353 
1354     if (*pcchValue <= len || !szValue)
1355         len = len * sizeof(WCHAR) - 1;
1356 
1357     *pcchValue = len - 1;
1358 
1359 done:
1360     msi_free(product);
1361     msi_free(usersid);
1362     msi_free(property);
1363     msi_free(value);
1364 
1365     return r;
1366 }
1367 
1368 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
1369 {
1370     UINT r = ERROR_SUCCESS;
1371 
1372     if (!val)
1373         return ERROR_UNKNOWN_PROPERTY;
1374 
1375     if (out)
1376     {
1377         if (lstrlenW(val) >= *size)
1378         {
1379             r = ERROR_MORE_DATA;
1380             if (*size > 0)
1381                 *out = '\0';
1382         }
1383         else
1384             lstrcpyW(out, val);
1385     }
1386 
1387     if (size)
1388         *size = lstrlenW(val);
1389 
1390     return r;
1391 }
1392 
1393 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
1394                                  MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
1395                                  LPWSTR szValue, LPDWORD pcchValue)
1396 {
1397     WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE];
1398     LPCWSTR package = NULL;
1399     HKEY props = NULL, prod, classes = NULL, managed, hkey = NULL;
1400     DWORD type;
1401     UINT r = ERROR_UNKNOWN_PRODUCT;
1402 
1403     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
1404           debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
1405            szValue, pcchValue);
1406 
1407     if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1408         return ERROR_INVALID_PARAMETER;
1409 
1410     if (szValue && !pcchValue)
1411         return ERROR_INVALID_PARAMETER;
1412 
1413     if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1414         dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1415         dwContext != MSIINSTALLCONTEXT_MACHINE)
1416         return ERROR_INVALID_PARAMETER;
1417 
1418     if (!szProperty || !*szProperty)
1419         return ERROR_INVALID_PARAMETER;
1420 
1421     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1422         return ERROR_INVALID_PARAMETER;
1423 
1424     /* FIXME: dwContext is provided, no need to search for it */
1425     MSIREG_OpenProductKey(szProductCode, NULL,MSIINSTALLCONTEXT_USERMANAGED,
1426                           &managed, FALSE);
1427     MSIREG_OpenProductKey(szProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1428                           &prod, FALSE);
1429 
1430     MSIREG_OpenInstallProps(szProductCode, dwContext, NULL, &props, FALSE);
1431 
1432     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1433     {
1434         package = INSTALLPROPERTY_LOCALPACKAGEW;
1435 
1436         if (!props && !prod)
1437             goto done;
1438     }
1439     else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1440     {
1441         package = L"ManagedLocalPackage";
1442 
1443         if (!props && !managed)
1444             goto done;
1445     }
1446     else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1447     {
1448         package = INSTALLPROPERTY_LOCALPACKAGEW;
1449         MSIREG_OpenProductKey(szProductCode, NULL, dwContext, &classes, FALSE);
1450 
1451         if (!props && !classes)
1452             goto done;
1453     }
1454 
1455     if (!wcscmp( szProperty, INSTALLPROPERTY_HELPLINKW ) ||
1456         !wcscmp( szProperty, INSTALLPROPERTY_HELPTELEPHONEW ) ||
1457         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLDATEW ) ||
1458         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ) ||
1459         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLLOCATIONW ) ||
1460         !wcscmp( szProperty, INSTALLPROPERTY_INSTALLSOURCEW ) ||
1461         !wcscmp( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ) ||
1462         !wcscmp( szProperty, INSTALLPROPERTY_PUBLISHERW ) ||
1463         !wcscmp( szProperty, INSTALLPROPERTY_URLINFOABOUTW ) ||
1464         !wcscmp( szProperty, INSTALLPROPERTY_URLUPDATEINFOW ) ||
1465         !wcscmp( szProperty, INSTALLPROPERTY_VERSIONMINORW ) ||
1466         !wcscmp( szProperty, INSTALLPROPERTY_VERSIONMAJORW ) ||
1467         !wcscmp( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ) ||
1468         !wcscmp( szProperty, INSTALLPROPERTY_PRODUCTIDW ) ||
1469         !wcscmp( szProperty, INSTALLPROPERTY_REGCOMPANYW ) ||
1470         !wcscmp( szProperty, INSTALLPROPERTY_REGOWNERW ) ||
1471         !wcscmp( szProperty, INSTALLPROPERTY_INSTANCETYPEW ))
1472     {
1473         val = reg_get_value(props, package, &type);
1474         if (!val)
1475         {
1476             if (prod || classes)
1477                 r = ERROR_UNKNOWN_PROPERTY;
1478 
1479             goto done;
1480         }
1481 
1482         msi_free(val);
1483 
1484         if (!wcscmp( szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW ))
1485             szProperty = L"DisplayName";
1486         else if (!wcscmp( szProperty, INSTALLPROPERTY_VERSIONSTRINGW ))
1487             szProperty = L"DisplayVersion";
1488 
1489         val = reg_get_value(props, szProperty, &type);
1490         if (!val)
1491             val = strdupW(L"");
1492 
1493         r = msi_copy_outval(val, szValue, pcchValue);
1494     }
1495     else if (!wcscmp( szProperty, INSTALLPROPERTY_TRANSFORMSW ) ||
1496              !wcscmp( szProperty, INSTALLPROPERTY_LANGUAGEW ) ||
1497              !wcscmp( szProperty, INSTALLPROPERTY_PRODUCTNAMEW ) ||
1498              !wcscmp( szProperty, INSTALLPROPERTY_PACKAGECODEW ) ||
1499              !wcscmp( szProperty, INSTALLPROPERTY_VERSIONW ) ||
1500              !wcscmp( szProperty, INSTALLPROPERTY_PRODUCTICONW ) ||
1501              !wcscmp( szProperty, INSTALLPROPERTY_PACKAGENAMEW ) ||
1502              !wcscmp( szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW ))
1503     {
1504         if (!prod && !classes)
1505             goto done;
1506 
1507         if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1508             hkey = prod;
1509         else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1510             hkey = managed;
1511         else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1512             hkey = classes;
1513 
1514         val = reg_get_value(hkey, szProperty, &type);
1515         if (!val)
1516             val = strdupW(L"");
1517 
1518         r = msi_copy_outval(val, szValue, pcchValue);
1519     }
1520     else if (!wcscmp( szProperty, INSTALLPROPERTY_PRODUCTSTATEW ))
1521     {
1522         if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1523         {
1524             if (props)
1525             {
1526                 val = reg_get_value(props, package, &type);
1527                 if (!val)
1528                     goto done;
1529 
1530                 msi_free(val);
1531                 val = strdupW(L"5");
1532             }
1533             else
1534                 val = strdupW(L"1");
1535 
1536             r = msi_copy_outval(val, szValue, pcchValue);
1537             goto done;
1538         }
1539         else if (props && (val = reg_get_value(props, package, &type)))
1540         {
1541             msi_free(val);
1542             val = strdupW(L"5");
1543             r = msi_copy_outval(val, szValue, pcchValue);
1544             goto done;
1545         }
1546 
1547         if (prod || managed)
1548             val = strdupW(L"1");
1549         else
1550             goto done;
1551 
1552         r = msi_copy_outval(val, szValue, pcchValue);
1553     }
1554     else if (!wcscmp( szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW ))
1555     {
1556         if (!prod && !classes)
1557             goto done;
1558 
1559         /* FIXME */
1560         val = strdupW(L"");
1561         r = msi_copy_outval(val, szValue, pcchValue);
1562     }
1563     else
1564         r = ERROR_UNKNOWN_PROPERTY;
1565 
1566 done:
1567     RegCloseKey(props);
1568     RegCloseKey(prod);
1569     RegCloseKey(managed);
1570     RegCloseKey(classes);
1571     msi_free(val);
1572 
1573     return r;
1574 }
1575 
1576 UINT WINAPI MsiGetPatchFileListA(LPCSTR szProductCode, LPCSTR szPatchList,
1577                                  LPDWORD pcFiles, MSIHANDLE **pphFileRecords)
1578 {
1579     FIXME("(%s, %s, %p, %p) stub!\n", debugstr_a(szProductCode),
1580           debugstr_a(szPatchList), pcFiles, pphFileRecords);
1581     return ERROR_FUNCTION_FAILED;
1582 }
1583 
1584 UINT WINAPI MsiGetPatchFileListW(LPCWSTR szProductCode, LPCWSTR szPatchList,
1585                                  LPDWORD pcFiles, MSIHANDLE **pphFileRecords)
1586 {
1587     FIXME("(%s, %s, %p, %p) stub!\n", debugstr_w(szProductCode),
1588           debugstr_w(szPatchList), pcFiles, pphFileRecords);
1589     return ERROR_FUNCTION_FAILED;
1590 }
1591 
1592 UINT WINAPI MsiGetPatchInfoExA(LPCSTR szPatchCode, LPCSTR szProductCode,
1593                                LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1594                                LPCSTR szProperty, LPSTR lpValue, DWORD *pcchValue)
1595 {
1596     LPWSTR patch = NULL, product = NULL, usersid = NULL;
1597     LPWSTR property = NULL, val = NULL;
1598     DWORD len;
1599     UINT r;
1600 
1601     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_a(szPatchCode),
1602           debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext,
1603           debugstr_a(szProperty), lpValue, pcchValue);
1604 
1605     if (lpValue && !pcchValue)
1606         return ERROR_INVALID_PARAMETER;
1607 
1608     if (szPatchCode) patch = strdupAtoW(szPatchCode);
1609     if (szProductCode) product = strdupAtoW(szProductCode);
1610     if (szUserSid) usersid = strdupAtoW(szUserSid);
1611     if (szProperty) property = strdupAtoW(szProperty);
1612 
1613     len = 0;
1614     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1615                            NULL, &len);
1616     if (r != ERROR_SUCCESS)
1617         goto done;
1618 
1619     val = msi_alloc(++len * sizeof(WCHAR));
1620     if (!val)
1621     {
1622         r = ERROR_OUTOFMEMORY;
1623         goto done;
1624     }
1625 
1626     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1627                            val, &len);
1628     if (r != ERROR_SUCCESS || !pcchValue)
1629         goto done;
1630 
1631     if (lpValue)
1632         WideCharToMultiByte(CP_ACP, 0, val, -1, lpValue,
1633                             *pcchValue - 1, NULL, NULL);
1634 
1635     len = lstrlenW(val);
1636     if ((*val && *pcchValue < len + 1) || !lpValue)
1637     {
1638         if (lpValue)
1639         {
1640             r = ERROR_MORE_DATA;
1641             lpValue[*pcchValue - 1] = '\0';
1642         }
1643 
1644         *pcchValue = len * sizeof(WCHAR);
1645     }
1646     else
1647         *pcchValue = len;
1648 
1649 done:
1650     msi_free(val);
1651     msi_free(patch);
1652     msi_free(product);
1653     msi_free(usersid);
1654     msi_free(property);
1655 
1656     return r;
1657 }
1658 
1659 UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
1660                                LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1661                                LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
1662 {
1663     WCHAR *val = NULL, squashed_pc[SQUASHED_GUID_SIZE], squashed_patch[SQUASHED_GUID_SIZE];
1664     HKEY udprod = 0, prod = 0, props = 0;
1665     HKEY patch = 0, patches = 0;
1666     HKEY udpatch = 0, datakey = 0;
1667     HKEY prodpatches = 0;
1668     UINT r = ERROR_UNKNOWN_PRODUCT;
1669     DWORD len, type;
1670     LONG res;
1671 
1672     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_w(szPatchCode),
1673           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext,
1674           debugstr_w(szProperty), lpValue, pcchValue);
1675 
1676     if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
1677         return ERROR_INVALID_PARAMETER;
1678 
1679     if (!szPatchCode || !squash_guid( szPatchCode, squashed_patch ))
1680         return ERROR_INVALID_PARAMETER;
1681 
1682     if (!szProperty)
1683         return ERROR_INVALID_PARAMETER;
1684 
1685     if (lpValue && !pcchValue)
1686         return ERROR_INVALID_PARAMETER;
1687 
1688     if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1689         dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1690         dwContext != MSIINSTALLCONTEXT_MACHINE)
1691         return ERROR_INVALID_PARAMETER;
1692 
1693     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1694         return ERROR_INVALID_PARAMETER;
1695 
1696     if (szUserSid && !wcscmp( szUserSid, L"S-1-5-18" ))
1697         return ERROR_INVALID_PARAMETER;
1698 
1699     if (MSIREG_OpenUserDataProductKey(szProductCode, dwContext, NULL,
1700                                       &udprod, FALSE) != ERROR_SUCCESS)
1701         goto done;
1702 
1703     if (MSIREG_OpenInstallProps(szProductCode, dwContext, NULL,
1704                                 &props, FALSE) != ERROR_SUCCESS)
1705         goto done;
1706 
1707     r = ERROR_UNKNOWN_PATCH;
1708 
1709     res = RegOpenKeyExW(udprod, L"Patches", 0, KEY_READ, &patches);
1710     if (res != ERROR_SUCCESS)
1711         goto done;
1712 
1713     res = RegOpenKeyExW( patches, squashed_patch, 0, KEY_READ, &patch );
1714     if (res != ERROR_SUCCESS)
1715         goto done;
1716 
1717     if (!wcscmp( szProperty, INSTALLPROPERTY_TRANSFORMSW ))
1718     {
1719         if (MSIREG_OpenProductKey(szProductCode, NULL, dwContext,
1720                                   &prod, FALSE) != ERROR_SUCCESS)
1721             goto done;
1722 
1723         res = RegOpenKeyExW(prod, L"Patches", 0, KEY_ALL_ACCESS, &prodpatches);
1724         if (res != ERROR_SUCCESS)
1725             goto done;
1726 
1727         datakey = prodpatches;
1728         szProperty = squashed_patch;
1729     }
1730     else
1731     {
1732         if (MSIREG_OpenUserDataPatchKey(szPatchCode, dwContext,
1733                                         &udpatch, FALSE) != ERROR_SUCCESS)
1734             goto done;
1735 
1736         if (!wcscmp( szProperty, INSTALLPROPERTY_LOCALPACKAGEW ))
1737         {
1738             if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1739                 szProperty = L"ManagedLocalPackage";
1740             datakey = udpatch;
1741         }
1742         else if (!wcscmp( szProperty, INSTALLPROPERTY_INSTALLDATEW ))
1743         {
1744             datakey = patch;
1745             szProperty = L"Installed";
1746         }
1747         else if (!wcscmp( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) ||
1748                  !wcscmp( szProperty, INSTALLPROPERTY_PATCHSTATEW ) ||
1749                  !wcscmp( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) ||
1750                  !wcscmp( szProperty, INSTALLPROPERTY_MOREINFOURLW ))
1751         {
1752             datakey = patch;
1753         }
1754         else
1755         {
1756             r = ERROR_UNKNOWN_PROPERTY;
1757             goto done;
1758         }
1759     }
1760 
1761     val = reg_get_value(datakey, szProperty, &type);
1762     if (!val)
1763         val = strdupW(L"");
1764 
1765     r = ERROR_SUCCESS;
1766 
1767     if (!pcchValue)
1768         goto done;
1769 
1770     if (lpValue)
1771         lstrcpynW(lpValue, val, *pcchValue);
1772 
1773     len = lstrlenW(val);
1774     if ((*val && *pcchValue < len + 1) || !lpValue)
1775     {
1776         if (lpValue)
1777             r = ERROR_MORE_DATA;
1778 
1779         *pcchValue = len * sizeof(WCHAR);
1780     }
1781 
1782     *pcchValue = len;
1783 
1784 done:
1785     msi_free(val);
1786     RegCloseKey(prodpatches);
1787     RegCloseKey(prod);
1788     RegCloseKey(patch);
1789     RegCloseKey(patches);
1790     RegCloseKey(udpatch);
1791     RegCloseKey(props);
1792     RegCloseKey(udprod);
1793 
1794     return r;
1795 }
1796 
1797 UINT WINAPI MsiGetPatchInfoA( LPCSTR patch, LPCSTR attr, LPSTR buffer, LPDWORD buflen )
1798 {
1799     UINT r = ERROR_OUTOFMEMORY;
1800     DWORD size;
1801     LPWSTR patchW = NULL, attrW = NULL, bufferW = NULL;
1802 
1803     TRACE("%s %s %p %p\n", debugstr_a(patch), debugstr_a(attr), buffer, buflen);
1804 
1805     if (!patch || !attr)
1806         return ERROR_INVALID_PARAMETER;
1807 
1808     if (!(patchW = strdupAtoW( patch )))
1809         goto done;
1810 
1811     if (!(attrW = strdupAtoW( attr )))
1812         goto done;
1813 
1814     size = 0;
1815     r = MsiGetPatchInfoW( patchW, attrW, NULL, &size );
1816     if (r != ERROR_SUCCESS)
1817         goto done;
1818 
1819     size++;
1820     if (!(bufferW = msi_alloc( size * sizeof(WCHAR) )))
1821     {
1822         r = ERROR_OUTOFMEMORY;
1823         goto done;
1824     }
1825 
1826     r = MsiGetPatchInfoW( patchW, attrW, bufferW, &size );
1827     if (r == ERROR_SUCCESS)
1828     {
1829         int len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
1830         if (len > *buflen)
1831             r = ERROR_MORE_DATA;
1832         else if (buffer)
1833             WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *buflen, NULL, NULL );
1834 
1835         *buflen = len - 1;
1836     }
1837 
1838 done:
1839     msi_free( patchW );
1840     msi_free( attrW );
1841     msi_free( bufferW );
1842     return r;
1843 }
1844 
1845 UINT WINAPI MsiGetPatchInfoW( LPCWSTR patch, LPCWSTR attr, LPWSTR buffer, LPDWORD buflen )
1846 {
1847     UINT r;
1848     WCHAR product[GUID_SIZE];
1849     DWORD index;
1850 
1851     TRACE("%s %s %p %p\n", debugstr_w(patch), debugstr_w(attr), buffer, buflen);
1852 
1853     if (!patch || !attr)
1854         return ERROR_INVALID_PARAMETER;
1855 
1856     if (wcscmp( INSTALLPROPERTY_LOCALPACKAGEW, attr ))
1857         return ERROR_UNKNOWN_PROPERTY;
1858 
1859     index = 0;
1860     while (1)
1861     {
1862         r = MsiEnumProductsW( index, product );
1863         if (r != ERROR_SUCCESS)
1864             break;
1865 
1866         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERMANAGED, attr, buffer, buflen );
1867         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
1868             return r;
1869 
1870         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, attr, buffer, buflen );
1871         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
1872             return r;
1873 
1874         r = MsiGetPatchInfoExW( patch, product, NULL, MSIINSTALLCONTEXT_MACHINE, attr, buffer, buflen );
1875         if (r == ERROR_SUCCESS || r == ERROR_MORE_DATA)
1876             return r;
1877 
1878         index++;
1879     }
1880 
1881     return ERROR_UNKNOWN_PRODUCT;
1882 }
1883 
1884 UINT WINAPI MsiEnableLogA( DWORD dwLogMode, const char *szLogFile, DWORD attributes )
1885 {
1886     LPWSTR szwLogFile = NULL;
1887     UINT r;
1888 
1889     TRACE( "%#lx, %s, %#lx\n", dwLogMode, debugstr_a(szLogFile), attributes );
1890 
1891     if( szLogFile )
1892     {
1893         szwLogFile = strdupAtoW( szLogFile );
1894         if( !szwLogFile )
1895             return ERROR_OUTOFMEMORY;
1896     }
1897     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
1898     msi_free( szwLogFile );
1899     return r;
1900 }
1901 
1902 UINT WINAPI MsiEnableLogW( DWORD dwLogMode, const WCHAR *szLogFile, DWORD attributes )
1903 {
1904     TRACE( "%#lx, %s, %#lx\n", dwLogMode, debugstr_w(szLogFile), attributes );
1905 
1906     msi_free(gszLogFile);
1907     gszLogFile = NULL;
1908     if (szLogFile)
1909     {
1910         HANDLE file;
1911 
1912         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
1913             DeleteFileW(szLogFile);
1914         file = CreateFileW(szLogFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
1915                            FILE_ATTRIBUTE_NORMAL, NULL);
1916         if (file != INVALID_HANDLE_VALUE)
1917         {
1918             gszLogFile = strdupW(szLogFile);
1919             CloseHandle(file);
1920         }
1921         else ERR( "unable to enable log %s (%lu)\n", debugstr_w(szLogFile), GetLastError() );
1922     }
1923 
1924     return ERROR_SUCCESS;
1925 }
1926 
1927 UINT WINAPI MsiEnumComponentCostsA( MSIHANDLE handle, const char *component, DWORD index, INSTALLSTATE state,
1928                                     char *drive, DWORD *buflen, int *cost, int *temp )
1929 {
1930     UINT r;
1931     DWORD len;
1932     WCHAR *driveW, *componentW = NULL;
1933 
1934     TRACE( "%lu, %s, %lu, %d, %p, %p, %p, %p\n", handle, debugstr_a(component), index, state, drive, buflen, cost,
1935            temp );
1936 
1937     if (!drive || !buflen) return ERROR_INVALID_PARAMETER;
1938     if (component && !(componentW = strdupAtoW( component ))) return ERROR_OUTOFMEMORY;
1939 
1940     len = *buflen;
1941     if (!(driveW = msi_alloc( len * sizeof(WCHAR) )))
1942     {
1943         msi_free( componentW );
1944         return ERROR_OUTOFMEMORY;
1945     }
1946     r = MsiEnumComponentCostsW( handle, componentW, index, state, driveW, buflen, cost, temp );
1947     if (!r)
1948     {
1949         WideCharToMultiByte( CP_ACP, 0, driveW, -1, drive, len, NULL, NULL );
1950     }
1951     msi_free( componentW );
1952     msi_free( driveW );
1953     return r;
1954 }
1955 
1956 static UINT set_drive( WCHAR *buffer, WCHAR letter )
1957 {
1958     buffer[0] = letter;
1959     buffer[1] = ':';
1960     buffer[2] = 0;
1961     return 2;
1962 }
1963 
1964 UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, const WCHAR *component, DWORD index, INSTALLSTATE state,
1965                                     WCHAR *drive, DWORD *buflen, int *cost, int *temp )
1966 {
1967     UINT r = ERROR_NO_MORE_ITEMS;
1968     MSICOMPONENT *comp = NULL;
1969     MSIPACKAGE *package;
1970     MSIFILE *file;
1971     STATSTG stat = {0};
1972     WCHAR path[MAX_PATH];
1973 
1974     TRACE( "%lu, %s, %lu, %d, %p, %p, %p, %p\n", handle, debugstr_w(component), index, state, drive, buflen, cost,
1975            temp );
1976 
1977     if (!drive || !buflen || !cost || !temp) return ERROR_INVALID_PARAMETER;
1978     if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE )))
1979     {
1980         WCHAR buffer[3];
1981         MSIHANDLE remote;
1982 
1983         if (!(remote = msi_get_remote(handle)))
1984             return ERROR_INVALID_HANDLE;
1985 
1986         __TRY
1987         {
1988             r = remote_EnumComponentCosts(remote, component, index, state, buffer, cost, temp);
1989         }
1990         __EXCEPT(rpc_filter)
1991         {
1992             r = GetExceptionCode();
1993         }
1994         __ENDTRY
1995 
1996         if (r == ERROR_SUCCESS)
1997         {
1998             lstrcpynW(drive, buffer, *buflen);
1999             if (*buflen < 3)
2000                 r = ERROR_MORE_DATA;
2001             *buflen = 2;
2002         }
2003         return r;
2004     }
2005 
2006     if (!msi_get_property_int( package->db, L"CostingComplete", 0 ))
2007     {
2008         msiobj_release( &package->hdr );
2009         return ERROR_FUNCTION_NOT_CALLED;
2010     }
2011     if (component && component[0] && !(comp = msi_get_loaded_component( package, component )))
2012     {
2013         msiobj_release( &package->hdr );
2014         return ERROR_UNKNOWN_COMPONENT;
2015     }
2016     if (*buflen < 3)
2017     {
2018         *buflen = 2;
2019         msiobj_release( &package->hdr );
2020         return ERROR_MORE_DATA;
2021     }
2022     if (index)
2023     {
2024         msiobj_release( &package->hdr );
2025         return ERROR_NO_MORE_ITEMS;
2026     }
2027 
2028     drive[0] = 0;
2029     *cost = *temp = 0;
2030     GetWindowsDirectoryW( path, MAX_PATH );
2031     if (component && component[0])
2032     {
2033         if (msi_is_global_assembly( comp )) *temp = comp->Cost;
2034         if (!comp->Enabled || !comp->KeyPath)
2035         {
2036             *cost = 0;
2037             *buflen = set_drive( drive, path[0] );
2038             r = ERROR_SUCCESS;
2039         }
2040         else if ((file = msi_get_loaded_file( package, comp->KeyPath )))
2041         {
2042             *cost = max( 8, comp->Cost / 512 );
2043             *buflen = set_drive( drive, file->TargetPath[0] );
2044             r = ERROR_SUCCESS;
2045         }
2046     }
2047     else if (IStorage_Stat( package->db->storage, &stat, STATFLAG_NONAME ) == S_OK)
2048     {
2049         *temp = max( 8, stat.cbSize.QuadPart / 512 );
2050         *buflen = set_drive( drive, path[0] );
2051         r = ERROR_SUCCESS;
2052     }
2053     msiobj_release( &package->hdr );
2054     return r;
2055 }
2056 
2057 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
2058                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
2059                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
2060 {
2061     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
2062     UINT r;
2063 
2064     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
2065           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
2066 
2067     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
2068         return ERROR_OUTOFMEMORY;
2069 
2070     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
2071             return ERROR_OUTOFMEMORY;
2072 
2073     if (szComponent && !(comp = strdupAtoW(szComponent)))
2074             return ERROR_OUTOFMEMORY;
2075 
2076     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
2077 
2078     msi_free(prodcode);
2079     msi_free(usersid);
2080     msi_free(comp);
2081 
2082     return r;
2083 }
2084 
2085 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
2086 {
2087     UINT r;
2088     HKEY hkey = NULL;
2089 
2090     r = MSIREG_OpenProductKey(prodcode, NULL, context, &hkey, FALSE);
2091     RegCloseKey(hkey);
2092     return (r == ERROR_SUCCESS);
2093 }
2094 
2095 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
2096 {
2097     LPCWSTR package;
2098     HKEY hkey;
2099     DWORD sz;
2100     LONG res;
2101     UINT r;
2102 
2103     r = MSIREG_OpenInstallProps(prodcode, context, NULL, &hkey, FALSE);
2104     if (r != ERROR_SUCCESS)
2105         return FALSE;
2106 
2107     if (context == MSIINSTALLCONTEXT_USERMANAGED)
2108         package = L"ManagedLocalPackage";
2109     else
2110         package = L"LocalPackage";
2111 
2112     sz = 0;
2113     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
2114     RegCloseKey(hkey);
2115 
2116     return (res == ERROR_SUCCESS);
2117 }
2118 
2119 static UINT msi_comp_find_prodcode(WCHAR *squashed_pc,
2120                                    MSIINSTALLCONTEXT context,
2121                                    LPCWSTR comp, LPWSTR val, DWORD *sz)
2122 {
2123     HKEY hkey;
2124     LONG res;
2125     UINT r;
2126 
2127     if (context == MSIINSTALLCONTEXT_MACHINE)
2128         r = MSIREG_OpenUserDataComponentKey(comp, L"S-1-5-18", &hkey, FALSE);
2129     else
2130         r = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
2131 
2132     if (r != ERROR_SUCCESS)
2133         return r;
2134 
2135     res = RegQueryValueExW( hkey, squashed_pc, NULL, NULL, (BYTE *)val, sz );
2136     if (res != ERROR_SUCCESS)
2137         return res;
2138 
2139     RegCloseKey(hkey);
2140     return res;
2141 }
2142 
2143 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
2144                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
2145                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
2146 {
2147     WCHAR squashed_pc[SQUASHED_GUID_SIZE];
2148     BOOL found;
2149     DWORD sz;
2150 
2151     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
2152           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
2153 
2154     if (!pdwState || !szComponent)
2155         return ERROR_INVALID_PARAMETER;
2156 
2157     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
2158         return ERROR_INVALID_PARAMETER;
2159 
2160     if (!squash_guid( szProductCode, squashed_pc ))
2161         return ERROR_INVALID_PARAMETER;
2162 
2163     found = msi_comp_find_prod_key(szProductCode, dwContext);
2164 
2165     if (!msi_comp_find_package(szProductCode, dwContext))
2166     {
2167         if (found)
2168         {
2169             *pdwState = INSTALLSTATE_UNKNOWN;
2170             return ERROR_UNKNOWN_COMPONENT;
2171         }
2172 
2173         return ERROR_UNKNOWN_PRODUCT;
2174     }
2175 
2176     *pdwState = INSTALLSTATE_UNKNOWN;
2177 
2178     sz = 0;
2179     if (msi_comp_find_prodcode( squashed_pc, dwContext, szComponent, NULL, &sz ))
2180         return ERROR_UNKNOWN_COMPONENT;
2181 
2182     if (sz == 0)
2183         *pdwState = INSTALLSTATE_NOTUSED;
2184     else
2185     {
2186         WCHAR *val;
2187         UINT r;
2188 
2189         if (!(val = msi_alloc( sz ))) return ERROR_OUTOFMEMORY;
2190         if ((r = msi_comp_find_prodcode( squashed_pc, dwContext, szComponent, val, &sz )))
2191         {
2192             msi_free(val);
2193             return r;
2194         }
2195 
2196         if (lstrlenW(val) > 2 &&
2197             val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9' && val[2] != ':')
2198         {
2199             *pdwState = INSTALLSTATE_SOURCE;
2200         }
2201         else
2202             *pdwState = INSTALLSTATE_LOCAL;
2203         msi_free( val );
2204     }
2205 
2206     TRACE("-> %d\n", *pdwState);
2207     return ERROR_SUCCESS;
2208 }
2209 
2210 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
2211 {
2212     LPWSTR szwProduct = NULL;
2213     INSTALLSTATE r;
2214 
2215     if( szProduct )
2216     {
2217          szwProduct = strdupAtoW( szProduct );
2218          if( !szwProduct )
2219              return ERROR_OUTOFMEMORY;
2220     }
2221     r = MsiQueryProductStateW( szwProduct );
2222     msi_free( szwProduct );
2223     return r;
2224 }
2225 
2226 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
2227 {
2228     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
2229     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
2230     HKEY prodkey = 0, userdata = 0;
2231     DWORD val;
2232     UINT r;
2233 
2234     TRACE("%s\n", debugstr_w(szProduct));
2235 
2236     if (!szProduct || !*szProduct)
2237         return INSTALLSTATE_INVALIDARG;
2238 
2239     if (lstrlenW(szProduct) != GUID_SIZE - 1)
2240         return INSTALLSTATE_INVALIDARG;
2241 
2242     if (szProduct[0] != '{' || szProduct[37] != '}')
2243         return INSTALLSTATE_UNKNOWN;
2244 
2245     SetLastError( ERROR_SUCCESS );
2246 
2247     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2248                               &prodkey, FALSE) != ERROR_SUCCESS &&
2249         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2250                               &prodkey, FALSE) != ERROR_SUCCESS &&
2251         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2252                               &prodkey, FALSE) == ERROR_SUCCESS)
2253     {
2254         context = MSIINSTALLCONTEXT_MACHINE;
2255     }
2256 
2257     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
2258     if (r != ERROR_SUCCESS)
2259         goto done;
2260 
2261     if (!msi_reg_get_val_dword(userdata, L"WindowsInstaller", &val))
2262         goto done;
2263 
2264     if (val)
2265         state = INSTALLSTATE_DEFAULT;
2266     else
2267         state = INSTALLSTATE_UNKNOWN;
2268 
2269 done:
2270     if (!prodkey)
2271     {
2272         state = INSTALLSTATE_UNKNOWN;
2273 
2274         if (userdata)
2275             state = INSTALLSTATE_ABSENT;
2276     }
2277 
2278     RegCloseKey(prodkey);
2279     RegCloseKey(userdata);
2280     TRACE("-> %d\n", state);
2281     return state;
2282 }
2283 
2284 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
2285 {
2286     INSTALLUILEVEL old = gUILevel;
2287     HWND oldwnd = gUIhwnd;
2288 
2289     TRACE("%08x %p\n", dwUILevel, phWnd);
2290 
2291     if (dwUILevel & ~(INSTALLUILEVEL_MASK|INSTALLUILEVEL_HIDECANCEL|INSTALLUILEVEL_PROGRESSONLY|
2292                       INSTALLUILEVEL_ENDDIALOG|INSTALLUILEVEL_SOURCERESONLY))
2293     {
2294         FIXME("Unrecognized flags %08x\n", dwUILevel);
2295         return INSTALLUILEVEL_NOCHANGE;
2296     }
2297 
2298     if (dwUILevel != INSTALLUILEVEL_NOCHANGE)
2299         gUILevel = dwUILevel;
2300 
2301     if (phWnd)
2302     {
2303         gUIhwnd = *phWnd;
2304         *phWnd = oldwnd;
2305     }
2306     return old;
2307 }
2308 
2309 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA( INSTALLUI_HANDLERA puiHandler, DWORD dwMessageFilter, void *pvContext )
2310 {
2311     INSTALLUI_HANDLERA prev = gUIHandlerA;
2312 
2313     TRACE( "%p, %#lx, %p\n", puiHandler, dwMessageFilter, pvContext );
2314 
2315     gUIHandlerA = puiHandler;
2316     gUIHandlerW = NULL;
2317     gUIFilter   = dwMessageFilter;
2318     gUIContext  = pvContext;
2319 
2320     return prev;
2321 }
2322 
2323 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW( INSTALLUI_HANDLERW puiHandler, DWORD dwMessageFilter, void *pvContext )
2324 {
2325     INSTALLUI_HANDLERW prev = gUIHandlerW;
2326 
2327     TRACE( "%p, %#lx, %p\n", puiHandler, dwMessageFilter, pvContext );
2328 
2329     gUIHandlerA = NULL;
2330     gUIHandlerW = puiHandler;
2331     gUIFilter   = dwMessageFilter;
2332     gUIContext  = pvContext;
2333 
2334     return prev;
2335 }
2336 
2337 /******************************************************************
2338  *  MsiLoadStringW            [MSI.@]
2339  *
2340  * Loads a string from MSI's string resources.
2341  *
2342  * PARAMS
2343  *
2344  *   handle        [I]  only -1 is handled currently
2345  *   id            [I]  id of the string to be loaded
2346  *   lpBuffer      [O]  buffer for the string to be written to
2347  *   nBufferMax    [I]  maximum size of the buffer in characters
2348  *   lang          [I]  the preferred language for the string
2349  *
2350  * RETURNS
2351  *
2352  *   If successful, this function returns the language id of the string loaded
2353  *   If the function fails, the function returns zero.
2354  *
2355  * NOTES
2356  *
2357  *   The type of the first parameter is unknown.  LoadString's prototype
2358  *  suggests that it might be a module handle.  I have made it an MSI handle
2359  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
2360  *  handle.  Maybe strings can be stored in an MSI database somehow.
2361  */
2362 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, WCHAR *lpBuffer, int nBufferMax, LANGID lang )
2363 {
2364     HRSRC hres;
2365     HGLOBAL hResData;
2366     LPWSTR p;
2367     DWORD i, len;
2368 
2369     TRACE( "%lu, %u, %p, %d, %#x\n", handle, id, lpBuffer, nBufferMax, lang );
2370 
2371     if( handle != -1 )
2372         FIXME( "don't know how to deal with handle = %lu\n", handle );
2373 
2374     if( !lang )
2375         lang = GetUserDefaultLangID();
2376 
2377     hres = FindResourceExW( msi_hInstance, (const WCHAR *)RT_STRING, (WCHAR *)1, lang );
2378     if( !hres )
2379         return 0;
2380     hResData = LoadResource( msi_hInstance, hres );
2381     if( !hResData )
2382         return 0;
2383     p = LockResource( hResData );
2384     if( !p )
2385         return 0;
2386 
2387     for (i = 0; i < (id & 0xf); i++) p += *p + 1;
2388     len = *p;
2389 
2390     if( nBufferMax <= len )
2391         return 0;
2392 
2393     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
2394     lpBuffer[ len ] = 0;
2395 
2396     TRACE("found -> %s\n", debugstr_w(lpBuffer));
2397     return lang;
2398 }
2399 
2400 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
2401                 int nBufferMax, LANGID lang )
2402 {
2403     LPWSTR bufW;
2404     LANGID r;
2405     INT len;
2406 
2407     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
2408     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
2409     if( r )
2410     {
2411         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
2412         if( len <= nBufferMax )
2413             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
2414                                  lpBuffer, nBufferMax, NULL, NULL );
2415         else
2416             r = 0;
2417     }
2418     msi_free(bufW);
2419     return r;
2420 }
2421 
2422 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
2423                 LPDWORD pcchBuf)
2424 {
2425     char szProduct[GUID_SIZE];
2426 
2427     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
2428 
2429     if (!szComponent || !pcchBuf)
2430         return INSTALLSTATE_INVALIDARG;
2431 
2432     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
2433         return INSTALLSTATE_UNKNOWN;
2434 
2435     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
2436 }
2437 
2438 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
2439                 LPDWORD pcchBuf)
2440 {
2441     WCHAR szProduct[GUID_SIZE];
2442 
2443     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
2444 
2445     if (!szComponent || !pcchBuf)
2446         return INSTALLSTATE_INVALIDARG;
2447 
2448     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
2449         return INSTALLSTATE_UNKNOWN;
2450 
2451     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
2452 }
2453 
2454 UINT WINAPI MsiMessageBoxA( HWND hWnd, const char *lpText, const char *lpCaption, UINT uType, WORD wLanguageId,
2455                             DWORD f )
2456 {
2457     FIXME( "%p, %s, %s, %u, %#x, %#lx\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption), uType, wLanguageId, f );
2458     return MessageBoxExA( hWnd, lpText, lpCaption, uType, wLanguageId );
2459 }
2460 
2461 UINT WINAPI MsiMessageBoxW( HWND hWnd, const WCHAR *lpText, const WCHAR *lpCaption, UINT uType, WORD wLanguageId,
2462                             DWORD f )
2463 {
2464     FIXME( "%p, %s, %s, %u, %#x %#lx\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption), uType, wLanguageId, f );
2465     return MessageBoxExW( hWnd, lpText, lpCaption, uType, wLanguageId );
2466 }
2467 
2468 UINT WINAPI MsiMessageBoxExA( HWND hWnd, const char *lpText, const char *lpCaption, UINT uType, DWORD unknown,
2469                               WORD wLanguageId, DWORD f )
2470 {
2471     FIXME( "%p, %s, %s, %u, %#lx, %#x, %#lx): semi-stub\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption), uType,
2472            unknown, wLanguageId, f );
2473     return MessageBoxExA( hWnd, lpText, lpCaption, uType, wLanguageId );
2474 }
2475 
2476 UINT WINAPI MsiMessageBoxExW( HWND hWnd, const WCHAR *lpText, const WCHAR *lpCaption, UINT uType, DWORD unknown,
2477                               WORD wLanguageId, DWORD f )
2478 {
2479     FIXME( "%p, %s, %s, %u, %#lx, %#x, %#lx): semi-stub\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption), uType,
2480            unknown, wLanguageId, f );
2481     return MessageBoxExW( hWnd, lpText, lpCaption, uType, wLanguageId );
2482 }
2483 
2484 UINT WINAPI MsiProvideAssemblyA( const char *szAssemblyName, const char *szAppContext, DWORD dwInstallMode,
2485                                  DWORD dwAssemblyInfo, char *lpPathBuf, DWORD *pcchPathBuf )
2486 {
2487     FIXME( "%s, %s, %#lx, %#lx, %p, %p\n", debugstr_a(szAssemblyName), debugstr_a(szAppContext), dwInstallMode,
2488            dwAssemblyInfo, lpPathBuf, pcchPathBuf );
2489     return ERROR_CALL_NOT_IMPLEMENTED;
2490 }
2491 
2492 UINT WINAPI MsiProvideAssemblyW( const WCHAR *szAssemblyName, const WCHAR *szAppContext, DWORD dwInstallMode,
2493                                  DWORD dwAssemblyInfo, WCHAR *lpPathBuf, DWORD *pcchPathBuf )
2494 {
2495     FIXME( "%s, %s, %#lx, %#lx, %p, %p\n", debugstr_w(szAssemblyName), debugstr_w(szAppContext), dwInstallMode,
2496            dwAssemblyInfo, lpPathBuf, pcchPathBuf );
2497     return ERROR_CALL_NOT_IMPLEMENTED;
2498 }
2499 
2500 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2501                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2502 {
2503     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2504     return ERROR_CALL_NOT_IMPLEMENTED;
2505 }
2506 
2507 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2508                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2509 {
2510     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2511     return ERROR_CALL_NOT_IMPLEMENTED;
2512 }
2513 
2514 HRESULT WINAPI MsiGetFileSignatureInformationA( const char *path, DWORD flags, PCCERT_CONTEXT *cert, BYTE *hash,
2515                                                 DWORD *hashlen )
2516 {
2517     UINT r;
2518     WCHAR *pathW = NULL;
2519 
2520     TRACE( "%s, %#lx, %p, %p, %p\n", debugstr_a(path), flags, cert, hash, hashlen );
2521 
2522     if (path && !(pathW = strdupAtoW( path ))) return E_OUTOFMEMORY;
2523     r = MsiGetFileSignatureInformationW( pathW, flags, cert, hash, hashlen );
2524     msi_free( pathW );
2525     return r;
2526 }
2527 
2528 HRESULT WINAPI MsiGetFileSignatureInformationW( const WCHAR *path, DWORD flags, PCCERT_CONTEXT *cert, BYTE *hash,
2529                                                 DWORD *hashlen )
2530 {
2531     static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
2532     HRESULT hr;
2533     WINTRUST_DATA data;
2534     WINTRUST_FILE_INFO info;
2535     CRYPT_PROVIDER_SGNR *signer;
2536     CRYPT_PROVIDER_CERT *provider;
2537 
2538     TRACE( "%s, %#lx, %p, %p, %p\n", debugstr_w(path), flags, cert, hash, hashlen );
2539 
2540     if (!path || !cert) return E_INVALIDARG;
2541 
2542     info.cbStruct       = sizeof(info);
2543     info.pcwszFilePath  = path;
2544     info.hFile          = NULL;
2545     info.pgKnownSubject = NULL;
2546 
2547     data.cbStruct            = sizeof(data);
2548     data.pPolicyCallbackData = NULL;
2549     data.pSIPClientData      = NULL;
2550     data.dwUIChoice          = WTD_UI_NONE;
2551     data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
2552     data.dwUnionChoice       = WTD_CHOICE_FILE;
2553     data.u.pFile             = &info;
2554     data.dwStateAction       = WTD_STATEACTION_VERIFY;
2555     data.hWVTStateData       = NULL;
2556     data.pwszURLReference    = NULL;
2557     data.dwProvFlags         = 0;
2558     data.dwUIContext         = WTD_UICONTEXT_INSTALL;
2559     hr = WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2560     *cert = NULL;
2561     if (FAILED(hr)) goto done;
2562 
2563     if (!(signer = WTHelperGetProvSignerFromChain( data.hWVTStateData, 0, FALSE, 0 )))
2564     {
2565         hr = TRUST_E_NOSIGNATURE;
2566         goto done;
2567     }
2568     if (hash)
2569     {
2570         DWORD len = signer->psSigner->EncryptedHash.cbData;
2571         if (*hashlen < len)
2572         {
2573             *hashlen = len;
2574             hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
2575             goto done;
2576         }
2577         memcpy( hash, signer->psSigner->EncryptedHash.pbData, len );
2578         *hashlen = len;
2579     }
2580     if (!(provider = WTHelperGetProvCertFromChain( signer, 0 )))
2581     {
2582         hr = TRUST_E_PROVIDER_UNKNOWN;
2583         goto done;
2584     }
2585     *cert = CertDuplicateCertificateContext( provider->pCert );
2586 
2587 done:
2588     data.dwStateAction = WTD_STATEACTION_CLOSE;
2589     WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2590     return hr;
2591 }
2592 
2593 /******************************************************************
2594  * MsiGetProductPropertyA      [MSI.@]
2595  */
2596 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, const char *szProperty, char *szValue, DWORD *pccbValue )
2597 {
2598     LPWSTR prop = NULL, val = NULL;
2599     DWORD len;
2600     UINT r;
2601 
2602     TRACE( "%lu, %s, %p, %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue );
2603 
2604     if (szValue && !pccbValue)
2605         return ERROR_INVALID_PARAMETER;
2606 
2607     if (szProperty) prop = strdupAtoW(szProperty);
2608 
2609     len = 0;
2610     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2611     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2612         goto done;
2613 
2614     if (r == ERROR_SUCCESS)
2615     {
2616         if (szValue) *szValue = '\0';
2617         if (pccbValue) *pccbValue = 0;
2618         goto done;
2619     }
2620 
2621     val = msi_alloc(++len * sizeof(WCHAR));
2622     if (!val)
2623     {
2624         r = ERROR_OUTOFMEMORY;
2625         goto done;
2626     }
2627 
2628     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2629     if (r != ERROR_SUCCESS)
2630         goto done;
2631 
2632     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2633 
2634     if (szValue)
2635         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2636                             *pccbValue, NULL, NULL);
2637 
2638     if (pccbValue)
2639     {
2640         if (len > *pccbValue)
2641             r = ERROR_MORE_DATA;
2642 
2643         *pccbValue = len - 1;
2644     }
2645 
2646 done:
2647     msi_free(prop);
2648     msi_free(val);
2649 
2650     return r;
2651 }
2652 
2653 /******************************************************************
2654  * MsiGetProductPropertyW      [MSI.@]
2655  */
2656 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, const WCHAR *szProperty, WCHAR *szValue, DWORD *pccbValue )
2657 {
2658     MSIPACKAGE *package;
2659     MSIQUERY *view = NULL;
2660     MSIRECORD *rec = NULL;
2661     LPCWSTR val;
2662     UINT r;
2663 
2664     TRACE( "%lu, %s, %p, %p)\n", hProduct, debugstr_w(szProperty), szValue, pccbValue );
2665 
2666     if (!szProperty)
2667         return ERROR_INVALID_PARAMETER;
2668 
2669     if (szValue && !pccbValue)
2670         return ERROR_INVALID_PARAMETER;
2671 
2672     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2673     if (!package)
2674         return ERROR_INVALID_HANDLE;
2675 
2676     r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `Property` WHERE `Property` = '%s'", szProperty);
2677     if (r != ERROR_SUCCESS)
2678         goto done;
2679 
2680     r = MSI_ViewExecute(view, 0);
2681     if (r != ERROR_SUCCESS)
2682         goto done;
2683 
2684     r = MSI_ViewFetch(view, &rec);
2685     if (r != ERROR_SUCCESS)
2686         goto done;
2687 
2688     val = MSI_RecordGetString(rec, 2);
2689     if (!val)
2690         goto done;
2691 
2692     if (lstrlenW(val) >= *pccbValue)
2693     {
2694         if (szValue) lstrcpynW(szValue, val, *pccbValue);
2695         r = ERROR_MORE_DATA;
2696     }
2697     else
2698     {
2699         if (szValue) lstrcpyW(szValue, val);
2700         r = ERROR_SUCCESS;
2701     }
2702 
2703     *pccbValue = lstrlenW(val);
2704 
2705 done:
2706     if (view)
2707     {
2708         MSI_ViewClose(view);
2709         msiobj_release(&view->hdr);
2710         if (rec) msiobj_release(&rec->hdr);
2711     }
2712 
2713     if (!rec)
2714     {
2715         if (szValue) *szValue = '\0';
2716         if (pccbValue) *pccbValue = 0;
2717         r = ERROR_SUCCESS;
2718     }
2719 
2720     msiobj_release(&package->hdr);
2721     return r;
2722 }
2723 
2724 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2725 {
2726     UINT r;
2727     LPWSTR szPack = NULL;
2728 
2729     TRACE("%s\n", debugstr_a(szPackage) );
2730 
2731     if( szPackage )
2732     {
2733         szPack = strdupAtoW( szPackage );
2734         if( !szPack )
2735             return ERROR_OUTOFMEMORY;
2736     }
2737 
2738     r = MsiVerifyPackageW( szPack );
2739 
2740     msi_free( szPack );
2741 
2742     return r;
2743 }
2744 
2745 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2746 {
2747     MSIHANDLE handle;
2748     UINT r;
2749 
2750     TRACE("%s\n", debugstr_w(szPackage) );
2751 
2752     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2753     MsiCloseHandle( handle );
2754 
2755     return r;
2756 }
2757 
2758 static BOOL open_userdata_comp_key( const WCHAR *comp, const WCHAR *usersid, MSIINSTALLCONTEXT ctx,
2759                                     HKEY *hkey )
2760 {
2761     if (ctx & MSIINSTALLCONTEXT_MACHINE)
2762     {
2763         if (!MSIREG_OpenUserDataComponentKey( comp, L"S-1-5-18", hkey, FALSE )) return TRUE;
2764     }
2765     if (ctx & (MSIINSTALLCONTEXT_USERMANAGED|MSIINSTALLCONTEXT_USERUNMANAGED))
2766     {
2767         if (usersid && !wcsicmp( usersid, L"S-1-1-0" ))
2768         {
2769             FIXME( "only looking at the current user\n" );
2770             usersid = NULL;
2771         }
2772         if (!MSIREG_OpenUserDataComponentKey( comp, usersid, hkey, FALSE )) return TRUE;
2773     }
2774     return FALSE;
2775 }
2776 
2777 static INSTALLSTATE MSI_GetComponentPath( const WCHAR *szProduct, const WCHAR *szComponent,
2778                                           const WCHAR *szUserSid, MSIINSTALLCONTEXT ctx,
2779                                           awstring *lpPathBuf, DWORD *pcchBuf )
2780 {
2781     WCHAR *path = NULL, squashed_pc[SQUASHED_GUID_SIZE], squashed_comp[SQUASHED_GUID_SIZE];
2782     HKEY hkey;
2783     INSTALLSTATE state;
2784     DWORD version;
2785 
2786     if (!szProduct || !szComponent)
2787         return INSTALLSTATE_INVALIDARG;
2788 
2789     if (lpPathBuf->str.w && !pcchBuf)
2790         return INSTALLSTATE_INVALIDARG;
2791 
2792     if (!squash_guid( szProduct, squashed_pc ) || !squash_guid( szComponent, squashed_comp ))
2793         return INSTALLSTATE_INVALIDARG;
2794 
2795     if (szUserSid && ctx == MSIINSTALLCONTEXT_MACHINE)
2796         return INSTALLSTATE_INVALIDARG;
2797 
2798     state = INSTALLSTATE_UNKNOWN;
2799 
2800     if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2801     {
2802         path = msi_reg_get_val_str( hkey, squashed_pc );
2803         RegCloseKey(hkey);
2804 
2805         state = INSTALLSTATE_ABSENT;
2806 
2807         if ((!MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL, &hkey, FALSE) ||
2808              !MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED, NULL, &hkey, FALSE)) &&
2809             msi_reg_get_val_dword(hkey, L"WindowsInstaller", &version) &&
2810             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2811         {
2812             RegCloseKey(hkey);
2813             state = INSTALLSTATE_LOCAL;
2814         }
2815     }
2816 
2817     if (state != INSTALLSTATE_LOCAL &&
2818         (!MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hkey, FALSE) ||
2819          !MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE, &hkey, FALSE)))
2820     {
2821         RegCloseKey(hkey);
2822 
2823         if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2824         {
2825             msi_free(path);
2826             path = msi_reg_get_val_str( hkey, squashed_pc );
2827             RegCloseKey(hkey);
2828 
2829             state = INSTALLSTATE_ABSENT;
2830 
2831             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2832                 state = INSTALLSTATE_LOCAL;
2833         }
2834     }
2835 
2836     if (!path)
2837         return INSTALLSTATE_UNKNOWN;
2838 
2839     if (state == INSTALLSTATE_LOCAL && !*path)
2840         state = INSTALLSTATE_NOTUSED;
2841 
2842     if (msi_strcpy_to_awstring(path, -1, lpPathBuf, pcchBuf) == ERROR_MORE_DATA)
2843         state = INSTALLSTATE_MOREDATA;
2844 
2845     msi_free(path);
2846     return state;
2847 }
2848 
2849 /******************************************************************
2850  * MsiGetComponentPathExW      [MSI.@]
2851  */
2852 INSTALLSTATE WINAPI MsiGetComponentPathExW( LPCWSTR product, LPCWSTR comp, LPCWSTR usersid,
2853                                             MSIINSTALLCONTEXT ctx, LPWSTR buf, LPDWORD buflen )
2854 {
2855     awstring path;
2856 
2857     TRACE( "%s %s %s 0x%x %p %p\n", debugstr_w(product), debugstr_w(comp), debugstr_w(usersid),
2858            ctx, buf, buflen );
2859 
2860     path.unicode = TRUE;
2861     path.str.w   = buf;
2862 
2863     return MSI_GetComponentPath( product, comp, usersid, ctx, &path, buflen );
2864 }
2865 
2866 INSTALLSTATE WINAPI MsiGetComponentPathExA( LPCSTR product, LPCSTR comp, LPCSTR usersid,
2867                                             MSIINSTALLCONTEXT ctx, LPSTR buf, LPDWORD buflen )
2868 {
2869     WCHAR *productW = NULL, *compW = NULL, *usersidW =  NULL;
2870     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2871     awstring path;
2872 
2873     TRACE( "%s %s %s 0x%x %p %p\n", debugstr_a(product), debugstr_a(comp), debugstr_a(usersid),
2874            ctx, buf, buflen );
2875 
2876     if (product && !(productW = strdupAtoW( product ))) return INSTALLSTATE_UNKNOWN;
2877     if (comp && !(compW = strdupAtoW( comp ))) goto end;
2878     if (usersid && !(usersidW = strdupAtoW( usersid ))) goto end;
2879 
2880     path.unicode = FALSE;
2881     path.str.a   = buf;
2882 
2883     r = MSI_GetComponentPath( productW, compW, usersidW, ctx, &path, buflen );
2884 
2885 end:
2886     msi_free( productW );
2887     msi_free( compW );
2888     msi_free( usersidW );
2889 
2890     return r;
2891 }
2892 
2893 /******************************************************************
2894  * MsiGetComponentPathW      [MSI.@]
2895  */
2896 INSTALLSTATE WINAPI MsiGetComponentPathW( LPCWSTR product, LPCWSTR comp, LPWSTR buf, LPDWORD buflen )
2897 {
2898     return MsiGetComponentPathExW( product, comp, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, buf, buflen );
2899 }
2900 
2901 /******************************************************************
2902  * MsiGetComponentPathA      [MSI.@]
2903  */
2904 INSTALLSTATE WINAPI MsiGetComponentPathA( LPCSTR product, LPCSTR comp, LPSTR buf, LPDWORD buflen )
2905 {
2906     return MsiGetComponentPathExA( product, comp, "s-1-1-0", MSIINSTALLCONTEXT_ALL, buf, buflen );
2907 }
2908 
2909 static UINT query_feature_state( const WCHAR *product, const WCHAR *squashed, const WCHAR *usersid,
2910                                  MSIINSTALLCONTEXT ctx, const WCHAR *feature, INSTALLSTATE *state )
2911 {
2912     UINT r;
2913     HKEY hkey;
2914     WCHAR *parent, *components, *path;
2915     const WCHAR *p;
2916     BOOL missing = FALSE, source = FALSE;
2917     WCHAR comp[GUID_SIZE];
2918     GUID guid;
2919 
2920     if (ctx != MSIINSTALLCONTEXT_MACHINE) SetLastError( ERROR_SUCCESS );
2921 
2922     if (MSIREG_OpenFeaturesKey( product, usersid, ctx, &hkey, FALSE )) return ERROR_UNKNOWN_PRODUCT;
2923 
2924     parent = msi_reg_get_val_str( hkey, feature );
2925     RegCloseKey( hkey );
2926     if (!parent) return ERROR_UNKNOWN_FEATURE;
2927 
2928     *state = (parent[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2929     msi_free( parent );
2930     if (*state == INSTALLSTATE_ABSENT)
2931         return ERROR_SUCCESS;
2932 
2933     r = MSIREG_OpenUserDataFeaturesKey( product, usersid, ctx, &hkey, FALSE );
2934     if (r != ERROR_SUCCESS)
2935     {
2936         *state = INSTALLSTATE_ADVERTISED;
2937         return ERROR_SUCCESS;
2938     }
2939     components = msi_reg_get_val_str( hkey, feature );
2940     RegCloseKey( hkey );
2941 
2942     TRACE("buffer = %s\n", debugstr_w(components));
2943 
2944     if (!components)
2945     {
2946         *state = INSTALLSTATE_ADVERTISED;
2947         return ERROR_SUCCESS;
2948     }
2949     for (p = components; *p && *p != 2 ; p += 20)
2950     {
2951         if (!decode_base85_guid( p, &guid ))
2952         {
2953             if (p != components) break;
2954             msi_free( components );
2955             *state = INSTALLSTATE_BADCONFIG;
2956             return ERROR_BAD_CONFIGURATION;
2957         }
2958         StringFromGUID2( &guid, comp, GUID_SIZE );
2959         if (ctx == MSIINSTALLCONTEXT_MACHINE)
2960             r = MSIREG_OpenUserDataComponentKey( comp, L"S-1-5-18", &hkey, FALSE );
2961         else
2962             r = MSIREG_OpenUserDataComponentKey( comp, usersid, &hkey, FALSE );
2963 
2964         if (r != ERROR_SUCCESS)
2965         {
2966             msi_free( components );
2967             *state = INSTALLSTATE_ADVERTISED;
2968             return ERROR_SUCCESS;
2969         }
2970         path = msi_reg_get_val_str( hkey, squashed );
2971         if (!path) missing = TRUE;
2972         else if (lstrlenW( path ) > 2 &&
2973                  path[0] >= '0' && path[0] <= '9' &&
2974                  path[1] >= '0' && path[1] <= '9')
2975         {
2976             source = TRUE;
2977         }
2978         msi_free( path );
2979     }
2980     msi_free( components );
2981 
2982     if (missing)
2983         *state = INSTALLSTATE_ADVERTISED;
2984     else if (source)
2985         *state = INSTALLSTATE_SOURCE;
2986     else
2987         *state = INSTALLSTATE_LOCAL;
2988 
2989     TRACE("returning state %d\n", *state);
2990     return ERROR_SUCCESS;
2991 }
2992 
2993 UINT WINAPI MsiQueryFeatureStateExA( LPCSTR product, LPCSTR usersid, MSIINSTALLCONTEXT ctx,
2994                                      LPCSTR feature, INSTALLSTATE *state )
2995 {
2996     UINT r;
2997     WCHAR *productW = NULL, *usersidW = NULL, *featureW = NULL;
2998 
2999     if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
3000     if (usersid && !(usersidW = strdupAtoW( usersid )))
3001     {
3002         msi_free( productW );
3003         return ERROR_OUTOFMEMORY;
3004     }
3005     if (feature && !(featureW = strdupAtoW( feature )))
3006     {
3007         msi_free( productW );
3008         msi_free( usersidW );
3009         return ERROR_OUTOFMEMORY;
3010     }
3011     r = MsiQueryFeatureStateExW( productW, usersidW, ctx, featureW, state );
3012     msi_free( productW );
3013     msi_free( usersidW );
3014     msi_free( featureW );
3015     return r;
3016 }
3017 
3018 UINT WINAPI MsiQueryFeatureStateExW( LPCWSTR product, LPCWSTR usersid, MSIINSTALLCONTEXT ctx,
3019                                      LPCWSTR feature, INSTALLSTATE *state )
3020 {
3021     WCHAR squashed[33];
3022     if (!squash_guid( product, squashed )) return ERROR_INVALID_PARAMETER;
3023     return query_feature_state( product, squashed, usersid, ctx, feature, state );
3024 }
3025 
3026 /******************************************************************
3027  * MsiQueryFeatureStateA      [MSI.@]
3028  */
3029 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
3030 {
3031     LPWSTR szwProduct = NULL, szwFeature= NULL;
3032     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
3033 
3034     szwProduct = strdupAtoW( szProduct );
3035     if ( szProduct && !szwProduct )
3036         goto end;
3037 
3038     szwFeature = strdupAtoW( szFeature );
3039     if ( szFeature && !szwFeature )
3040         goto end;
3041 
3042     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
3043 
3044 end:
3045     msi_free( szwProduct);
3046     msi_free( szwFeature);
3047 
3048     return rc;
3049 }
3050 
3051 /******************************************************************
3052  * MsiQueryFeatureStateW      [MSI.@]
3053  *
3054  * Checks the state of a feature
3055  *
3056  * PARAMS
3057  *   szProduct     [I]  Product's GUID string
3058  *   szFeature     [I]  Feature's GUID string
3059  *
3060  * RETURNS
3061  *   INSTALLSTATE_LOCAL        Feature is installed and usable
3062  *   INSTALLSTATE_ABSENT       Feature is absent
3063  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
3064  *   INSTALLSTATE_UNKNOWN      An error occurred
3065  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
3066  *
3067  */
3068 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
3069 {
3070     UINT r;
3071     INSTALLSTATE state;
3072     WCHAR squashed[33];
3073 
3074     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
3075 
3076     if (!szProduct || !szFeature || !squash_guid( szProduct, squashed ))
3077         return INSTALLSTATE_INVALIDARG;
3078 
3079     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERMANAGED, szFeature, &state );
3080     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3081 
3082     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, szFeature, &state );
3083     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3084 
3085     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_MACHINE, szFeature, &state );
3086     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3087 
3088     return INSTALLSTATE_UNKNOWN;
3089 }
3090 
3091 /******************************************************************
3092  * MsiGetFileVersionA         [MSI.@]
3093  */
3094 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
3095                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
3096 {
3097     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
3098     UINT ret = ERROR_OUTOFMEMORY;
3099 
3100     if ((lpVersionBuf && !pcchVersionBuf) ||
3101         (lpLangBuf && !pcchLangBuf))
3102         return ERROR_INVALID_PARAMETER;
3103 
3104     if( szFilePath )
3105     {
3106         szwFilePath = strdupAtoW( szFilePath );
3107         if( !szwFilePath )
3108             goto end;
3109     }
3110 
3111     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
3112     {
3113         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
3114         if( !lpwVersionBuff )
3115             goto end;
3116     }
3117 
3118     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
3119     {
3120         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
3121         if( !lpwLangBuff )
3122             goto end;
3123     }
3124 
3125     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
3126                              lpwLangBuff, pcchLangBuf);
3127 
3128     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
3129         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
3130                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
3131     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
3132         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
3133                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
3134 
3135 end:
3136     msi_free(szwFilePath);
3137     msi_free(lpwVersionBuff);
3138     msi_free(lpwLangBuff);
3139 
3140     return ret;
3141 }
3142 
3143 static UINT get_file_version( const WCHAR *path, WCHAR *verbuf, DWORD *verlen,
3144                               WCHAR *langbuf, DWORD *langlen )
3145 {
3146     UINT ret = ERROR_MORE_DATA;
3147     UINT len;
3148     DWORD error;
3149     LPVOID version;
3150     VS_FIXEDFILEINFO *ffi;
3151     USHORT *lang;
3152     WCHAR tmp[32];
3153 
3154     if (!(len = GetFileVersionInfoSizeW( path, NULL )))
3155     {
3156         error = GetLastError();
3157         if (error == ERROR_BAD_PATHNAME) return ERROR_FILE_NOT_FOUND;
3158         if (error == ERROR_RESOURCE_DATA_NOT_FOUND) return ERROR_FILE_INVALID;
3159         return error;
3160     }
3161     if (!(version = msi_alloc( len ))) return ERROR_OUTOFMEMORY;
3162     if (!GetFileVersionInfoW( path, 0, len, version ))
3163     {
3164         msi_free( version );
3165         return GetLastError();
3166     }
3167     if (!verbuf && !verlen && !langbuf && !langlen)
3168     {
3169         msi_free( version );
3170         return ERROR_SUCCESS;
3171     }
3172     if (verlen)
3173     {
3174         if (VerQueryValueW( version, L"\\", (LPVOID *)&ffi, &len ) && len > 0)
3175         {
3176             swprintf( tmp, ARRAY_SIZE(tmp), L"%d.%d.%d.%d",
3177                       HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
3178                       HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS) );
3179             if (verbuf) lstrcpynW( verbuf, tmp, *verlen );
3180             len = lstrlenW( tmp );
3181             if (*verlen > len) ret = ERROR_SUCCESS;
3182             *verlen = len;
3183         }
3184         else
3185         {
3186             if (verbuf) *verbuf = 0;
3187             *verlen = 0;
3188         }
3189     }
3190     if (langlen)
3191     {
3192         if (VerQueryValueW( version, L"\\VarFileInfo\\Translation", (LPVOID *)&lang, &len ) && len > 0)
3193         {
3194             swprintf( tmp, ARRAY_SIZE(tmp), L"%d", *lang );
3195             if (langbuf) lstrcpynW( langbuf, tmp, *langlen );
3196             len = lstrlenW( tmp );
3197             if (*langlen > len) ret = ERROR_SUCCESS;
3198             *langlen = len;
3199         }
3200         else
3201         {
3202             if (langbuf) *langbuf = 0;
3203             *langlen = 0;
3204         }
3205     }
3206     msi_free( version );
3207     return ret;
3208 }
3209 
3210 
3211 /******************************************************************
3212  * MsiGetFileVersionW         [MSI.@]
3213  */
3214 UINT WINAPI MsiGetFileVersionW( const WCHAR *path, WCHAR *verbuf, DWORD *verlen, WCHAR *langbuf, DWORD *langlen )
3215 {
3216     UINT ret;
3217 
3218     TRACE( "%s, %p(%lu), %p(%lu)\n", debugstr_w(path), verbuf, verlen ? *verlen : 0, langbuf, langlen ? *langlen : 0 );
3219 
3220     if ((verbuf && !verlen) || (langbuf && !langlen))
3221         return ERROR_INVALID_PARAMETER;
3222 
3223     ret = get_file_version( path, verbuf, verlen, langbuf, langlen );
3224     if (ret == ERROR_RESOURCE_DATA_NOT_FOUND && verlen)
3225     {
3226         int len;
3227         WCHAR *version = msi_get_font_file_version( NULL, path );
3228         if (!version) return ERROR_FILE_INVALID;
3229         len = lstrlenW( version );
3230         if (len >= *verlen) ret = ERROR_MORE_DATA;
3231         else if (verbuf)
3232         {
3233             lstrcpyW( verbuf, version );
3234             ret = ERROR_SUCCESS;
3235         }
3236         *verlen = len;
3237         msi_free( version );
3238     }
3239     return ret;
3240 }
3241 
3242 /***********************************************************************
3243  * MsiGetFeatureUsageW           [MSI.@]
3244  */
3245 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
3246                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
3247 {
3248     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
3249           pdwUseCount, pwDateUsed);
3250     return ERROR_CALL_NOT_IMPLEMENTED;
3251 }
3252 
3253 /***********************************************************************
3254  * MsiGetFeatureUsageA           [MSI.@]
3255  */
3256 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
3257                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
3258 {
3259     LPWSTR prod = NULL, feat = NULL;
3260     UINT ret = ERROR_OUTOFMEMORY;
3261 
3262     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
3263           pdwUseCount, pwDateUsed);
3264 
3265     prod = strdupAtoW( szProduct );
3266     if (szProduct && !prod)
3267         goto end;
3268 
3269     feat = strdupAtoW( szFeature );
3270     if (szFeature && !feat)
3271         goto end;
3272 
3273     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
3274 
3275 end:
3276     msi_free( prod );
3277     msi_free( feat );
3278 
3279     return ret;
3280 }
3281 
3282 /***********************************************************************
3283  * MsiUseFeatureExW           [MSI.@]
3284  */
3285 INSTALLSTATE WINAPI MsiUseFeatureExW( const WCHAR *szProduct, const WCHAR *szFeature, DWORD dwInstallMode,
3286                                       DWORD dwReserved )
3287 {
3288     INSTALLSTATE state;
3289 
3290     TRACE( "%s, %s, %lu %#lx\n", debugstr_w(szProduct), debugstr_w(szFeature), dwInstallMode, dwReserved );
3291 
3292     state = MsiQueryFeatureStateW( szProduct, szFeature );
3293 
3294     if (dwReserved)
3295         return INSTALLSTATE_INVALIDARG;
3296 
3297     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
3298     {
3299         FIXME("mark product %s feature %s as used\n",
3300               debugstr_w(szProduct), debugstr_w(szFeature) );
3301     }
3302 
3303     return state;
3304 }
3305 
3306 /***********************************************************************
3307  * MsiUseFeatureExA           [MSI.@]
3308  */
3309 INSTALLSTATE WINAPI MsiUseFeatureExA( const char *szProduct, const char *szFeature, DWORD dwInstallMode,
3310                                       DWORD dwReserved )
3311 {
3312     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
3313     WCHAR *prod = NULL, *feat = NULL;
3314 
3315     TRACE( "%s, %s, %lu, %#lx\n", debugstr_a(szProduct), debugstr_a(szFeature), dwInstallMode, dwReserved );
3316 
3317     prod = strdupAtoW( szProduct );
3318     if (szProduct && !prod)
3319         goto end;
3320 
3321     feat = strdupAtoW( szFeature );
3322     if (szFeature && !feat)
3323         goto end;
3324 
3325     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
3326 
3327 end:
3328     msi_free( prod );
3329     msi_free( feat );
3330 
3331     return ret;
3332 }
3333 
3334 /***********************************************************************
3335  * MsiUseFeatureW             [MSI.@]
3336  */
3337 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
3338 {
3339     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
3340 }
3341 
3342 /***********************************************************************
3343  * MsiUseFeatureA             [MSI.@]
3344  */
3345 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
3346 {
3347     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
3348 }
3349 
3350 static WCHAR *reg_get_multisz( HKEY hkey, const WCHAR *name )
3351 {
3352     WCHAR *ret;
3353     DWORD len, type;
3354     if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_MULTI_SZ) return NULL;
3355     if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3356     return ret;
3357 }
3358 
3359 static WCHAR *reg_get_sz( HKEY hkey, const WCHAR *name )
3360 {
3361     WCHAR *ret;
3362     DWORD len, type;
3363     if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_SZ) return NULL;
3364     if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3365     return ret;
3366 }
3367 
3368 #define BASE85_SIZE 20
3369 
3370 /***********************************************************************
3371  * MSI_ProvideQualifiedComponentEx [internal]
3372  */
3373 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
3374                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
3375                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
3376                 LPDWORD pcchPathBuf)
3377 {
3378     WCHAR product[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
3379     WCHAR *desc;
3380     HKEY hkey;
3381     DWORD size;
3382     UINT ret;
3383     INSTALLSTATE state;
3384 
3385     if (MSIREG_OpenUserComponentsKey( szComponent, &hkey, FALSE )) return ERROR_UNKNOWN_COMPONENT;
3386 
3387     desc = reg_get_multisz( hkey, szQualifier );
3388     RegCloseKey(hkey);
3389     if (!desc) return ERROR_INDEX_ABSENT;
3390 
3391     /* FIXME: handle multiple descriptors */
3392     ret = MsiDecomposeDescriptorW( desc, product, feature, comp, &size );
3393     msi_free( desc );
3394     if (ret != ERROR_SUCCESS) return ret;
3395 
3396     if (!szProduct) szProduct = product;
3397     if (!comp[0])
3398     {
3399         MSIINSTALLCONTEXT ctx;
3400         WCHAR *components;
3401         GUID guid;
3402 
3403         /* use the first component of the feature if the descriptor component is empty */
3404         if ((ret = msi_locate_product( szProduct, &ctx ))) return ret;
3405         if ((ret = MSIREG_OpenUserDataFeaturesKey( szProduct, NULL, ctx, &hkey, FALSE )))
3406         {
3407             return ERROR_FILE_NOT_FOUND;
3408         }
3409         components = reg_get_sz( hkey, feature );
3410         RegCloseKey( hkey );
3411         if (!components) return ERROR_FILE_NOT_FOUND;
3412 
3413         if (lstrlenW( components ) < BASE85_SIZE || !decode_base85_guid( components, &guid ))
3414         {
3415             msi_free( components );
3416             return ERROR_FILE_NOT_FOUND;
3417         }
3418         msi_free( components );
3419         StringFromGUID2( &guid, comp, ARRAY_SIZE( comp ));
3420     }
3421 
3422     state = MSI_GetComponentPath( szProduct, comp, L"S-1-1-0", MSIINSTALLCONTEXT_ALL, lpPathBuf, pcchPathBuf );
3423 
3424     if (state == INSTALLSTATE_MOREDATA) return ERROR_MORE_DATA;
3425     if (state != INSTALLSTATE_LOCAL) return ERROR_FILE_NOT_FOUND;
3426     return ERROR_SUCCESS;
3427 }
3428 
3429 /***********************************************************************
3430  * MsiProvideQualifiedComponentExW [MSI.@]
3431  */
3432 UINT WINAPI MsiProvideQualifiedComponentExW( const WCHAR *szComponent, const WCHAR *szQualifier, DWORD dwInstallMode,
3433                                              const WCHAR *szProduct, DWORD Unused1, DWORD Unused2, WCHAR *lpPathBuf,
3434                                              DWORD *pcchPathBuf )
3435 {
3436     awstring path;
3437 
3438     TRACE( "%s, %s, %lu, %s, %#lx, %#lx, %p, %p\n", debugstr_w(szComponent), debugstr_w(szQualifier), dwInstallMode,
3439            debugstr_w(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf );
3440 
3441     path.unicode = TRUE;
3442     path.str.w = lpPathBuf;
3443 
3444     return MSI_ProvideQualifiedComponentEx( szComponent, szQualifier, dwInstallMode, szProduct, Unused1, Unused2,
3445                                             &path, pcchPathBuf );
3446 }
3447 
3448 /***********************************************************************
3449  * MsiProvideQualifiedComponentExA [MSI.@]
3450  */
3451 UINT WINAPI MsiProvideQualifiedComponentExA( const char *szComponent, const char *szQualifier, DWORD dwInstallMode,
3452                                              const char *szProduct, DWORD Unused1, DWORD Unused2, char *lpPathBuf,
3453                                              DWORD *pcchPathBuf )
3454 {
3455     WCHAR *szwComponent, *szwQualifier = NULL, *szwProduct = NULL;
3456     UINT r = ERROR_OUTOFMEMORY;
3457     awstring path;
3458 
3459     TRACE( "%s, %s, %lu, %s, %#lx, %#lx, %p, %p\n", debugstr_a(szComponent), debugstr_a(szQualifier), dwInstallMode,
3460            debugstr_a(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf );
3461 
3462     szwComponent = strdupAtoW( szComponent );
3463     if (szComponent && !szwComponent)
3464         goto end;
3465 
3466     szwQualifier = strdupAtoW( szQualifier );
3467     if (szQualifier && !szwQualifier)
3468         goto end;
3469 
3470     szwProduct = strdupAtoW( szProduct );
3471     if (szProduct && !szwProduct)
3472         goto end;
3473 
3474     path.unicode = FALSE;
3475     path.str.a = lpPathBuf;
3476 
3477     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
3478                               dwInstallMode, szwProduct, Unused1,
3479                               Unused2, &path, pcchPathBuf);
3480 end:
3481     msi_free(szwProduct);
3482     msi_free(szwComponent);
3483     msi_free(szwQualifier);
3484 
3485     return r;
3486 }
3487 
3488 /***********************************************************************
3489  * MsiProvideQualifiedComponentW [MSI.@]
3490  */
3491 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
3492                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
3493                 LPDWORD pcchPathBuf)
3494 {
3495     return MsiProvideQualifiedComponentExW(szComponent, szQualifier,
3496                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3497 }
3498 
3499 /***********************************************************************
3500  * MsiProvideQualifiedComponentA [MSI.@]
3501  */
3502 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
3503                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
3504                 LPDWORD pcchPathBuf)
3505 {
3506     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
3507                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3508 }
3509 
3510 /***********************************************************************
3511  * MSI_GetUserInfo [internal]
3512  */
3513 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
3514                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
3515                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3516                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
3517 {
3518     WCHAR *user, *org, *serial, squashed_pc[SQUASHED_GUID_SIZE];
3519     USERINFOSTATE state;
3520     HKEY hkey, props;
3521     LPCWSTR orgptr;
3522     UINT r;
3523 
3524     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
3525           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
3526           pcchSerialBuf);
3527 
3528     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
3529         return USERINFOSTATE_INVALIDARG;
3530 
3531     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
3532                               &hkey, FALSE) != ERROR_SUCCESS &&
3533         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3534                               &hkey, FALSE) != ERROR_SUCCESS &&
3535         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
3536                               &hkey, FALSE) != ERROR_SUCCESS)
3537     {
3538         return USERINFOSTATE_UNKNOWN;
3539     }
3540 
3541     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
3542                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
3543         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
3544                                 NULL, &props, FALSE) != ERROR_SUCCESS)
3545     {
3546         RegCloseKey(hkey);
3547         return USERINFOSTATE_ABSENT;
3548     }
3549 
3550     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
3551     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
3552     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
3553     state = USERINFOSTATE_ABSENT;
3554 
3555     RegCloseKey(hkey);
3556     RegCloseKey(props);
3557 
3558     if (user && serial)
3559         state = USERINFOSTATE_PRESENT;
3560 
3561     if (pcchUserNameBuf)
3562     {
3563         if (lpUserNameBuf && !user)
3564         {
3565             (*pcchUserNameBuf)--;
3566             goto done;
3567         }
3568 
3569         r = msi_strcpy_to_awstring(user, -1, lpUserNameBuf, pcchUserNameBuf);
3570         if (r == ERROR_MORE_DATA)
3571         {
3572             state = USERINFOSTATE_MOREDATA;
3573             goto done;
3574         }
3575     }
3576 
3577     if (pcchOrgNameBuf)
3578     {
3579         orgptr = org;
3580         if (!orgptr) orgptr = L"";
3581 
3582         r = msi_strcpy_to_awstring(orgptr, -1, lpOrgNameBuf, pcchOrgNameBuf);
3583         if (r == ERROR_MORE_DATA)
3584         {
3585             state = USERINFOSTATE_MOREDATA;
3586             goto done;
3587         }
3588     }
3589 
3590     if (pcchSerialBuf)
3591     {
3592         if (!serial)
3593         {
3594             (*pcchSerialBuf)--;
3595             goto done;
3596         }
3597 
3598         r = msi_strcpy_to_awstring(serial, -1, lpSerialBuf, pcchSerialBuf);
3599         if (r == ERROR_MORE_DATA)
3600             state = USERINFOSTATE_MOREDATA;
3601     }
3602 
3603 done:
3604     msi_free(user);
3605     msi_free(org);
3606     msi_free(serial);
3607 
3608     return state;
3609 }
3610 
3611 /***********************************************************************
3612  * MsiGetUserInfoW [MSI.@]
3613  */
3614 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3615                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3616                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3617                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3618 {
3619     awstring user, org, serial;
3620 
3621     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3622         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3623         (lpSerialBuf && !pcchSerialBuf))
3624         return USERINFOSTATE_INVALIDARG;
3625 
3626     user.unicode = TRUE;
3627     user.str.w = lpUserNameBuf;
3628     org.unicode = TRUE;
3629     org.str.w = lpOrgNameBuf;
3630     serial.unicode = TRUE;
3631     serial.str.w = lpSerialBuf;
3632 
3633     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3634                             &org, pcchOrgNameBuf,
3635                             &serial, pcchSerialBuf );
3636 }
3637 
3638 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3639                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3640                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3641                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3642 {
3643     awstring user, org, serial;
3644     LPWSTR prod;
3645     UINT r;
3646 
3647     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3648         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3649         (lpSerialBuf && !pcchSerialBuf))
3650         return USERINFOSTATE_INVALIDARG;
3651 
3652     prod = strdupAtoW( szProduct );
3653     if (szProduct && !prod)
3654         return ERROR_OUTOFMEMORY;
3655 
3656     user.unicode = FALSE;
3657     user.str.a = lpUserNameBuf;
3658     org.unicode = FALSE;
3659     org.str.a = lpOrgNameBuf;
3660     serial.unicode = FALSE;
3661     serial.str.a = lpSerialBuf;
3662 
3663     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3664                          &org, pcchOrgNameBuf,
3665                          &serial, pcchSerialBuf );
3666 
3667     msi_free( prod );
3668 
3669     return r;
3670 }
3671 
3672 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3673 {
3674     MSIHANDLE handle;
3675     UINT rc;
3676     MSIPACKAGE *package;
3677 
3678     TRACE("(%s)\n",debugstr_w(szProduct));
3679 
3680     rc = MsiOpenProductW(szProduct,&handle);
3681     if (rc != ERROR_SUCCESS)
3682         return ERROR_INVALID_PARAMETER;
3683 
3684     /* MsiCollectUserInfo cannot be called from a custom action. */
3685     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3686     if (!package)
3687         return ERROR_CALL_NOT_IMPLEMENTED;
3688 
3689     rc = ACTION_PerformAction(package, L"FirstRun");
3690     msiobj_release( &package->hdr );
3691 
3692     MsiCloseHandle(handle);
3693 
3694     return rc;
3695 }
3696 
3697 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3698 {
3699     MSIHANDLE handle;
3700     UINT rc;
3701     MSIPACKAGE *package;
3702 
3703     TRACE("(%s)\n",debugstr_a(szProduct));
3704 
3705     rc = MsiOpenProductA(szProduct,&handle);
3706     if (rc != ERROR_SUCCESS)
3707         return ERROR_INVALID_PARAMETER;
3708 
3709     /* MsiCollectUserInfo cannot be called from a custom action. */
3710     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3711     if (!package)
3712         return ERROR_CALL_NOT_IMPLEMENTED;
3713 
3714     rc = ACTION_PerformAction(package, L"FirstRun");
3715     msiobj_release( &package->hdr );
3716 
3717     MsiCloseHandle(handle);
3718 
3719     return rc;
3720 }
3721 
3722 /***********************************************************************
3723  * MsiConfigureFeatureA            [MSI.@]
3724  */
3725 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3726 {
3727     LPWSTR prod, feat = NULL;
3728     UINT r = ERROR_OUTOFMEMORY;
3729 
3730     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3731 
3732     prod = strdupAtoW( szProduct );
3733     if (szProduct && !prod)
3734         goto end;
3735 
3736     feat = strdupAtoW( szFeature );
3737     if (szFeature && !feat)
3738         goto end;
3739 
3740     r = MsiConfigureFeatureW(prod, feat, eInstallState);
3741 
3742 end:
3743     msi_free(feat);
3744     msi_free(prod);
3745 
3746     return r;
3747 }
3748 
3749 /***********************************************************************
3750  * MsiConfigureFeatureW            [MSI.@]
3751  */
3752 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
3753 {
3754     MSIPACKAGE *package = NULL;
3755     UINT r;
3756     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
3757     DWORD sz;
3758 
3759     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
3760 
3761     if (!szProduct || !szFeature)
3762         return ERROR_INVALID_PARAMETER;
3763 
3764     switch (eInstallState)
3765     {
3766     case INSTALLSTATE_DEFAULT:
3767         /* FIXME: how do we figure out the default location? */
3768         eInstallState = INSTALLSTATE_LOCAL;
3769         break;
3770     case INSTALLSTATE_LOCAL:
3771     case INSTALLSTATE_SOURCE:
3772     case INSTALLSTATE_ABSENT:
3773     case INSTALLSTATE_ADVERTISED:
3774         break;
3775     default:
3776         return ERROR_INVALID_PARAMETER;
3777     }
3778 
3779     r = MSI_OpenProductW( szProduct, &package );
3780     if (r != ERROR_SUCCESS)
3781         return r;
3782 
3783     sz = sizeof(sourcepath);
3784     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3785                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3786 
3787     sz = sizeof(filename);
3788     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3789                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3790 
3791     lstrcatW( sourcepath, filename );
3792 
3793     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
3794 
3795     r = ACTION_PerformAction(package, L"CostInitialize");
3796     if (r != ERROR_SUCCESS)
3797         goto end;
3798 
3799     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
3800     if (r != ERROR_SUCCESS)
3801         goto end;
3802 
3803     r = MSI_InstallPackage( package, sourcepath, NULL );
3804 
3805 end:
3806     msiobj_release( &package->hdr );
3807 
3808     return r;
3809 }
3810 
3811 /***********************************************************************
3812  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
3813  *
3814  * Notes: undocumented
3815  */
3816 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
3817 {
3818     WCHAR path[MAX_PATH];
3819 
3820     TRACE( "%#lx\n", dwReserved );
3821 
3822     if (dwReserved)
3823     {
3824         FIXME( "dwReserved = %#lx\n", dwReserved );
3825         return ERROR_INVALID_PARAMETER;
3826     }
3827 
3828     if (!GetWindowsDirectoryW(path, MAX_PATH))
3829         return ERROR_FUNCTION_FAILED;
3830 
3831     lstrcatW(path, L"\\Installer");
3832 
3833     if (!CreateDirectoryW(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
3834         return ERROR_FUNCTION_FAILED;
3835 
3836     return ERROR_SUCCESS;
3837 }
3838 
3839 /***********************************************************************
3840  * MsiGetShortcutTargetA           [MSI.@]
3841  */
3842 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
3843                                    LPSTR szProductCode, LPSTR szFeatureId,
3844                                    LPSTR szComponentCode )
3845 {
3846     LPWSTR target;
3847     const int len = MAX_FEATURE_CHARS+1;
3848     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
3849     UINT r;
3850 
3851     target = strdupAtoW( szShortcutTarget );
3852     if (szShortcutTarget && !target )
3853         return ERROR_OUTOFMEMORY;
3854     product[0] = 0;
3855     feature[0] = 0;
3856     component[0] = 0;
3857     r = MsiGetShortcutTargetW( target, product, feature, component );
3858     msi_free( target );
3859     if (r == ERROR_SUCCESS)
3860     {
3861         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
3862         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
3863         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
3864     }
3865     return r;
3866 }
3867 
3868 /***********************************************************************
3869  * MsiGetShortcutTargetW           [MSI.@]
3870  */
3871 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
3872                                    LPWSTR szProductCode, LPWSTR szFeatureId,
3873                                    LPWSTR szComponentCode )
3874 {
3875     IShellLinkDataList *dl = NULL;
3876     IPersistFile *pf = NULL;
3877     LPEXP_DARWIN_LINK darwin = NULL;
3878     HRESULT r, init;
3879 
3880     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
3881           szProductCode, szFeatureId, szComponentCode );
3882 
3883     init = CoInitialize(NULL);
3884 
3885     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3886                           &IID_IPersistFile, (LPVOID*) &pf );
3887     if( SUCCEEDED( r ) )
3888     {
3889         r = IPersistFile_Load( pf, szShortcutTarget,
3890                                STGM_READ | STGM_SHARE_DENY_WRITE );
3891         if( SUCCEEDED( r ) )
3892         {
3893             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
3894                                              (LPVOID*) &dl );
3895             if( SUCCEEDED( r ) )
3896             {
3897                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
3898                                                   (LPVOID) &darwin );
3899                 IShellLinkDataList_Release( dl );
3900             }
3901         }
3902         IPersistFile_Release( pf );
3903     }
3904 
3905     if (SUCCEEDED(init))
3906         CoUninitialize();
3907 
3908     TRACE("darwin = %p\n", darwin);
3909 
3910     if (darwin)
3911     {
3912         DWORD sz;
3913         UINT ret;
3914 
3915         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
3916                   szProductCode, szFeatureId, szComponentCode, &sz );
3917         LocalFree( darwin );
3918         return ret;
3919     }
3920 
3921     return ERROR_FUNCTION_FAILED;
3922 }
3923 
3924 UINT WINAPI MsiReinstallFeatureW( const WCHAR *szProduct, const WCHAR *szFeature, DWORD dwReinstallMode )
3925 {
3926     MSIPACKAGE *package;
3927     MSIINSTALLCONTEXT context;
3928     UINT r;
3929     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH], reinstallmode[11];
3930     WCHAR *ptr, *cmdline;
3931     DWORD sz;
3932 
3933     TRACE( "%s, %s, %#lx\n", debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode );
3934 
3935     r = msi_locate_product( szProduct, &context );
3936     if (r != ERROR_SUCCESS)
3937         return r;
3938 
3939     ptr = reinstallmode;
3940 
3941     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
3942         *ptr++ = 'p';
3943     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
3944         *ptr++ = 'o';
3945     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
3946         *ptr++ = 'w';
3947     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
3948         *ptr++ = 'd';
3949     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
3950         *ptr++ = 'c';
3951     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
3952         *ptr++ = 'a';
3953     if (dwReinstallMode & REINSTALLMODE_USERDATA)
3954         *ptr++ = 'u';
3955     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
3956         *ptr++ = 'm';
3957     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
3958         *ptr++ = 's';
3959     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3960         *ptr++ = 'v';
3961     *ptr = 0;
3962 
3963     sz = sizeof(sourcepath);
3964     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
3965                            INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
3966     sz = sizeof(filename);
3967     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
3968                            INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
3969     lstrcatW( sourcepath, filename );
3970 
3971     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3972         r = MSI_OpenPackageW( sourcepath, 0, &package );
3973     else
3974         r = MSI_OpenProductW( szProduct, &package );
3975 
3976     if (r != ERROR_SUCCESS)
3977         return r;
3978 
3979     sz = (lstrlenW( L"%s=%s %s=%s" ) + lstrlenW( L"REINSTALLMODE" ) + lstrlenW( reinstallmode )) * sizeof(WCHAR);
3980     sz += (lstrlenW( L"REINSTALL" ) + lstrlenW( szFeature )) * sizeof(WCHAR);
3981     if (!(cmdline = msi_alloc( sz )))
3982     {
3983         msiobj_release( &package->hdr );
3984         return ERROR_OUTOFMEMORY;
3985     }
3986     swprintf( cmdline, sz / sizeof(WCHAR), L"%s=%s %s=%s", L"REINSTALLMODE", reinstallmode, L"REINSTALL", szFeature );
3987 
3988     r = MSI_InstallPackage( package, sourcepath, cmdline );
3989     msiobj_release( &package->hdr );
3990     msi_free( cmdline );
3991 
3992     return r;
3993 }
3994 
3995 UINT WINAPI MsiReinstallFeatureA( const char *szProduct, const char *szFeature, DWORD dwReinstallMode )
3996 {
3997     WCHAR *wszProduct, *wszFeature;
3998     UINT rc;
3999 
4000     TRACE( "%s, %s, %lu\n", debugstr_a(szProduct), debugstr_a(szFeature), dwReinstallMode );
4001 
4002     wszProduct = strdupAtoW(szProduct);
4003     wszFeature = strdupAtoW(szFeature);
4004 
4005     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
4006 
4007     msi_free(wszProduct);
4008     msi_free(wszFeature);
4009     return rc;
4010 }
4011 
4012 typedef struct
4013 {
4014     unsigned int i[2];
4015     unsigned int buf[4];
4016     unsigned char in[64];
4017     unsigned char digest[16];
4018 } MD5_CTX;
4019 
4020 extern VOID WINAPI MD5Init( MD5_CTX *);
4021 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
4022 extern VOID WINAPI MD5Final( MD5_CTX *);
4023 
4024 UINT msi_get_filehash( MSIPACKAGE *package, const WCHAR *path, MSIFILEHASHINFO *hash )
4025 {
4026     HANDLE handle, mapping;
4027     void *p;
4028     DWORD length;
4029     UINT r = ERROR_FUNCTION_FAILED;
4030 
4031     if (package)
4032         handle = msi_create_file( package, path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, OPEN_EXISTING, 0 );
4033     else
4034         handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
4035     if (handle == INVALID_HANDLE_VALUE)
4036     {
4037         WARN( "can't open file %lu\n", GetLastError() );
4038         return ERROR_FILE_NOT_FOUND;
4039     }
4040     if ((length = GetFileSize( handle, NULL )))
4041     {
4042         if ((mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL )))
4043         {
4044             if ((p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length )))
4045             {
4046                 MD5_CTX ctx;
4047 
4048                 MD5Init( &ctx );
4049                 MD5Update( &ctx, p, length );
4050                 MD5Final( &ctx );
4051                 UnmapViewOfFile( p );
4052 
4053                 memcpy( hash->dwData, ctx.digest, sizeof(hash->dwData) );
4054                 r = ERROR_SUCCESS;
4055             }
4056             CloseHandle( mapping );
4057         }
4058     }
4059     else
4060     {
4061         /* Empty file -> set hash to 0 */
4062         memset( hash->dwData, 0, sizeof(hash->dwData) );
4063         r = ERROR_SUCCESS;
4064     }
4065 
4066     CloseHandle( handle );
4067     return r;
4068 }
4069 
4070 /***********************************************************************
4071  * MsiGetFileHashW            [MSI.@]
4072  */
4073 UINT WINAPI MsiGetFileHashW( const WCHAR *szFilePath, DWORD dwOptions, MSIFILEHASHINFO *pHash )
4074 {
4075     TRACE( "%s, %#lx, %p\n", debugstr_w(szFilePath), dwOptions, pHash );
4076 
4077     if (!szFilePath)
4078         return ERROR_INVALID_PARAMETER;
4079 
4080     if (!*szFilePath)
4081         return ERROR_PATH_NOT_FOUND;
4082 
4083     if (dwOptions)
4084         return ERROR_INVALID_PARAMETER;
4085     if (!pHash)
4086         return ERROR_INVALID_PARAMETER;
4087     if (pHash->dwFileHashInfoSize < sizeof *pHash)
4088         return ERROR_INVALID_PARAMETER;
4089 
4090     return msi_get_filehash( NULL, szFilePath, pHash );
4091 }
4092 
4093 /***********************************************************************
4094  * MsiGetFileHashA            [MSI.@]
4095  */
4096 UINT WINAPI MsiGetFileHashA( const char *szFilePath, DWORD dwOptions, MSIFILEHASHINFO *pHash )
4097 {
4098     LPWSTR file;
4099     UINT r;
4100 
4101     TRACE( "%s, %#lx, %p\n", debugstr_a(szFilePath), dwOptions, pHash );
4102 
4103     file = strdupAtoW( szFilePath );
4104     if (szFilePath && !file)
4105         return ERROR_OUTOFMEMORY;
4106 
4107     r = MsiGetFileHashW( file, dwOptions, pHash );
4108     msi_free( file );
4109     return r;
4110 }
4111 
4112 /***********************************************************************
4113  * MsiAdvertiseScriptW        [MSI.@]
4114  */
4115 UINT WINAPI MsiAdvertiseScriptW( const WCHAR *szScriptFile, DWORD dwFlags, HKEY *phRegData, BOOL fRemoveItems )
4116 {
4117     FIXME( "%s, %#lx, %p, %d\n", debugstr_w(szScriptFile), dwFlags, phRegData, fRemoveItems );
4118     return ERROR_CALL_NOT_IMPLEMENTED;
4119 }
4120 
4121 /***********************************************************************
4122  * MsiAdvertiseScriptA        [MSI.@]
4123  */
4124 UINT WINAPI MsiAdvertiseScriptA( const char *szScriptFile, DWORD dwFlags, HKEY *phRegData, BOOL fRemoveItems )
4125 {
4126     FIXME( "%s, %#lx, %p, %d\n", debugstr_a(szScriptFile), dwFlags, phRegData, fRemoveItems );
4127     return ERROR_CALL_NOT_IMPLEMENTED;
4128 }
4129 
4130 /***********************************************************************
4131  * MsiIsProductElevatedW        [MSI.@]
4132  */
4133 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
4134 {
4135     FIXME("%s %p - stub\n",
4136           debugstr_w( szProduct ), pfElevated );
4137     *pfElevated = TRUE;
4138     return ERROR_SUCCESS;
4139 }
4140 
4141 /***********************************************************************
4142  * MsiIsProductElevatedA        [MSI.@]
4143  */
4144 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
4145 {
4146     FIXME("%s %p - stub\n",
4147           debugstr_a( szProduct ), pfElevated );
4148     *pfElevated = TRUE;
4149     return ERROR_SUCCESS;
4150 }
4151 
4152 /***********************************************************************
4153  * MsiSetExternalUIRecord     [MSI.@]
4154  */
4155 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler, DWORD filter, void *context,
4156                                     INSTALLUI_HANDLER_RECORD *prev )
4157 {
4158     TRACE( "%p, %#lx, %p, %p\n", handler, filter, context, prev );
4159 
4160     if (prev)
4161         *prev = gUIHandlerRecord;
4162 
4163     gUIHandlerRecord = handler;
4164     gUIFilterRecord  = filter;
4165     gUIContextRecord = context;
4166 
4167     return ERROR_SUCCESS;
4168 }
4169 
4170 /***********************************************************************
4171  * MsiInstallMissingComponentA     [MSI.@]
4172  */
4173 UINT WINAPI MsiInstallMissingComponentA( LPCSTR product, LPCSTR component, INSTALLSTATE state )
4174 {
4175     UINT r;
4176     WCHAR *productW = NULL, *componentW = NULL;
4177 
4178     TRACE("%s, %s, %d\n", debugstr_a(product), debugstr_a(component), state);
4179 
4180     if (product && !(productW = strdupAtoW( product )))
4181         return ERROR_OUTOFMEMORY;
4182 
4183     if (component && !(componentW = strdupAtoW( component )))
4184     {
4185         msi_free( productW );
4186         return ERROR_OUTOFMEMORY;
4187     }
4188 
4189     r = MsiInstallMissingComponentW( productW, componentW, state );
4190     msi_free( productW );
4191     msi_free( componentW );
4192     return r;
4193 }
4194 
4195 /***********************************************************************
4196  * MsiInstallMissingComponentW     [MSI.@]
4197  */
4198 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
4199 {
4200     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
4201     return ERROR_SUCCESS;
4202 }
4203 
4204 UINT WINAPI MsiProvideComponentA( const char *product, const char *feature, const char *component, DWORD mode,
4205                                   char *buf, DWORD *buflen )
4206 {
4207     WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL;
4208     UINT r = ERROR_OUTOFMEMORY;
4209     DWORD lenW = 0;
4210     int len;
4211 
4212     TRACE( "%s, %s, %s, %#lx, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode,
4213            buf, buflen );
4214 
4215     if (product && !(productW = strdupAtoW( product ))) goto done;
4216     if (feature && !(featureW = strdupAtoW( feature ))) goto done;
4217     if (component && !(componentW = strdupAtoW( component ))) goto done;
4218 
4219     r = MsiProvideComponentW( productW, featureW, componentW, mode, NULL, &lenW );
4220     if (r != ERROR_SUCCESS)
4221         goto done;
4222 
4223     if (!(bufW = msi_alloc( ++lenW * sizeof(WCHAR) )))
4224     {
4225         r = ERROR_OUTOFMEMORY;
4226         goto done;
4227     }
4228 
4229     r = MsiProvideComponentW( productW, featureW, componentW, mode, bufW, &lenW );
4230     if (r != ERROR_SUCCESS)
4231         goto done;
4232 
4233     len = WideCharToMultiByte( CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
4234     if (buf)
4235     {
4236         if (len > *buflen)
4237             r = ERROR_MORE_DATA;
4238         else
4239             WideCharToMultiByte( CP_ACP, 0, bufW, -1, buf, *buflen, NULL, NULL );
4240     }
4241 
4242     *buflen = len - 1;
4243 
4244 done:
4245     msi_free( productW );
4246     msi_free( featureW );
4247     msi_free( componentW );
4248     msi_free( bufW );
4249     return r;
4250 }
4251 
4252 UINT WINAPI MsiProvideComponentW( const WCHAR *product, const WCHAR *feature, const WCHAR *component, DWORD mode,
4253                                   WCHAR *buf, DWORD *buflen )
4254 {
4255     INSTALLSTATE state;
4256 
4257     TRACE( "%s, %s, %s, %#lx, %p, %p\n", debugstr_w(product), debugstr_w(component), debugstr_w(feature), mode,
4258            buf, buflen);
4259 
4260     state = MsiQueryFeatureStateW( product, feature );
4261     TRACE("feature state: %d\n", state);
4262     switch (mode)
4263     {
4264     case INSTALLMODE_NODETECTION:
4265         break;
4266 
4267     default:
4268         FIXME( "mode %#lx not implemented\n", mode );
4269         return ERROR_INSTALL_FAILURE;
4270     }
4271 
4272     state = MsiGetComponentPathW( product, component, buf, buflen );
4273     TRACE("component state: %d\n", state);
4274     switch (state)
4275     {
4276     case INSTALLSTATE_INVALIDARG:
4277         return ERROR_INVALID_PARAMETER;
4278 
4279     case INSTALLSTATE_MOREDATA:
4280         return ERROR_MORE_DATA;
4281 
4282     case INSTALLSTATE_ADVERTISED:
4283     case INSTALLSTATE_LOCAL:
4284     case INSTALLSTATE_SOURCE:
4285         MsiUseFeatureW( product, feature );
4286         return ERROR_SUCCESS;
4287 
4288     default:
4289         TRACE("MsiGetComponentPathW returned %d\n", state);
4290         return ERROR_INSTALL_FAILURE;
4291     }
4292 }
4293 
4294 /***********************************************************************
4295  * MsiBeginTransactionA     [MSI.@]
4296  */
4297 UINT WINAPI MsiBeginTransactionA( const char *name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
4298 {
4299     WCHAR *nameW;
4300     UINT r;
4301 
4302     FIXME( "%s, %#lx, %p, %p\n", debugstr_a(name), attrs, id, event );
4303 
4304     nameW = strdupAtoW( name );
4305     if (name && !nameW)
4306         return ERROR_OUTOFMEMORY;
4307 
4308     r = MsiBeginTransactionW( nameW, attrs, id, event );
4309     msi_free( nameW );
4310     return r;
4311 }
4312 
4313 /***********************************************************************
4314  * MsiBeginTransactionW     [MSI.@]
4315  */
4316 UINT WINAPI MsiBeginTransactionW( const WCHAR *name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
4317 {
4318     FIXME( "%s, %#lx, %p, %p\n", debugstr_w(name), attrs, id, event );
4319 
4320     *id = (MSIHANDLE)0xdeadbeef;
4321     *event = (HANDLE)0xdeadbeef;
4322 
4323     return ERROR_SUCCESS;
4324 }
4325 
4326 /***********************************************************************
4327  * MsiJoinTransaction     [MSI.@]
4328  */
4329 UINT WINAPI MsiJoinTransaction( MSIHANDLE handle, DWORD attrs, HANDLE *event )
4330 {
4331     FIXME( "%lu, %#lx, %p\n", handle, attrs, event );
4332 
4333     *event = (HANDLE)0xdeadbeef;
4334     return ERROR_SUCCESS;
4335 }
4336 
4337 /***********************************************************************
4338  * MsiEndTransaction     [MSI.@]
4339  */
4340 UINT WINAPI MsiEndTransaction( DWORD state )
4341 {
4342     FIXME( "%#lx\n", state );
4343     return ERROR_SUCCESS;
4344 }
4345 
4346 UINT WINAPI Migrate10CachedPackagesW( void *a, void *b, void *c, DWORD d )
4347 {
4348     FIXME( "%p, %p, %p, %#lx\n", a, b, c, d );
4349     return ERROR_SUCCESS;
4350 }
4351 
4352 /***********************************************************************
4353  * MsiRemovePatchesA     [MSI.@]
4354  */
4355 UINT WINAPI MsiRemovePatchesA(LPCSTR patchlist, LPCSTR product, INSTALLTYPE type, LPCSTR propertylist)
4356 {
4357     FIXME("(%s %s %d %s\n", debugstr_a(patchlist), debugstr_a(product), type, debugstr_a(propertylist));
4358     return ERROR_SUCCESS;
4359 }
4360 
4361 /***********************************************************************
4362  * MsiRemovePatchesW    [MSI.@]
4363  */
4364 UINT WINAPI MsiRemovePatchesW(LPCWSTR patchlist, LPCWSTR product, INSTALLTYPE type, LPCWSTR propertylist)
4365 {
4366     FIXME("(%s %s %d %s\n", debugstr_w(patchlist), debugstr_w(product), type, debugstr_w(propertylist));
4367     return ERROR_SUCCESS;
4368 }
4369