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