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