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