xref: /reactos/dll/win32/msi/msi.c (revision d56c9a89)
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     if (dwUILevel & ~(INSTALLUILEVEL_MASK|INSTALLUILEVEL_HIDECANCEL|INSTALLUILEVEL_PROGRESSONLY|
2297                       INSTALLUILEVEL_ENDDIALOG|INSTALLUILEVEL_SOURCERESONLY))
2298     {
2299         FIXME("Unrecognized flags %08x\n", dwUILevel);
2300         return INSTALLUILEVEL_NOCHANGE;
2301     }
2302 
2303     if (dwUILevel != INSTALLUILEVEL_NOCHANGE)
2304         gUILevel = dwUILevel;
2305 
2306     if (phWnd)
2307     {
2308         gUIhwnd = *phWnd;
2309         *phWnd = oldwnd;
2310     }
2311     return old;
2312 }
2313 
2314 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
2315                                   DWORD dwMessageFilter, LPVOID pvContext)
2316 {
2317     INSTALLUI_HANDLERA prev = gUIHandlerA;
2318 
2319     TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
2320 
2321     gUIHandlerA = puiHandler;
2322     gUIHandlerW = NULL;
2323     gUIFilter   = dwMessageFilter;
2324     gUIContext  = pvContext;
2325 
2326     return prev;
2327 }
2328 
2329 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
2330                                   DWORD dwMessageFilter, LPVOID pvContext)
2331 {
2332     INSTALLUI_HANDLERW prev = gUIHandlerW;
2333 
2334     TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
2335 
2336     gUIHandlerA = NULL;
2337     gUIHandlerW = puiHandler;
2338     gUIFilter   = dwMessageFilter;
2339     gUIContext  = pvContext;
2340 
2341     return prev;
2342 }
2343 
2344 /******************************************************************
2345  *  MsiLoadStringW            [MSI.@]
2346  *
2347  * Loads a string from MSI's string resources.
2348  *
2349  * PARAMS
2350  *
2351  *   handle        [I]  only -1 is handled currently
2352  *   id            [I]  id of the string to be loaded
2353  *   lpBuffer      [O]  buffer for the string to be written to
2354  *   nBufferMax    [I]  maximum size of the buffer in characters
2355  *   lang          [I]  the preferred language for the string
2356  *
2357  * RETURNS
2358  *
2359  *   If successful, this function returns the language id of the string loaded
2360  *   If the function fails, the function returns zero.
2361  *
2362  * NOTES
2363  *
2364  *   The type of the first parameter is unknown.  LoadString's prototype
2365  *  suggests that it might be a module handle.  I have made it an MSI handle
2366  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
2367  *  handle.  Maybe strings can be stored in an MSI database somehow.
2368  */
2369 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
2370                 int nBufferMax, LANGID lang )
2371 {
2372     HRSRC hres;
2373     HGLOBAL hResData;
2374     LPWSTR p;
2375     DWORD i, len;
2376 
2377     TRACE("%d %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
2378 
2379     if( handle != -1 )
2380         FIXME("don't know how to deal with handle = %08x\n", handle);
2381 
2382     if( !lang )
2383         lang = GetUserDefaultLangID();
2384 
2385     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
2386                             (LPWSTR)1, lang );
2387     if( !hres )
2388         return 0;
2389     hResData = LoadResource( msi_hInstance, hres );
2390     if( !hResData )
2391         return 0;
2392     p = LockResource( hResData );
2393     if( !p )
2394         return 0;
2395 
2396     for (i = 0; i < (id & 0xf); i++) p += *p + 1;
2397     len = *p;
2398 
2399     if( nBufferMax <= len )
2400         return 0;
2401 
2402     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
2403     lpBuffer[ len ] = 0;
2404 
2405     TRACE("found -> %s\n", debugstr_w(lpBuffer));
2406     return lang;
2407 }
2408 
2409 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
2410                 int nBufferMax, LANGID lang )
2411 {
2412     LPWSTR bufW;
2413     LANGID r;
2414     INT len;
2415 
2416     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
2417     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
2418     if( r )
2419     {
2420         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
2421         if( len <= nBufferMax )
2422             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
2423                                  lpBuffer, nBufferMax, NULL, NULL );
2424         else
2425             r = 0;
2426     }
2427     msi_free(bufW);
2428     return r;
2429 }
2430 
2431 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
2432                 LPDWORD pcchBuf)
2433 {
2434     char szProduct[GUID_SIZE];
2435 
2436     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
2437 
2438     if (!szComponent || !pcchBuf)
2439         return INSTALLSTATE_INVALIDARG;
2440 
2441     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
2442         return INSTALLSTATE_UNKNOWN;
2443 
2444     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
2445 }
2446 
2447 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
2448                 LPDWORD pcchBuf)
2449 {
2450     WCHAR szProduct[GUID_SIZE];
2451 
2452     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
2453 
2454     if (!szComponent || !pcchBuf)
2455         return INSTALLSTATE_INVALIDARG;
2456 
2457     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
2458         return INSTALLSTATE_UNKNOWN;
2459 
2460     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
2461 }
2462 
2463 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
2464                 WORD wLanguageId, DWORD f)
2465 {
2466     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
2467           uType, wLanguageId, f);
2468     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId);
2469 }
2470 
2471 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
2472                 WORD wLanguageId, DWORD f)
2473 {
2474     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
2475           uType, wLanguageId, f);
2476     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId);
2477 }
2478 
2479 UINT WINAPI MsiMessageBoxExA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
2480                 DWORD unknown, WORD wLanguageId, DWORD f)
2481 {
2482     FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_a(lpText),
2483             debugstr_a(lpCaption), uType, unknown, wLanguageId, f);
2484     return MessageBoxExA(hWnd, lpText, lpCaption, uType, wLanguageId);
2485 }
2486 
2487 UINT WINAPI MsiMessageBoxExW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
2488                 DWORD unknown, WORD wLanguageId, DWORD f)
2489 {
2490     FIXME("(%p, %s, %s, %u, 0x%08x, 0x%08x, 0x%08x): semi-stub\n", hWnd, debugstr_w(lpText),
2491             debugstr_w(lpCaption), uType, unknown, wLanguageId, f);
2492     return MessageBoxExW(hWnd, lpText, lpCaption, uType, wLanguageId);
2493 }
2494 
2495 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
2496                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
2497                 LPDWORD pcchPathBuf )
2498 {
2499     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
2500           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2501           pcchPathBuf);
2502     return ERROR_CALL_NOT_IMPLEMENTED;
2503 }
2504 
2505 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
2506                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
2507                 LPDWORD pcchPathBuf )
2508 {
2509     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
2510           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2511           pcchPathBuf);
2512     return ERROR_CALL_NOT_IMPLEMENTED;
2513 }
2514 
2515 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2516                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2517 {
2518     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2519     return ERROR_CALL_NOT_IMPLEMENTED;
2520 }
2521 
2522 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2523                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2524 {
2525     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2526     return ERROR_CALL_NOT_IMPLEMENTED;
2527 }
2528 
2529 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR path, DWORD flags, PCCERT_CONTEXT *cert,
2530                                                 LPBYTE hash, LPDWORD hashlen )
2531 {
2532     UINT r;
2533     WCHAR *pathW = NULL;
2534 
2535     TRACE("%s %08x %p %p %p\n", debugstr_a(path), flags, cert, hash, hashlen);
2536 
2537     if (path && !(pathW = strdupAtoW( path ))) return E_OUTOFMEMORY;
2538     r = MsiGetFileSignatureInformationW( pathW, flags, cert, hash, hashlen );
2539     msi_free( pathW );
2540     return r;
2541 }
2542 
2543 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR path, DWORD flags, PCCERT_CONTEXT *cert,
2544                                                 LPBYTE hash, LPDWORD hashlen )
2545 {
2546     static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
2547     HRESULT hr;
2548     WINTRUST_DATA data;
2549     WINTRUST_FILE_INFO info;
2550     CRYPT_PROVIDER_SGNR *signer;
2551     CRYPT_PROVIDER_CERT *provider;
2552 
2553     TRACE("%s %08x %p %p %p\n", debugstr_w(path), flags, cert, hash, hashlen);
2554 
2555     if (!path || !cert) return E_INVALIDARG;
2556 
2557     info.cbStruct       = sizeof(info);
2558     info.pcwszFilePath  = path;
2559     info.hFile          = NULL;
2560     info.pgKnownSubject = NULL;
2561 
2562     data.cbStruct            = sizeof(data);
2563     data.pPolicyCallbackData = NULL;
2564     data.pSIPClientData      = NULL;
2565     data.dwUIChoice          = WTD_UI_NONE;
2566     data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
2567     data.dwUnionChoice       = WTD_CHOICE_FILE;
2568     data.u.pFile             = &info;
2569     data.dwStateAction       = WTD_STATEACTION_VERIFY;
2570     data.hWVTStateData       = NULL;
2571     data.pwszURLReference    = NULL;
2572     data.dwProvFlags         = 0;
2573     data.dwUIContext         = WTD_UICONTEXT_INSTALL;
2574     hr = WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2575     *cert = NULL;
2576     if (FAILED(hr)) goto done;
2577 
2578     if (!(signer = WTHelperGetProvSignerFromChain( data.hWVTStateData, 0, FALSE, 0 )))
2579     {
2580         hr = TRUST_E_NOSIGNATURE;
2581         goto done;
2582     }
2583     if (hash)
2584     {
2585         DWORD len = signer->psSigner->EncryptedHash.cbData;
2586         if (*hashlen < len)
2587         {
2588             *hashlen = len;
2589             hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
2590             goto done;
2591         }
2592         memcpy( hash, signer->psSigner->EncryptedHash.pbData, len );
2593         *hashlen = len;
2594     }
2595     if (!(provider = WTHelperGetProvCertFromChain( signer, 0 )))
2596     {
2597         hr = TRUST_E_PROVIDER_UNKNOWN;
2598         goto done;
2599     }
2600     *cert = CertDuplicateCertificateContext( provider->pCert );
2601 
2602 done:
2603     data.dwStateAction = WTD_STATEACTION_CLOSE;
2604     WinVerifyTrustEx( INVALID_HANDLE_VALUE, &generic_verify_v2, &data );
2605     return hr;
2606 }
2607 
2608 /******************************************************************
2609  * MsiGetProductPropertyA      [MSI.@]
2610  */
2611 UINT WINAPI MsiGetProductPropertyA(MSIHANDLE hProduct, LPCSTR szProperty,
2612                                    LPSTR szValue, LPDWORD pccbValue)
2613 {
2614     LPWSTR prop = NULL, val = NULL;
2615     DWORD len;
2616     UINT r;
2617 
2618     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_a(szProperty),
2619           szValue, pccbValue);
2620 
2621     if (szValue && !pccbValue)
2622         return ERROR_INVALID_PARAMETER;
2623 
2624     if (szProperty) prop = strdupAtoW(szProperty);
2625 
2626     len = 0;
2627     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2628     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2629         goto done;
2630 
2631     if (r == ERROR_SUCCESS)
2632     {
2633         if (szValue) *szValue = '\0';
2634         if (pccbValue) *pccbValue = 0;
2635         goto done;
2636     }
2637 
2638     val = msi_alloc(++len * sizeof(WCHAR));
2639     if (!val)
2640     {
2641         r = ERROR_OUTOFMEMORY;
2642         goto done;
2643     }
2644 
2645     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2646     if (r != ERROR_SUCCESS)
2647         goto done;
2648 
2649     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2650 
2651     if (szValue)
2652         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2653                             *pccbValue, NULL, NULL);
2654 
2655     if (pccbValue)
2656     {
2657         if (len > *pccbValue)
2658             r = ERROR_MORE_DATA;
2659 
2660         *pccbValue = len - 1;
2661     }
2662 
2663 done:
2664     msi_free(prop);
2665     msi_free(val);
2666 
2667     return r;
2668 }
2669 
2670 /******************************************************************
2671  * MsiGetProductPropertyW      [MSI.@]
2672  */
2673 UINT WINAPI MsiGetProductPropertyW(MSIHANDLE hProduct, LPCWSTR szProperty,
2674                                    LPWSTR szValue, LPDWORD pccbValue)
2675 {
2676     MSIPACKAGE *package;
2677     MSIQUERY *view = NULL;
2678     MSIRECORD *rec = NULL;
2679     LPCWSTR val;
2680     UINT r;
2681 
2682     static const WCHAR query[] = {
2683        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2684        '`','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2685        '`','P','r','o','p','e','r','t','y','`','=','\'','%','s','\'',0};
2686 
2687     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_w(szProperty),
2688           szValue, pccbValue);
2689 
2690     if (!szProperty)
2691         return ERROR_INVALID_PARAMETER;
2692 
2693     if (szValue && !pccbValue)
2694         return ERROR_INVALID_PARAMETER;
2695 
2696     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2697     if (!package)
2698         return ERROR_INVALID_HANDLE;
2699 
2700     r = MSI_OpenQuery(package->db, &view, query, szProperty);
2701     if (r != ERROR_SUCCESS)
2702         goto done;
2703 
2704     r = MSI_ViewExecute(view, 0);
2705     if (r != ERROR_SUCCESS)
2706         goto done;
2707 
2708     r = MSI_ViewFetch(view, &rec);
2709     if (r != ERROR_SUCCESS)
2710         goto done;
2711 
2712     val = MSI_RecordGetString(rec, 2);
2713     if (!val)
2714         goto done;
2715 
2716     if (lstrlenW(val) >= *pccbValue)
2717     {
2718         if (szValue) lstrcpynW(szValue, val, *pccbValue);
2719         r = ERROR_MORE_DATA;
2720     }
2721     else
2722     {
2723         if (szValue) lstrcpyW(szValue, val);
2724         r = ERROR_SUCCESS;
2725     }
2726 
2727     *pccbValue = lstrlenW(val);
2728 
2729 done:
2730     if (view)
2731     {
2732         MSI_ViewClose(view);
2733         msiobj_release(&view->hdr);
2734         if (rec) msiobj_release(&rec->hdr);
2735     }
2736 
2737     if (!rec)
2738     {
2739         if (szValue) *szValue = '\0';
2740         if (pccbValue) *pccbValue = 0;
2741         r = ERROR_SUCCESS;
2742     }
2743 
2744     msiobj_release(&package->hdr);
2745     return r;
2746 }
2747 
2748 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2749 {
2750     UINT r;
2751     LPWSTR szPack = NULL;
2752 
2753     TRACE("%s\n", debugstr_a(szPackage) );
2754 
2755     if( szPackage )
2756     {
2757         szPack = strdupAtoW( szPackage );
2758         if( !szPack )
2759             return ERROR_OUTOFMEMORY;
2760     }
2761 
2762     r = MsiVerifyPackageW( szPack );
2763 
2764     msi_free( szPack );
2765 
2766     return r;
2767 }
2768 
2769 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2770 {
2771     MSIHANDLE handle;
2772     UINT r;
2773 
2774     TRACE("%s\n", debugstr_w(szPackage) );
2775 
2776     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2777     MsiCloseHandle( handle );
2778 
2779     return r;
2780 }
2781 
2782 static BOOL open_userdata_comp_key( const WCHAR *comp, const WCHAR *usersid, MSIINSTALLCONTEXT ctx,
2783                                     HKEY *hkey )
2784 {
2785     if (ctx & MSIINSTALLCONTEXT_MACHINE)
2786     {
2787         if (!MSIREG_OpenUserDataComponentKey( comp, szLocalSid, hkey, FALSE )) return TRUE;
2788     }
2789     if (ctx & (MSIINSTALLCONTEXT_USERMANAGED|MSIINSTALLCONTEXT_USERUNMANAGED))
2790     {
2791         if (usersid && !strcmpiW( usersid, szAllSid ))
2792         {
2793             FIXME( "only looking at the current user\n" );
2794             usersid = NULL;
2795         }
2796         if (!MSIREG_OpenUserDataComponentKey( comp, usersid, hkey, FALSE )) return TRUE;
2797     }
2798     return FALSE;
2799 }
2800 
2801 static INSTALLSTATE MSI_GetComponentPath( const WCHAR *szProduct, const WCHAR *szComponent,
2802                                           const WCHAR *szUserSid, MSIINSTALLCONTEXT ctx,
2803                                           awstring *lpPathBuf, DWORD *pcchBuf )
2804 {
2805     static const WCHAR wininstaller[] =
2806         {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
2807     WCHAR *path = NULL, squashed_pc[SQUASHED_GUID_SIZE], squashed_comp[SQUASHED_GUID_SIZE];
2808     HKEY hkey;
2809     INSTALLSTATE state;
2810     DWORD version;
2811 
2812     if (!szProduct || !szComponent)
2813         return INSTALLSTATE_INVALIDARG;
2814 
2815     if (lpPathBuf->str.w && !pcchBuf)
2816         return INSTALLSTATE_INVALIDARG;
2817 
2818     if (!squash_guid( szProduct, squashed_pc ) || !squash_guid( szComponent, squashed_comp ))
2819         return INSTALLSTATE_INVALIDARG;
2820 
2821     if (szUserSid && ctx == MSIINSTALLCONTEXT_MACHINE)
2822         return INSTALLSTATE_INVALIDARG;
2823 
2824     state = INSTALLSTATE_UNKNOWN;
2825 
2826     if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2827     {
2828         path = msi_reg_get_val_str( hkey, squashed_pc );
2829         RegCloseKey(hkey);
2830 
2831         state = INSTALLSTATE_ABSENT;
2832 
2833         if ((!MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL, &hkey, FALSE) ||
2834              !MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED, NULL, &hkey, FALSE)) &&
2835             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
2836             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2837         {
2838             RegCloseKey(hkey);
2839             state = INSTALLSTATE_LOCAL;
2840         }
2841     }
2842 
2843     if (state != INSTALLSTATE_LOCAL &&
2844         (!MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hkey, FALSE) ||
2845          !MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE, &hkey, FALSE)))
2846     {
2847         RegCloseKey(hkey);
2848 
2849         if (open_userdata_comp_key( szComponent, szUserSid, ctx, &hkey ))
2850         {
2851             msi_free(path);
2852             path = msi_reg_get_val_str( hkey, squashed_pc );
2853             RegCloseKey(hkey);
2854 
2855             state = INSTALLSTATE_ABSENT;
2856 
2857             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2858                 state = INSTALLSTATE_LOCAL;
2859         }
2860     }
2861 
2862     if (!path)
2863         return INSTALLSTATE_UNKNOWN;
2864 
2865     if (state == INSTALLSTATE_LOCAL && !*path)
2866         state = INSTALLSTATE_NOTUSED;
2867 
2868     if (msi_strcpy_to_awstring(path, -1, lpPathBuf, pcchBuf) == ERROR_MORE_DATA)
2869         state = INSTALLSTATE_MOREDATA;
2870 
2871     msi_free(path);
2872     return state;
2873 }
2874 
2875 /******************************************************************
2876  * MsiGetComponentPathExW      [MSI.@]
2877  */
2878 INSTALLSTATE WINAPI MsiGetComponentPathExW( LPCWSTR product, LPCWSTR comp, LPCWSTR usersid,
2879                                             MSIINSTALLCONTEXT ctx, LPWSTR buf, LPDWORD buflen )
2880 {
2881     awstring path;
2882 
2883     TRACE( "%s %s %s 0x%x %p %p\n", debugstr_w(product), debugstr_w(comp), debugstr_w(usersid),
2884            ctx, buf, buflen );
2885 
2886     path.unicode = TRUE;
2887     path.str.w   = buf;
2888 
2889     return MSI_GetComponentPath( product, comp, usersid, ctx, &path, buflen );
2890 }
2891 
2892 INSTALLSTATE WINAPI MsiGetComponentPathExA( LPCSTR product, LPCSTR comp, LPCSTR usersid,
2893                                             MSIINSTALLCONTEXT ctx, LPSTR buf, LPDWORD buflen )
2894 {
2895     WCHAR *productW = NULL, *compW = NULL, *usersidW =  NULL;
2896     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2897     awstring path;
2898 
2899     TRACE( "%s %s %s 0x%x %p %p\n", debugstr_a(product), debugstr_a(comp), debugstr_a(usersid),
2900            ctx, buf, buflen );
2901 
2902     if (product && !(productW = strdupAtoW( product ))) return INSTALLSTATE_UNKNOWN;
2903     if (comp && !(compW = strdupAtoW( comp ))) goto end;
2904     if (usersid && !(usersidW = strdupAtoW( usersid ))) goto end;
2905 
2906     path.unicode = FALSE;
2907     path.str.a   = buf;
2908 
2909     r = MSI_GetComponentPath( productW, compW, usersidW, ctx, &path, buflen );
2910 
2911 end:
2912     msi_free( productW );
2913     msi_free( compW );
2914     msi_free( usersidW );
2915 
2916     return r;
2917 }
2918 
2919 /******************************************************************
2920  * MsiGetComponentPathW      [MSI.@]
2921  */
2922 INSTALLSTATE WINAPI MsiGetComponentPathW( LPCWSTR product, LPCWSTR comp, LPWSTR buf, LPDWORD buflen )
2923 {
2924     return MsiGetComponentPathExW( product, comp, szAllSid, MSIINSTALLCONTEXT_ALL, buf, buflen );
2925 }
2926 
2927 /******************************************************************
2928  * MsiGetComponentPathA      [MSI.@]
2929  */
2930 INSTALLSTATE WINAPI MsiGetComponentPathA( LPCSTR product, LPCSTR comp, LPSTR buf, LPDWORD buflen )
2931 {
2932     return MsiGetComponentPathExA( product, comp, "s-1-1-0", MSIINSTALLCONTEXT_ALL, buf, buflen );
2933 }
2934 
2935 static UINT query_feature_state( const WCHAR *product, const WCHAR *squashed, const WCHAR *usersid,
2936                                  MSIINSTALLCONTEXT ctx, const WCHAR *feature, INSTALLSTATE *state )
2937 {
2938     UINT r;
2939     HKEY hkey;
2940     WCHAR *parent, *components, *path;
2941     const WCHAR *p;
2942     BOOL missing = FALSE, source = FALSE;
2943     WCHAR comp[GUID_SIZE];
2944     GUID guid;
2945 
2946     if (ctx != MSIINSTALLCONTEXT_MACHINE) SetLastError( ERROR_SUCCESS );
2947 
2948     if (MSIREG_OpenFeaturesKey( product, usersid, ctx, &hkey, FALSE )) return ERROR_UNKNOWN_PRODUCT;
2949 
2950     parent = msi_reg_get_val_str( hkey, feature );
2951     RegCloseKey( hkey );
2952     if (!parent) return ERROR_UNKNOWN_FEATURE;
2953 
2954     *state = (parent[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2955     msi_free( parent );
2956     if (*state == INSTALLSTATE_ABSENT)
2957         return ERROR_SUCCESS;
2958 
2959     r = MSIREG_OpenUserDataFeaturesKey( product, usersid, ctx, &hkey, FALSE );
2960     if (r != ERROR_SUCCESS)
2961     {
2962         *state = INSTALLSTATE_ADVERTISED;
2963         return ERROR_SUCCESS;
2964     }
2965     components = msi_reg_get_val_str( hkey, feature );
2966     RegCloseKey( hkey );
2967 
2968     TRACE("buffer = %s\n", debugstr_w(components));
2969 
2970     if (!components)
2971     {
2972         *state = INSTALLSTATE_ADVERTISED;
2973         return ERROR_SUCCESS;
2974     }
2975     for (p = components; *p && *p != 2 ; p += 20)
2976     {
2977         if (!decode_base85_guid( p, &guid ))
2978         {
2979             if (p != components) break;
2980             msi_free( components );
2981             *state = INSTALLSTATE_BADCONFIG;
2982             return ERROR_BAD_CONFIGURATION;
2983         }
2984         StringFromGUID2( &guid, comp, GUID_SIZE );
2985         if (ctx == MSIINSTALLCONTEXT_MACHINE)
2986             r = MSIREG_OpenUserDataComponentKey( comp, szLocalSid, &hkey, FALSE );
2987         else
2988             r = MSIREG_OpenUserDataComponentKey( comp, usersid, &hkey, FALSE );
2989 
2990         if (r != ERROR_SUCCESS)
2991         {
2992             msi_free( components );
2993             *state = INSTALLSTATE_ADVERTISED;
2994             return ERROR_SUCCESS;
2995         }
2996         path = msi_reg_get_val_str( hkey, squashed );
2997         if (!path) missing = TRUE;
2998         else if (strlenW( path ) > 2 &&
2999                  path[0] >= '0' && path[0] <= '9' &&
3000                  path[1] >= '0' && path[1] <= '9')
3001         {
3002             source = TRUE;
3003         }
3004         msi_free( path );
3005     }
3006     msi_free( components );
3007 
3008     if (missing)
3009         *state = INSTALLSTATE_ADVERTISED;
3010     else if (source)
3011         *state = INSTALLSTATE_SOURCE;
3012     else
3013         *state = INSTALLSTATE_LOCAL;
3014 
3015     TRACE("returning state %d\n", *state);
3016     return ERROR_SUCCESS;
3017 }
3018 
3019 UINT WINAPI MsiQueryFeatureStateExA( LPCSTR product, LPCSTR usersid, MSIINSTALLCONTEXT ctx,
3020                                      LPCSTR feature, INSTALLSTATE *state )
3021 {
3022     UINT r;
3023     WCHAR *productW = NULL, *usersidW = NULL, *featureW = NULL;
3024 
3025     if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
3026     if (usersid && !(usersidW = strdupAtoW( usersid )))
3027     {
3028         msi_free( productW );
3029         return ERROR_OUTOFMEMORY;
3030     }
3031     if (feature && !(featureW = strdupAtoW( feature )))
3032     {
3033         msi_free( productW );
3034         msi_free( usersidW );
3035         return ERROR_OUTOFMEMORY;
3036     }
3037     r = MsiQueryFeatureStateExW( productW, usersidW, ctx, featureW, state );
3038     msi_free( productW );
3039     msi_free( usersidW );
3040     msi_free( featureW );
3041     return r;
3042 }
3043 
3044 UINT WINAPI MsiQueryFeatureStateExW( LPCWSTR product, LPCWSTR usersid, MSIINSTALLCONTEXT ctx,
3045                                      LPCWSTR feature, INSTALLSTATE *state )
3046 {
3047     WCHAR squashed[33];
3048     if (!squash_guid( product, squashed )) return ERROR_INVALID_PARAMETER;
3049     return query_feature_state( product, squashed, usersid, ctx, feature, state );
3050 }
3051 
3052 /******************************************************************
3053  * MsiQueryFeatureStateA      [MSI.@]
3054  */
3055 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
3056 {
3057     LPWSTR szwProduct = NULL, szwFeature= NULL;
3058     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
3059 
3060     szwProduct = strdupAtoW( szProduct );
3061     if ( szProduct && !szwProduct )
3062         goto end;
3063 
3064     szwFeature = strdupAtoW( szFeature );
3065     if ( szFeature && !szwFeature )
3066         goto end;
3067 
3068     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
3069 
3070 end:
3071     msi_free( szwProduct);
3072     msi_free( szwFeature);
3073 
3074     return rc;
3075 }
3076 
3077 /******************************************************************
3078  * MsiQueryFeatureStateW      [MSI.@]
3079  *
3080  * Checks the state of a feature
3081  *
3082  * PARAMS
3083  *   szProduct     [I]  Product's GUID string
3084  *   szFeature     [I]  Feature's GUID string
3085  *
3086  * RETURNS
3087  *   INSTALLSTATE_LOCAL        Feature is installed and usable
3088  *   INSTALLSTATE_ABSENT       Feature is absent
3089  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
3090  *   INSTALLSTATE_UNKNOWN      An error occurred
3091  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
3092  *
3093  */
3094 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
3095 {
3096     UINT r;
3097     INSTALLSTATE state;
3098     WCHAR squashed[33];
3099 
3100     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
3101 
3102     if (!szProduct || !szFeature || !squash_guid( szProduct, squashed ))
3103         return INSTALLSTATE_INVALIDARG;
3104 
3105     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERMANAGED, szFeature, &state );
3106     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3107 
3108     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, szFeature, &state );
3109     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3110 
3111     r = query_feature_state( szProduct, squashed, NULL, MSIINSTALLCONTEXT_MACHINE, szFeature, &state );
3112     if (r == ERROR_SUCCESS || r == ERROR_BAD_CONFIGURATION) return state;
3113 
3114     return INSTALLSTATE_UNKNOWN;
3115 }
3116 
3117 /******************************************************************
3118  * MsiGetFileVersionA         [MSI.@]
3119  */
3120 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
3121                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
3122 {
3123     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
3124     UINT ret = ERROR_OUTOFMEMORY;
3125 
3126     if ((lpVersionBuf && !pcchVersionBuf) ||
3127         (lpLangBuf && !pcchLangBuf))
3128         return ERROR_INVALID_PARAMETER;
3129 
3130     if( szFilePath )
3131     {
3132         szwFilePath = strdupAtoW( szFilePath );
3133         if( !szwFilePath )
3134             goto end;
3135     }
3136 
3137     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
3138     {
3139         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
3140         if( !lpwVersionBuff )
3141             goto end;
3142     }
3143 
3144     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
3145     {
3146         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
3147         if( !lpwLangBuff )
3148             goto end;
3149     }
3150 
3151     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
3152                              lpwLangBuff, pcchLangBuf);
3153 
3154     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
3155         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
3156                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
3157     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
3158         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
3159                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
3160 
3161 end:
3162     msi_free(szwFilePath);
3163     msi_free(lpwVersionBuff);
3164     msi_free(lpwLangBuff);
3165 
3166     return ret;
3167 }
3168 
3169 static UINT get_file_version( const WCHAR *path, WCHAR *verbuf, DWORD *verlen,
3170                               WCHAR *langbuf, DWORD *langlen )
3171 {
3172     static const WCHAR szVersionResource[] = {'\\',0};
3173     static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3174     static const WCHAR szLangFormat[] = {'%','d',0};
3175     UINT ret = ERROR_MORE_DATA;
3176     DWORD len, error;
3177     LPVOID version;
3178     VS_FIXEDFILEINFO *ffi;
3179     USHORT *lang;
3180     WCHAR tmp[32];
3181 
3182     if (!(len = GetFileVersionInfoSizeW( path, NULL )))
3183     {
3184         error = GetLastError();
3185         if (error == ERROR_BAD_PATHNAME) return ERROR_FILE_NOT_FOUND;
3186         if (error == ERROR_RESOURCE_DATA_NOT_FOUND) return ERROR_FILE_INVALID;
3187         return error;
3188     }
3189     if (!(version = msi_alloc( len ))) return ERROR_OUTOFMEMORY;
3190     if (!GetFileVersionInfoW( path, 0, len, version ))
3191     {
3192         msi_free( version );
3193         return GetLastError();
3194     }
3195     if (!verbuf && !verlen && !langbuf && !langlen)
3196     {
3197         msi_free( version );
3198         return ERROR_SUCCESS;
3199     }
3200     if (verlen)
3201     {
3202         if (VerQueryValueW( version, szVersionResource, (LPVOID *)&ffi, &len ) && len > 0)
3203         {
3204             sprintfW( tmp, szVersionFormat,
3205                       HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
3206                       HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS) );
3207             if (verbuf) lstrcpynW( verbuf, tmp, *verlen );
3208             len = strlenW( tmp );
3209             if (*verlen > len) ret = ERROR_SUCCESS;
3210             *verlen = len;
3211         }
3212         else
3213         {
3214             if (verbuf) *verbuf = 0;
3215             *verlen = 0;
3216         }
3217     }
3218     if (langlen)
3219     {
3220         if (VerQueryValueW( version, szLangResource, (LPVOID *)&lang, &len ) && len > 0)
3221         {
3222             sprintfW( tmp, szLangFormat, *lang );
3223             if (langbuf) lstrcpynW( langbuf, tmp, *langlen );
3224             len = strlenW( tmp );
3225             if (*langlen > len) ret = ERROR_SUCCESS;
3226             *langlen = len;
3227         }
3228         else
3229         {
3230             if (langbuf) *langbuf = 0;
3231             *langlen = 0;
3232         }
3233     }
3234     msi_free( version );
3235     return ret;
3236 }
3237 
3238 
3239 /******************************************************************
3240  * MsiGetFileVersionW         [MSI.@]
3241  */
3242 UINT WINAPI MsiGetFileVersionW( LPCWSTR path, LPWSTR verbuf, LPDWORD verlen,
3243                                 LPWSTR langbuf, LPDWORD langlen )
3244 {
3245     UINT ret;
3246 
3247     TRACE("%s %p %u %p %u\n", debugstr_w(path), verbuf, verlen ? *verlen : 0,
3248           langbuf, langlen ? *langlen : 0);
3249 
3250     if ((verbuf && !verlen) || (langbuf && !langlen))
3251         return ERROR_INVALID_PARAMETER;
3252 
3253     ret = get_file_version( path, verbuf, verlen, langbuf, langlen );
3254     if (ret == ERROR_RESOURCE_DATA_NOT_FOUND && verlen)
3255     {
3256         int len;
3257         WCHAR *version = msi_font_version_from_file( path );
3258         if (!version) return ERROR_FILE_INVALID;
3259         len = strlenW( version );
3260         if (len >= *verlen) ret = ERROR_MORE_DATA;
3261         else if (verbuf)
3262         {
3263             strcpyW( verbuf, version );
3264             ret = ERROR_SUCCESS;
3265         }
3266         *verlen = len;
3267         msi_free( version );
3268     }
3269     return ret;
3270 }
3271 
3272 /***********************************************************************
3273  * MsiGetFeatureUsageW           [MSI.@]
3274  */
3275 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
3276                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
3277 {
3278     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
3279           pdwUseCount, pwDateUsed);
3280     return ERROR_CALL_NOT_IMPLEMENTED;
3281 }
3282 
3283 /***********************************************************************
3284  * MsiGetFeatureUsageA           [MSI.@]
3285  */
3286 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
3287                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
3288 {
3289     LPWSTR prod = NULL, feat = NULL;
3290     UINT ret = ERROR_OUTOFMEMORY;
3291 
3292     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
3293           pdwUseCount, pwDateUsed);
3294 
3295     prod = strdupAtoW( szProduct );
3296     if (szProduct && !prod)
3297         goto end;
3298 
3299     feat = strdupAtoW( szFeature );
3300     if (szFeature && !feat)
3301         goto end;
3302 
3303     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
3304 
3305 end:
3306     msi_free( prod );
3307     msi_free( feat );
3308 
3309     return ret;
3310 }
3311 
3312 /***********************************************************************
3313  * MsiUseFeatureExW           [MSI.@]
3314  */
3315 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
3316                                       DWORD dwInstallMode, DWORD dwReserved )
3317 {
3318     INSTALLSTATE state;
3319 
3320     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
3321           dwInstallMode, dwReserved);
3322 
3323     state = MsiQueryFeatureStateW( szProduct, szFeature );
3324 
3325     if (dwReserved)
3326         return INSTALLSTATE_INVALIDARG;
3327 
3328     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
3329     {
3330         FIXME("mark product %s feature %s as used\n",
3331               debugstr_w(szProduct), debugstr_w(szFeature) );
3332     }
3333 
3334     return state;
3335 }
3336 
3337 /***********************************************************************
3338  * MsiUseFeatureExA           [MSI.@]
3339  */
3340 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
3341                                       DWORD dwInstallMode, DWORD dwReserved )
3342 {
3343     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
3344     LPWSTR prod = NULL, feat = NULL;
3345 
3346     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
3347           dwInstallMode, dwReserved);
3348 
3349     prod = strdupAtoW( szProduct );
3350     if (szProduct && !prod)
3351         goto end;
3352 
3353     feat = strdupAtoW( szFeature );
3354     if (szFeature && !feat)
3355         goto end;
3356 
3357     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
3358 
3359 end:
3360     msi_free( prod );
3361     msi_free( feat );
3362 
3363     return ret;
3364 }
3365 
3366 /***********************************************************************
3367  * MsiUseFeatureW             [MSI.@]
3368  */
3369 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
3370 {
3371     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
3372 }
3373 
3374 /***********************************************************************
3375  * MsiUseFeatureA             [MSI.@]
3376  */
3377 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
3378 {
3379     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
3380 }
3381 
3382 static WCHAR *reg_get_multisz( HKEY hkey, const WCHAR *name )
3383 {
3384     WCHAR *ret;
3385     DWORD len, type;
3386     if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_MULTI_SZ) return NULL;
3387     if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3388     return ret;
3389 }
3390 
3391 static WCHAR *reg_get_sz( HKEY hkey, const WCHAR *name )
3392 {
3393     WCHAR *ret;
3394     DWORD len, type;
3395     if (RegQueryValueExW( hkey, name, NULL, &type, NULL, &len ) || type != REG_SZ) return NULL;
3396     if ((ret = msi_alloc( len ))) RegQueryValueExW( hkey, name, NULL, NULL, (BYTE *)ret, &len );
3397     return ret;
3398 }
3399 
3400 #define BASE85_SIZE 20
3401 
3402 /***********************************************************************
3403  * MSI_ProvideQualifiedComponentEx [internal]
3404  */
3405 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
3406                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
3407                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
3408                 LPDWORD pcchPathBuf)
3409 {
3410     WCHAR product[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
3411     WCHAR *desc;
3412     HKEY hkey;
3413     DWORD size;
3414     UINT ret;
3415     INSTALLSTATE state;
3416 
3417     if (MSIREG_OpenUserComponentsKey( szComponent, &hkey, FALSE )) return ERROR_UNKNOWN_COMPONENT;
3418 
3419     desc = reg_get_multisz( hkey, szQualifier );
3420     RegCloseKey(hkey);
3421     if (!desc) return ERROR_INDEX_ABSENT;
3422 
3423     /* FIXME: handle multiple descriptors */
3424     ret = MsiDecomposeDescriptorW( desc, product, feature, comp, &size );
3425     msi_free( desc );
3426     if (ret != ERROR_SUCCESS) return ret;
3427 
3428     if (!szProduct) szProduct = product;
3429     if (!comp[0])
3430     {
3431         MSIINSTALLCONTEXT ctx;
3432         WCHAR *components;
3433         GUID guid;
3434 
3435         /* use the first component of the feature if the descriptor component is empty */
3436         if ((ret = msi_locate_product( szProduct, &ctx ))) return ret;
3437         if ((ret = MSIREG_OpenUserDataFeaturesKey( szProduct, NULL, ctx, &hkey, FALSE )))
3438         {
3439             return ERROR_FILE_NOT_FOUND;
3440         }
3441         components = reg_get_sz( hkey, feature );
3442         RegCloseKey( hkey );
3443         if (!components) return ERROR_FILE_NOT_FOUND;
3444 
3445         if (strlenW( components ) < BASE85_SIZE || !decode_base85_guid( components, &guid ))
3446         {
3447             msi_free( components );
3448             return ERROR_FILE_NOT_FOUND;
3449         }
3450         msi_free( components );
3451         StringFromGUID2( &guid, comp, sizeof(comp)/sizeof(comp[0]) );
3452     }
3453 
3454     state = MSI_GetComponentPath( szProduct, comp, szAllSid, MSIINSTALLCONTEXT_ALL, lpPathBuf, pcchPathBuf );
3455 
3456     if (state == INSTALLSTATE_MOREDATA) return ERROR_MORE_DATA;
3457     if (state != INSTALLSTATE_LOCAL) return ERROR_FILE_NOT_FOUND;
3458     return ERROR_SUCCESS;
3459 }
3460 
3461 /***********************************************************************
3462  * MsiProvideQualifiedComponentExW [MSI.@]
3463  */
3464 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
3465                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
3466                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
3467                 LPDWORD pcchPathBuf)
3468 {
3469     awstring path;
3470 
3471     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_w(szComponent),
3472           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
3473           Unused1, Unused2, lpPathBuf, pcchPathBuf);
3474 
3475     path.unicode = TRUE;
3476     path.str.w = lpPathBuf;
3477 
3478     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
3479             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
3480 }
3481 
3482 /***********************************************************************
3483  * MsiProvideQualifiedComponentExA [MSI.@]
3484  */
3485 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
3486                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
3487                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
3488                 LPDWORD pcchPathBuf)
3489 {
3490     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
3491     UINT r = ERROR_OUTOFMEMORY;
3492     awstring path;
3493 
3494     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
3495           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
3496           Unused1, Unused2, lpPathBuf, pcchPathBuf);
3497 
3498     szwComponent = strdupAtoW( szComponent );
3499     if (szComponent && !szwComponent)
3500         goto end;
3501 
3502     szwQualifier = strdupAtoW( szQualifier );
3503     if (szQualifier && !szwQualifier)
3504         goto end;
3505 
3506     szwProduct = strdupAtoW( szProduct );
3507     if (szProduct && !szwProduct)
3508         goto end;
3509 
3510     path.unicode = FALSE;
3511     path.str.a = lpPathBuf;
3512 
3513     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
3514                               dwInstallMode, szwProduct, Unused1,
3515                               Unused2, &path, pcchPathBuf);
3516 end:
3517     msi_free(szwProduct);
3518     msi_free(szwComponent);
3519     msi_free(szwQualifier);
3520 
3521     return r;
3522 }
3523 
3524 /***********************************************************************
3525  * MsiProvideQualifiedComponentW [MSI.@]
3526  */
3527 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
3528                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
3529                 LPDWORD pcchPathBuf)
3530 {
3531     return MsiProvideQualifiedComponentExW(szComponent, szQualifier,
3532                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3533 }
3534 
3535 /***********************************************************************
3536  * MsiProvideQualifiedComponentA [MSI.@]
3537  */
3538 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
3539                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
3540                 LPDWORD pcchPathBuf)
3541 {
3542     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
3543                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3544 }
3545 
3546 /***********************************************************************
3547  * MSI_GetUserInfo [internal]
3548  */
3549 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
3550                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
3551                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3552                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
3553 {
3554     WCHAR *user, *org, *serial, squashed_pc[SQUASHED_GUID_SIZE];
3555     USERINFOSTATE state;
3556     HKEY hkey, props;
3557     LPCWSTR orgptr;
3558     UINT r;
3559 
3560     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
3561           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
3562           pcchSerialBuf);
3563 
3564     if (!szProduct || !squash_guid( szProduct, squashed_pc ))
3565         return USERINFOSTATE_INVALIDARG;
3566 
3567     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
3568                               &hkey, FALSE) != ERROR_SUCCESS &&
3569         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3570                               &hkey, FALSE) != ERROR_SUCCESS &&
3571         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
3572                               &hkey, FALSE) != ERROR_SUCCESS)
3573     {
3574         return USERINFOSTATE_UNKNOWN;
3575     }
3576 
3577     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
3578                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
3579         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
3580                                 NULL, &props, FALSE) != ERROR_SUCCESS)
3581     {
3582         RegCloseKey(hkey);
3583         return USERINFOSTATE_ABSENT;
3584     }
3585 
3586     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
3587     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
3588     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
3589     state = USERINFOSTATE_ABSENT;
3590 
3591     RegCloseKey(hkey);
3592     RegCloseKey(props);
3593 
3594     if (user && serial)
3595         state = USERINFOSTATE_PRESENT;
3596 
3597     if (pcchUserNameBuf)
3598     {
3599         if (lpUserNameBuf && !user)
3600         {
3601             (*pcchUserNameBuf)--;
3602             goto done;
3603         }
3604 
3605         r = msi_strcpy_to_awstring(user, -1, lpUserNameBuf, pcchUserNameBuf);
3606         if (r == ERROR_MORE_DATA)
3607         {
3608             state = USERINFOSTATE_MOREDATA;
3609             goto done;
3610         }
3611     }
3612 
3613     if (pcchOrgNameBuf)
3614     {
3615         orgptr = org;
3616         if (!orgptr) orgptr = szEmpty;
3617 
3618         r = msi_strcpy_to_awstring(orgptr, -1, lpOrgNameBuf, pcchOrgNameBuf);
3619         if (r == ERROR_MORE_DATA)
3620         {
3621             state = USERINFOSTATE_MOREDATA;
3622             goto done;
3623         }
3624     }
3625 
3626     if (pcchSerialBuf)
3627     {
3628         if (!serial)
3629         {
3630             (*pcchSerialBuf)--;
3631             goto done;
3632         }
3633 
3634         r = msi_strcpy_to_awstring(serial, -1, lpSerialBuf, pcchSerialBuf);
3635         if (r == ERROR_MORE_DATA)
3636             state = USERINFOSTATE_MOREDATA;
3637     }
3638 
3639 done:
3640     msi_free(user);
3641     msi_free(org);
3642     msi_free(serial);
3643 
3644     return state;
3645 }
3646 
3647 /***********************************************************************
3648  * MsiGetUserInfoW [MSI.@]
3649  */
3650 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3651                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3652                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3653                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3654 {
3655     awstring user, org, serial;
3656 
3657     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3658         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3659         (lpSerialBuf && !pcchSerialBuf))
3660         return USERINFOSTATE_INVALIDARG;
3661 
3662     user.unicode = TRUE;
3663     user.str.w = lpUserNameBuf;
3664     org.unicode = TRUE;
3665     org.str.w = lpOrgNameBuf;
3666     serial.unicode = TRUE;
3667     serial.str.w = lpSerialBuf;
3668 
3669     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3670                             &org, pcchOrgNameBuf,
3671                             &serial, pcchSerialBuf );
3672 }
3673 
3674 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3675                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3676                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3677                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3678 {
3679     awstring user, org, serial;
3680     LPWSTR prod;
3681     UINT r;
3682 
3683     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3684         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3685         (lpSerialBuf && !pcchSerialBuf))
3686         return USERINFOSTATE_INVALIDARG;
3687 
3688     prod = strdupAtoW( szProduct );
3689     if (szProduct && !prod)
3690         return ERROR_OUTOFMEMORY;
3691 
3692     user.unicode = FALSE;
3693     user.str.a = lpUserNameBuf;
3694     org.unicode = FALSE;
3695     org.str.a = lpOrgNameBuf;
3696     serial.unicode = FALSE;
3697     serial.str.a = lpSerialBuf;
3698 
3699     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3700                          &org, pcchOrgNameBuf,
3701                          &serial, pcchSerialBuf );
3702 
3703     msi_free( prod );
3704 
3705     return r;
3706 }
3707 
3708 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3709 {
3710     MSIHANDLE handle;
3711     UINT rc;
3712     MSIPACKAGE *package;
3713     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3714 
3715     TRACE("(%s)\n",debugstr_w(szProduct));
3716 
3717     rc = MsiOpenProductW(szProduct,&handle);
3718     if (rc != ERROR_SUCCESS)
3719         return ERROR_INVALID_PARAMETER;
3720 
3721     /* MsiCollectUserInfo cannot be called from a custom action. */
3722     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3723     if (!package)
3724         return ERROR_CALL_NOT_IMPLEMENTED;
3725 
3726     rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE);
3727     msiobj_release( &package->hdr );
3728 
3729     MsiCloseHandle(handle);
3730 
3731     return rc;
3732 }
3733 
3734 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3735 {
3736     MSIHANDLE handle;
3737     UINT rc;
3738     MSIPACKAGE *package;
3739     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3740 
3741     TRACE("(%s)\n",debugstr_a(szProduct));
3742 
3743     rc = MsiOpenProductA(szProduct,&handle);
3744     if (rc != ERROR_SUCCESS)
3745         return ERROR_INVALID_PARAMETER;
3746 
3747     /* MsiCollectUserInfo cannot be called from a custom action. */
3748     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3749     if (!package)
3750         return ERROR_CALL_NOT_IMPLEMENTED;
3751 
3752     rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE);
3753     msiobj_release( &package->hdr );
3754 
3755     MsiCloseHandle(handle);
3756 
3757     return rc;
3758 }
3759 
3760 /***********************************************************************
3761  * MsiConfigureFeatureA            [MSI.@]
3762  */
3763 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3764 {
3765     LPWSTR prod, feat = NULL;
3766     UINT r = ERROR_OUTOFMEMORY;
3767 
3768     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3769 
3770     prod = strdupAtoW( szProduct );
3771     if (szProduct && !prod)
3772         goto end;
3773 
3774     feat = strdupAtoW( szFeature );
3775     if (szFeature && !feat)
3776         goto end;
3777 
3778     r = MsiConfigureFeatureW(prod, feat, eInstallState);
3779 
3780 end:
3781     msi_free(feat);
3782     msi_free(prod);
3783 
3784     return r;
3785 }
3786 
3787 /***********************************************************************
3788  * MsiConfigureFeatureW            [MSI.@]
3789  */
3790 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
3791 {
3792     MSIPACKAGE *package = NULL;
3793     UINT r;
3794     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
3795     DWORD sz;
3796 
3797     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
3798 
3799     if (!szProduct || !szFeature)
3800         return ERROR_INVALID_PARAMETER;
3801 
3802     switch (eInstallState)
3803     {
3804     case INSTALLSTATE_DEFAULT:
3805         /* FIXME: how do we figure out the default location? */
3806         eInstallState = INSTALLSTATE_LOCAL;
3807         break;
3808     case INSTALLSTATE_LOCAL:
3809     case INSTALLSTATE_SOURCE:
3810     case INSTALLSTATE_ABSENT:
3811     case INSTALLSTATE_ADVERTISED:
3812         break;
3813     default:
3814         return ERROR_INVALID_PARAMETER;
3815     }
3816 
3817     r = MSI_OpenProductW( szProduct, &package );
3818     if (r != ERROR_SUCCESS)
3819         return r;
3820 
3821     sz = sizeof(sourcepath);
3822     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3823                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3824 
3825     sz = sizeof(filename);
3826     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3827                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3828 
3829     lstrcatW( sourcepath, filename );
3830 
3831     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
3832 
3833     r = ACTION_PerformUIAction( package, szCostInitialize, SCRIPT_NONE );
3834     if (r != ERROR_SUCCESS)
3835         goto end;
3836 
3837     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
3838     if (r != ERROR_SUCCESS)
3839         goto end;
3840 
3841     r = MSI_InstallPackage( package, sourcepath, NULL );
3842 
3843 end:
3844     msiobj_release( &package->hdr );
3845 
3846     return r;
3847 }
3848 
3849 /***********************************************************************
3850  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
3851  *
3852  * Notes: undocumented
3853  */
3854 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
3855 {
3856     WCHAR path[MAX_PATH];
3857 
3858     TRACE("%d\n", dwReserved);
3859 
3860     if (dwReserved)
3861     {
3862         FIXME("dwReserved=%d\n", dwReserved);
3863         return ERROR_INVALID_PARAMETER;
3864     }
3865 
3866     if (!GetWindowsDirectoryW(path, MAX_PATH))
3867         return ERROR_FUNCTION_FAILED;
3868 
3869     lstrcatW(path, installerW);
3870 
3871     if (!CreateDirectoryW(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
3872         return ERROR_FUNCTION_FAILED;
3873 
3874     return ERROR_SUCCESS;
3875 }
3876 
3877 /***********************************************************************
3878  * MsiGetShortcutTargetA           [MSI.@]
3879  */
3880 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
3881                                    LPSTR szProductCode, LPSTR szFeatureId,
3882                                    LPSTR szComponentCode )
3883 {
3884     LPWSTR target;
3885     const int len = MAX_FEATURE_CHARS+1;
3886     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
3887     UINT r;
3888 
3889     target = strdupAtoW( szShortcutTarget );
3890     if (szShortcutTarget && !target )
3891         return ERROR_OUTOFMEMORY;
3892     product[0] = 0;
3893     feature[0] = 0;
3894     component[0] = 0;
3895     r = MsiGetShortcutTargetW( target, product, feature, component );
3896     msi_free( target );
3897     if (r == ERROR_SUCCESS)
3898     {
3899         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
3900         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
3901         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
3902     }
3903     return r;
3904 }
3905 
3906 /***********************************************************************
3907  * MsiGetShortcutTargetW           [MSI.@]
3908  */
3909 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
3910                                    LPWSTR szProductCode, LPWSTR szFeatureId,
3911                                    LPWSTR szComponentCode )
3912 {
3913     IShellLinkDataList *dl = NULL;
3914     IPersistFile *pf = NULL;
3915     LPEXP_DARWIN_LINK darwin = NULL;
3916     HRESULT r, init;
3917 
3918     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
3919           szProductCode, szFeatureId, szComponentCode );
3920 
3921     init = CoInitialize(NULL);
3922 
3923     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3924                           &IID_IPersistFile, (LPVOID*) &pf );
3925     if( SUCCEEDED( r ) )
3926     {
3927         r = IPersistFile_Load( pf, szShortcutTarget,
3928                                STGM_READ | STGM_SHARE_DENY_WRITE );
3929         if( SUCCEEDED( r ) )
3930         {
3931             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
3932                                              (LPVOID*) &dl );
3933             if( SUCCEEDED( r ) )
3934             {
3935                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
3936                                                   (LPVOID) &darwin );
3937                 IShellLinkDataList_Release( dl );
3938             }
3939         }
3940         IPersistFile_Release( pf );
3941     }
3942 
3943     if (SUCCEEDED(init))
3944         CoUninitialize();
3945 
3946     TRACE("darwin = %p\n", darwin);
3947 
3948     if (darwin)
3949     {
3950         DWORD sz;
3951         UINT ret;
3952 
3953         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
3954                   szProductCode, szFeatureId, szComponentCode, &sz );
3955         LocalFree( darwin );
3956         return ret;
3957     }
3958 
3959     return ERROR_FUNCTION_FAILED;
3960 }
3961 
3962 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, DWORD dwReinstallMode )
3963 {
3964     static const WCHAR fmtW[] = {'%','s','=','%','s',' ','%','s','=','%','s',0};
3965     MSIPACKAGE *package;
3966     MSIINSTALLCONTEXT context;
3967     UINT r;
3968     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH], reinstallmode[11];
3969     WCHAR *ptr, *cmdline;
3970     DWORD sz;
3971 
3972     TRACE("%s, %s, 0x%08x\n", debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode);
3973 
3974     r = msi_locate_product( szProduct, &context );
3975     if (r != ERROR_SUCCESS)
3976         return r;
3977 
3978     ptr = reinstallmode;
3979 
3980     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
3981         *ptr++ = 'p';
3982     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
3983         *ptr++ = 'o';
3984     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
3985         *ptr++ = 'w';
3986     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
3987         *ptr++ = 'd';
3988     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
3989         *ptr++ = 'c';
3990     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
3991         *ptr++ = 'a';
3992     if (dwReinstallMode & REINSTALLMODE_USERDATA)
3993         *ptr++ = 'u';
3994     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
3995         *ptr++ = 'm';
3996     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
3997         *ptr++ = 's';
3998     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3999         *ptr++ = 'v';
4000     *ptr = 0;
4001 
4002     sz = sizeof(sourcepath);
4003     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
4004                            INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz );
4005     sz = sizeof(filename);
4006     MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT,
4007                            INSTALLPROPERTY_PACKAGENAMEW, filename, &sz );
4008     strcatW( sourcepath, filename );
4009 
4010     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
4011         r = MSI_OpenPackageW( sourcepath, &package );
4012     else
4013         r = MSI_OpenProductW( szProduct, &package );
4014 
4015     if (r != ERROR_SUCCESS)
4016         return r;
4017 
4018     sz = (strlenW( fmtW ) + strlenW( szReinstallMode ) + strlenW( reinstallmode )) * sizeof(WCHAR);
4019     sz += (strlenW( szReinstall ) + strlenW( szFeature )) * sizeof(WCHAR);
4020     if (!(cmdline = msi_alloc( sz )))
4021     {
4022         msiobj_release( &package->hdr );
4023         return ERROR_OUTOFMEMORY;
4024     }
4025     sprintfW( cmdline, fmtW, szReinstallMode, reinstallmode, szReinstall, szFeature );
4026 
4027     r = MSI_InstallPackage( package, sourcepath, cmdline );
4028     msiobj_release( &package->hdr );
4029     msi_free( cmdline );
4030 
4031     return r;
4032 }
4033 
4034 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
4035                                   DWORD dwReinstallMode )
4036 {
4037     LPWSTR wszProduct;
4038     LPWSTR wszFeature;
4039     UINT rc;
4040 
4041     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
4042                            dwReinstallMode);
4043 
4044     wszProduct = strdupAtoW(szProduct);
4045     wszFeature = strdupAtoW(szFeature);
4046 
4047     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
4048 
4049     msi_free(wszProduct);
4050     msi_free(wszFeature);
4051     return rc;
4052 }
4053 
4054 typedef struct
4055 {
4056     unsigned int i[2];
4057     unsigned int buf[4];
4058     unsigned char in[64];
4059     unsigned char digest[16];
4060 } MD5_CTX;
4061 
4062 extern VOID WINAPI MD5Init( MD5_CTX *);
4063 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
4064 extern VOID WINAPI MD5Final( MD5_CTX *);
4065 
4066 UINT msi_get_filehash( const WCHAR *path, MSIFILEHASHINFO *hash )
4067 {
4068     HANDLE handle, mapping;
4069     void *p;
4070     DWORD length;
4071     UINT r = ERROR_FUNCTION_FAILED;
4072 
4073     handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
4074     if (handle == INVALID_HANDLE_VALUE)
4075     {
4076         WARN("can't open file %u\n", GetLastError());
4077         return ERROR_FILE_NOT_FOUND;
4078     }
4079     if ((length = GetFileSize( handle, NULL )))
4080     {
4081         if ((mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL )))
4082         {
4083             if ((p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length )))
4084             {
4085                 MD5_CTX ctx;
4086 
4087                 MD5Init( &ctx );
4088                 MD5Update( &ctx, p, length );
4089                 MD5Final( &ctx );
4090                 UnmapViewOfFile( p );
4091 
4092                 memcpy( hash->dwData, ctx.digest, sizeof(hash->dwData) );
4093                 r = ERROR_SUCCESS;
4094             }
4095             CloseHandle( mapping );
4096         }
4097     }
4098     else
4099     {
4100         /* Empty file -> set hash to 0 */
4101         memset( hash->dwData, 0, sizeof(hash->dwData) );
4102         r = ERROR_SUCCESS;
4103     }
4104 
4105     CloseHandle( handle );
4106     return r;
4107 }
4108 
4109 /***********************************************************************
4110  * MsiGetFileHashW            [MSI.@]
4111  */
4112 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
4113                              PMSIFILEHASHINFO pHash )
4114 {
4115     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
4116 
4117     if (!szFilePath)
4118         return ERROR_INVALID_PARAMETER;
4119 
4120     if (!*szFilePath)
4121         return ERROR_PATH_NOT_FOUND;
4122 
4123     if (dwOptions)
4124         return ERROR_INVALID_PARAMETER;
4125     if (!pHash)
4126         return ERROR_INVALID_PARAMETER;
4127     if (pHash->dwFileHashInfoSize < sizeof *pHash)
4128         return ERROR_INVALID_PARAMETER;
4129 
4130     return msi_get_filehash( szFilePath, pHash );
4131 }
4132 
4133 /***********************************************************************
4134  * MsiGetFileHashA            [MSI.@]
4135  */
4136 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
4137                              PMSIFILEHASHINFO pHash )
4138 {
4139     LPWSTR file;
4140     UINT r;
4141 
4142     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
4143 
4144     file = strdupAtoW( szFilePath );
4145     if (szFilePath && !file)
4146         return ERROR_OUTOFMEMORY;
4147 
4148     r = MsiGetFileHashW( file, dwOptions, pHash );
4149     msi_free( file );
4150     return r;
4151 }
4152 
4153 /***********************************************************************
4154  * MsiAdvertiseScriptW        [MSI.@]
4155  */
4156 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
4157                                  PHKEY phRegData, BOOL fRemoveItems )
4158 {
4159     FIXME("%s %08x %p %d\n",
4160           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
4161     return ERROR_CALL_NOT_IMPLEMENTED;
4162 }
4163 
4164 /***********************************************************************
4165  * MsiAdvertiseScriptA        [MSI.@]
4166  */
4167 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
4168                                  PHKEY phRegData, BOOL fRemoveItems )
4169 {
4170     FIXME("%s %08x %p %d\n",
4171           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
4172     return ERROR_CALL_NOT_IMPLEMENTED;
4173 }
4174 
4175 /***********************************************************************
4176  * MsiIsProductElevatedW        [MSI.@]
4177  */
4178 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
4179 {
4180     FIXME("%s %p - stub\n",
4181           debugstr_w( szProduct ), pfElevated );
4182     *pfElevated = TRUE;
4183     return ERROR_SUCCESS;
4184 }
4185 
4186 /***********************************************************************
4187  * MsiIsProductElevatedA        [MSI.@]
4188  */
4189 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
4190 {
4191     FIXME("%s %p - stub\n",
4192           debugstr_a( szProduct ), pfElevated );
4193     *pfElevated = TRUE;
4194     return ERROR_SUCCESS;
4195 }
4196 
4197 /***********************************************************************
4198  * MsiSetExternalUIRecord     [MSI.@]
4199  */
4200 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler,
4201                                     DWORD filter, LPVOID context,
4202                                     PINSTALLUI_HANDLER_RECORD prev )
4203 {
4204     TRACE("%p %08x %p %p\n", handler, filter, context, prev);
4205 
4206     if (prev)
4207         *prev = gUIHandlerRecord;
4208 
4209     gUIHandlerRecord = handler;
4210     gUIFilterRecord  = filter;
4211     gUIContextRecord = context;
4212 
4213     return ERROR_SUCCESS;
4214 }
4215 
4216 /***********************************************************************
4217  * MsiInstallMissingComponentA     [MSI.@]
4218  */
4219 UINT WINAPI MsiInstallMissingComponentA( LPCSTR product, LPCSTR component, INSTALLSTATE state )
4220 {
4221     UINT r;
4222     WCHAR *productW = NULL, *componentW = NULL;
4223 
4224     TRACE("%s, %s, %d\n", debugstr_a(product), debugstr_a(component), state);
4225 
4226     if (product && !(productW = strdupAtoW( product )))
4227         return ERROR_OUTOFMEMORY;
4228 
4229     if (component && !(componentW = strdupAtoW( component )))
4230     {
4231         msi_free( productW );
4232         return ERROR_OUTOFMEMORY;
4233     }
4234 
4235     r = MsiInstallMissingComponentW( productW, componentW, state );
4236     msi_free( productW );
4237     msi_free( componentW );
4238     return r;
4239 }
4240 
4241 /***********************************************************************
4242  * MsiInstallMissingComponentW     [MSI.@]
4243  */
4244 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
4245 {
4246     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
4247     return ERROR_SUCCESS;
4248 }
4249 
4250 UINT WINAPI MsiProvideComponentA( LPCSTR product, LPCSTR feature, LPCSTR component, DWORD mode, LPSTR buf, LPDWORD buflen )
4251 {
4252     WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL;
4253     UINT r = ERROR_OUTOFMEMORY;
4254     DWORD lenW = 0;
4255     int len;
4256 
4257     TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode, buf, buflen);
4258 
4259     if (product && !(productW = strdupAtoW( product ))) goto done;
4260     if (feature && !(featureW = strdupAtoW( feature ))) goto done;
4261     if (component && !(componentW = strdupAtoW( component ))) goto done;
4262 
4263     r = MsiProvideComponentW( productW, featureW, componentW, mode, NULL, &lenW );
4264     if (r != ERROR_SUCCESS)
4265         goto done;
4266 
4267     if (!(bufW = msi_alloc( ++lenW * sizeof(WCHAR) )))
4268     {
4269         r = ERROR_OUTOFMEMORY;
4270         goto done;
4271     }
4272 
4273     r = MsiProvideComponentW( productW, featureW, componentW, mode, bufW, &lenW );
4274     if (r != ERROR_SUCCESS)
4275         goto done;
4276 
4277     len = WideCharToMultiByte( CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
4278     if (buf)
4279     {
4280         if (len > *buflen)
4281             r = ERROR_MORE_DATA;
4282         else
4283             WideCharToMultiByte( CP_ACP, 0, bufW, -1, buf, *buflen, NULL, NULL );
4284     }
4285 
4286     *buflen = len - 1;
4287 
4288 done:
4289     msi_free( productW );
4290     msi_free( featureW );
4291     msi_free( componentW );
4292     msi_free( bufW );
4293     return r;
4294 }
4295 
4296 UINT WINAPI MsiProvideComponentW( LPCWSTR product, LPCWSTR feature, LPCWSTR component, DWORD mode, LPWSTR buf, LPDWORD buflen )
4297 {
4298     INSTALLSTATE state;
4299 
4300     TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_w(product), debugstr_w(component), debugstr_w(feature), mode, buf, buflen);
4301 
4302     state = MsiQueryFeatureStateW( product, feature );
4303     TRACE("feature state: %d\n", state);
4304     switch (mode)
4305     {
4306     case INSTALLMODE_NODETECTION:
4307         break;
4308 
4309     default:
4310         FIXME("mode %x not implemented\n", mode);
4311         return ERROR_INSTALL_FAILURE;
4312     }
4313 
4314     state = MsiGetComponentPathW( product, component, buf, buflen );
4315     TRACE("component state: %d\n", state);
4316     switch (state)
4317     {
4318     case INSTALLSTATE_INVALIDARG:
4319         return ERROR_INVALID_PARAMETER;
4320 
4321     case INSTALLSTATE_MOREDATA:
4322         return ERROR_MORE_DATA;
4323 
4324     case INSTALLSTATE_ADVERTISED:
4325     case INSTALLSTATE_LOCAL:
4326     case INSTALLSTATE_SOURCE:
4327         MsiUseFeatureW( product, feature );
4328         return ERROR_SUCCESS;
4329 
4330     default:
4331         TRACE("MsiGetComponentPathW returned %d\n", state);
4332         return ERROR_INSTALL_FAILURE;
4333     }
4334 }
4335 
4336 /***********************************************************************
4337  * MsiBeginTransactionA     [MSI.@]
4338  */
4339 UINT WINAPI MsiBeginTransactionA( LPCSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
4340 {
4341     WCHAR *nameW;
4342     UINT r;
4343 
4344     FIXME("%s %u %p %p\n", debugstr_a(name), attrs, id, event);
4345 
4346     nameW = strdupAtoW( name );
4347     if (name && !nameW)
4348         return ERROR_OUTOFMEMORY;
4349 
4350     r = MsiBeginTransactionW( nameW, attrs, id, event );
4351     msi_free( nameW );
4352     return r;
4353 }
4354 
4355 /***********************************************************************
4356  * MsiBeginTransactionW     [MSI.@]
4357  */
4358 UINT WINAPI MsiBeginTransactionW( LPCWSTR name, DWORD attrs, MSIHANDLE *id, HANDLE *event )
4359 {
4360     FIXME("%s %u %p %p\n", debugstr_w(name), attrs, id, event);
4361 
4362     *id = (MSIHANDLE)0xdeadbeef;
4363     *event = (HANDLE)0xdeadbeef;
4364 
4365     return ERROR_SUCCESS;
4366 }
4367 
4368 /***********************************************************************
4369  * MsiJoinTransaction     [MSI.@]
4370  */
4371 UINT WINAPI MsiJoinTransaction( MSIHANDLE handle, DWORD attrs, HANDLE *event )
4372 {
4373     FIXME("%u %08x %p\n", handle, attrs, event);
4374 
4375     *event = (HANDLE)0xdeadbeef;
4376     return ERROR_SUCCESS;
4377 }
4378 
4379 /***********************************************************************
4380  * MsiEndTransaction     [MSI.@]
4381  */
4382 UINT WINAPI MsiEndTransaction( DWORD state )
4383 {
4384     FIXME("%u\n", state);
4385     return ERROR_SUCCESS;
4386 }
4387 
4388 UINT WINAPI Migrate10CachedPackagesW(void* a, void* b, void* c, DWORD d)
4389 {
4390     FIXME("%p,%p,%p,%08x\n", a, b, c, d);
4391     return ERROR_SUCCESS;
4392 }
4393 
4394 /***********************************************************************
4395  * MsiRemovePatchesA     [MSI.@]
4396  */
4397 UINT WINAPI MsiRemovePatchesA(LPCSTR patchlist, LPCSTR product, INSTALLTYPE type, LPCSTR propertylist)
4398 {
4399     FIXME("(%s %s %d %s\n", debugstr_a(patchlist), debugstr_a(product), type, debugstr_a(propertylist));
4400     return ERROR_SUCCESS;
4401 }
4402 
4403 /***********************************************************************
4404  * MsiRemovePatchesW    [MSI.@]
4405  */
4406 UINT WINAPI MsiRemovePatchesW(LPCWSTR patchlist, LPCWSTR product, INSTALLTYPE type, LPCWSTR propertylist)
4407 {
4408     FIXME("(%s %s %d %s\n", debugstr_w(patchlist), debugstr_w(product), type, debugstr_w(propertylist));
4409     return ERROR_SUCCESS;
4410 }
4411