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