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