msi: Add tests for registering and unregistering class info.
[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 MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
2153                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
2154                 LPDWORD pcchPathBuf )
2155 {
2156     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
2157           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2158           pcchPathBuf);
2159     return ERROR_CALL_NOT_IMPLEMENTED;
2160 }
2161
2162 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
2163                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
2164                 LPDWORD pcchPathBuf )
2165 {
2166     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
2167           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2168           pcchPathBuf);
2169     return ERROR_CALL_NOT_IMPLEMENTED;
2170 }
2171
2172 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2173                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2174 {
2175     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2176     return ERROR_CALL_NOT_IMPLEMENTED;
2177 }
2178
2179 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2180                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2181 {
2182     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2183     return ERROR_CALL_NOT_IMPLEMENTED;
2184 }
2185
2186 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
2187                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
2188                 LPDWORD pcbHashData)
2189 {
2190     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
2191           ppcCertContext, pbHashData, pcbHashData);
2192     return ERROR_CALL_NOT_IMPLEMENTED;
2193 }
2194
2195 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
2196                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
2197                 LPDWORD pcbHashData)
2198 {
2199     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
2200           ppcCertContext, pbHashData, pcbHashData);
2201     return ERROR_CALL_NOT_IMPLEMENTED;
2202 }
2203
2204 /******************************************************************
2205  * MsiGetProductPropertyA      [MSI.@]
2206  */
2207 UINT WINAPI MsiGetProductPropertyA(MSIHANDLE hProduct, LPCSTR szProperty,
2208                                    LPSTR szValue, LPDWORD pccbValue)
2209 {
2210     LPWSTR prop = NULL, val = NULL;
2211     DWORD len;
2212     UINT r;
2213
2214     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_a(szProperty),
2215           szValue, pccbValue);
2216
2217     if (szValue && !pccbValue)
2218         return ERROR_INVALID_PARAMETER;
2219
2220     if (szProperty) prop = strdupAtoW(szProperty);
2221
2222     len = 0;
2223     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2224     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2225         goto done;
2226
2227     if (r == ERROR_SUCCESS)
2228     {
2229         if (szValue) *szValue = '\0';
2230         if (pccbValue) *pccbValue = 0;
2231         goto done;
2232     }
2233
2234     val = msi_alloc(++len * sizeof(WCHAR));
2235     if (!val)
2236     {
2237         r = ERROR_OUTOFMEMORY;
2238         goto done;
2239     }
2240
2241     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2242     if (r != ERROR_SUCCESS)
2243         goto done;
2244
2245     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2246
2247     if (szValue)
2248         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2249                             *pccbValue, NULL, NULL);
2250
2251     if (pccbValue)
2252     {
2253         if (len > *pccbValue)
2254             r = ERROR_MORE_DATA;
2255
2256         *pccbValue = len - 1;
2257     }
2258
2259 done:
2260     msi_free(prop);
2261     msi_free(val);
2262
2263     return r;
2264 }
2265
2266 /******************************************************************
2267  * MsiGetProductPropertyW      [MSI.@]
2268  */
2269 UINT WINAPI MsiGetProductPropertyW(MSIHANDLE hProduct, LPCWSTR szProperty,
2270                                    LPWSTR szValue, LPDWORD pccbValue)
2271 {
2272     MSIPACKAGE *package;
2273     MSIQUERY *view = NULL;
2274     MSIRECORD *rec = NULL;
2275     LPCWSTR val;
2276     UINT r;
2277
2278     static const WCHAR query[] = {
2279        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2280        '`','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2281        '`','P','r','o','p','e','r','t','y','`','=','\'','%','s','\'',0};
2282
2283     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_w(szProperty),
2284           szValue, pccbValue);
2285
2286     if (!szProperty)
2287         return ERROR_INVALID_PARAMETER;
2288
2289     if (szValue && !pccbValue)
2290         return ERROR_INVALID_PARAMETER;
2291
2292     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2293     if (!package)
2294         return ERROR_INVALID_HANDLE;
2295
2296     r = MSI_OpenQuery(package->db, &view, query, szProperty);
2297     if (r != ERROR_SUCCESS)
2298         goto done;
2299
2300     r = MSI_ViewExecute(view, 0);
2301     if (r != ERROR_SUCCESS)
2302         goto done;
2303
2304     r = MSI_ViewFetch(view, &rec);
2305     if (r != ERROR_SUCCESS)
2306         goto done;
2307
2308     val = MSI_RecordGetString(rec, 2);
2309     if (!val)
2310         goto done;
2311
2312     if (lstrlenW(val) >= *pccbValue)
2313     {
2314         lstrcpynW(szValue, val, *pccbValue);
2315         *pccbValue = lstrlenW(val);
2316         r = ERROR_MORE_DATA;
2317     }
2318     else
2319     {
2320         lstrcpyW(szValue, val);
2321         *pccbValue = lstrlenW(val);
2322         r = ERROR_SUCCESS;
2323     }
2324
2325 done:
2326     if (view)
2327     {
2328         MSI_ViewClose(view);
2329         msiobj_release(&view->hdr);
2330         if (rec) msiobj_release(&rec->hdr);
2331     }
2332
2333     if (!rec)
2334     {
2335         if (szValue) *szValue = '\0';
2336         if (pccbValue) *pccbValue = 0;
2337         r = ERROR_SUCCESS;
2338     }
2339
2340     return r;
2341 }
2342
2343 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2344 {
2345     UINT r;
2346     LPWSTR szPack = NULL;
2347
2348     TRACE("%s\n", debugstr_a(szPackage) );
2349
2350     if( szPackage )
2351     {
2352         szPack = strdupAtoW( szPackage );
2353         if( !szPack )
2354             return ERROR_OUTOFMEMORY;
2355     }
2356
2357     r = MsiVerifyPackageW( szPack );
2358
2359     msi_free( szPack );
2360
2361     return r;
2362 }
2363
2364 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2365 {
2366     MSIHANDLE handle;
2367     UINT r;
2368
2369     TRACE("%s\n", debugstr_w(szPackage) );
2370
2371     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2372     MsiCloseHandle( handle );
2373
2374     return r;
2375 }
2376
2377 static INSTALLSTATE MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
2378                                          awstring* lpPathBuf, LPDWORD pcchBuf)
2379 {
2380     WCHAR squished_pc[GUID_SIZE];
2381     WCHAR squished_comp[GUID_SIZE];
2382     HKEY hkey;
2383     LPWSTR path = NULL;
2384     INSTALLSTATE state;
2385     DWORD version;
2386
2387     static const WCHAR wininstaller[] = {
2388         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
2389
2390     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
2391            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
2392
2393     if (!szProduct || !szComponent)
2394         return INSTALLSTATE_INVALIDARG;
2395
2396     if (lpPathBuf->str.w && !pcchBuf)
2397         return INSTALLSTATE_INVALIDARG;
2398
2399     if (!squash_guid(szProduct, squished_pc) ||
2400         !squash_guid(szComponent, squished_comp))
2401         return INSTALLSTATE_INVALIDARG;
2402
2403     state = INSTALLSTATE_UNKNOWN;
2404
2405     if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
2406         MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
2407     {
2408         path = msi_reg_get_val_str(hkey, squished_pc);
2409         RegCloseKey(hkey);
2410
2411         state = INSTALLSTATE_ABSENT;
2412
2413         if ((MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL,
2414                                      &hkey, FALSE) == ERROR_SUCCESS ||
2415             MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2416                                           NULL, &hkey, FALSE) == ERROR_SUCCESS) &&
2417             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
2418             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2419         {
2420             RegCloseKey(hkey);
2421             state = INSTALLSTATE_LOCAL;
2422         }
2423     }
2424
2425     if (state != INSTALLSTATE_LOCAL &&
2426         (MSIREG_OpenProductKey(szProduct, NULL,
2427                                MSIINSTALLCONTEXT_USERUNMANAGED,
2428                                &hkey, FALSE) == ERROR_SUCCESS ||
2429          MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2430                                &hkey, FALSE) == ERROR_SUCCESS))
2431     {
2432         RegCloseKey(hkey);
2433
2434         if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
2435             MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
2436         {
2437             msi_free(path);
2438             path = msi_reg_get_val_str(hkey, squished_pc);
2439             RegCloseKey(hkey);
2440
2441             state = INSTALLSTATE_ABSENT;
2442
2443             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2444                 state = INSTALLSTATE_LOCAL;
2445         }
2446     }
2447
2448     if (!path)
2449         return INSTALLSTATE_UNKNOWN;
2450
2451     if (state == INSTALLSTATE_LOCAL && !*path)
2452         state = INSTALLSTATE_NOTUSED;
2453
2454     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
2455     msi_free(path);
2456     return state;
2457 }
2458
2459 /******************************************************************
2460  * MsiGetComponentPathW      [MSI.@]
2461  */
2462 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
2463                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
2464 {
2465     awstring path;
2466
2467     path.unicode = TRUE;
2468     path.str.w = lpPathBuf;
2469
2470     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
2471 }
2472
2473 /******************************************************************
2474  * MsiGetComponentPathA      [MSI.@]
2475  */
2476 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
2477                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
2478 {
2479     LPWSTR szwProduct, szwComponent = NULL;
2480     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2481     awstring path;
2482
2483     szwProduct = strdupAtoW( szProduct );
2484     if( szProduct && !szwProduct)
2485         goto end;
2486
2487     szwComponent = strdupAtoW( szComponent );
2488     if( szComponent && !szwComponent )
2489         goto end;
2490
2491     path.unicode = FALSE;
2492     path.str.a = lpPathBuf;
2493
2494     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
2495
2496 end:
2497     msi_free( szwProduct );
2498     msi_free( szwComponent );
2499
2500     return r;
2501 }
2502
2503 /******************************************************************
2504  * MsiQueryFeatureStateA      [MSI.@]
2505  */
2506 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
2507 {
2508     LPWSTR szwProduct = NULL, szwFeature= NULL;
2509     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
2510
2511     szwProduct = strdupAtoW( szProduct );
2512     if ( szProduct && !szwProduct )
2513         goto end;
2514
2515     szwFeature = strdupAtoW( szFeature );
2516     if ( szFeature && !szwFeature )
2517         goto end;
2518
2519     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
2520
2521 end:
2522     msi_free( szwProduct);
2523     msi_free( szwFeature);
2524
2525     return rc;
2526 }
2527
2528 /******************************************************************
2529  * MsiQueryFeatureStateW      [MSI.@]
2530  *
2531  * Checks the state of a feature
2532  *
2533  * PARAMS
2534  *   szProduct     [I]  Product's GUID string
2535  *   szFeature     [I]  Feature's GUID string
2536  *
2537  * RETURNS
2538  *   INSTALLSTATE_LOCAL        Feature is installed and usable
2539  *   INSTALLSTATE_ABSENT       Feature is absent
2540  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
2541  *   INSTALLSTATE_UNKNOWN      An error occurred
2542  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
2543  *
2544  */
2545 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
2546 {
2547     WCHAR squishProduct[33], comp[GUID_SIZE];
2548     GUID guid;
2549     LPWSTR components, p, parent_feature, path;
2550     UINT rc;
2551     HKEY hkey;
2552     INSTALLSTATE r;
2553     BOOL missing = FALSE;
2554     BOOL machine = FALSE;
2555     BOOL source = FALSE;
2556
2557     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
2558
2559     if (!szProduct || !szFeature)
2560         return INSTALLSTATE_INVALIDARG;
2561
2562     if (!squash_guid( szProduct, squishProduct ))
2563         return INSTALLSTATE_INVALIDARG;
2564
2565     if (MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERMANAGED,
2566                                &hkey, FALSE) != ERROR_SUCCESS &&
2567         MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2568                                &hkey, FALSE) != ERROR_SUCCESS)
2569     {
2570         rc = MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_MACHINE,
2571                                     &hkey, FALSE);
2572         if (rc != ERROR_SUCCESS)
2573             return INSTALLSTATE_UNKNOWN;
2574
2575         machine = TRUE;
2576     }
2577
2578     parent_feature = msi_reg_get_val_str( hkey, szFeature );
2579     RegCloseKey(hkey);
2580
2581     if (!parent_feature)
2582         return INSTALLSTATE_UNKNOWN;
2583
2584     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2585     msi_free(parent_feature);
2586     if (r == INSTALLSTATE_ABSENT)
2587         return r;
2588
2589     if (machine)
2590         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
2591                                             MSIINSTALLCONTEXT_MACHINE,
2592                                             &hkey, FALSE);
2593     else
2594         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
2595                                             MSIINSTALLCONTEXT_USERUNMANAGED,
2596                                             &hkey, FALSE);
2597
2598     if (rc != ERROR_SUCCESS)
2599         return INSTALLSTATE_ADVERTISED;
2600
2601     components = msi_reg_get_val_str( hkey, szFeature );
2602     RegCloseKey(hkey);
2603
2604     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
2605
2606     if (!components)
2607         return INSTALLSTATE_ADVERTISED;
2608
2609     for( p = components; *p && *p != 2 ; p += 20)
2610     {
2611         if (!decode_base85_guid( p, &guid ))
2612         {
2613             if (p != components)
2614                 break;
2615
2616             msi_free(components);
2617             return INSTALLSTATE_BADCONFIG;
2618         }
2619
2620         StringFromGUID2(&guid, comp, GUID_SIZE);
2621
2622         if (machine)
2623             rc = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
2624         else
2625             rc = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
2626
2627         if (rc != ERROR_SUCCESS)
2628         {
2629             msi_free(components);
2630             return INSTALLSTATE_ADVERTISED;
2631         }
2632
2633         path = msi_reg_get_val_str(hkey, squishProduct);
2634         if (!path)
2635             missing = TRUE;
2636         else if (lstrlenW(path) > 2 &&
2637                  path[0] >= '0' && path[0] <= '9' &&
2638                  path[1] >= '0' && path[1] <= '9')
2639         {
2640             source = TRUE;
2641         }
2642
2643         msi_free(path);
2644     }
2645
2646     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
2647     msi_free(components);
2648
2649     if (missing)
2650         return INSTALLSTATE_ADVERTISED;
2651
2652     if (source)
2653         return INSTALLSTATE_SOURCE;
2654
2655     return INSTALLSTATE_LOCAL;
2656 }
2657
2658 /******************************************************************
2659  * MsiGetFileVersionA         [MSI.@]
2660  */
2661 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
2662                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
2663 {
2664     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
2665     UINT ret = ERROR_OUTOFMEMORY;
2666
2667     if ((lpVersionBuf && !pcchVersionBuf) ||
2668         (lpLangBuf && !pcchLangBuf))
2669         return ERROR_INVALID_PARAMETER;
2670
2671     if( szFilePath )
2672     {
2673         szwFilePath = strdupAtoW( szFilePath );
2674         if( !szwFilePath )
2675             goto end;
2676     }
2677
2678     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
2679     {
2680         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
2681         if( !lpwVersionBuff )
2682             goto end;
2683     }
2684
2685     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
2686     {
2687         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
2688         if( !lpwLangBuff )
2689             goto end;
2690     }
2691
2692     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
2693                              lpwLangBuff, pcchLangBuf);
2694
2695     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
2696         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
2697                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
2698     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
2699         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
2700                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
2701
2702 end:
2703     msi_free(szwFilePath);
2704     msi_free(lpwVersionBuff);
2705     msi_free(lpwLangBuff);
2706
2707     return ret;
2708 }
2709
2710 /******************************************************************
2711  * MsiGetFileVersionW         [MSI.@]
2712  */
2713 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
2714                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
2715 {
2716     static const WCHAR szVersionResource[] = {'\\',0};
2717     static const WCHAR szVersionFormat[] = {
2718         '%','d','.','%','d','.','%','d','.','%','d',0};
2719     static const WCHAR szLangResource[] = {
2720         '\\','V','a','r','F','i','l','e','I','n','f','o','\\',
2721         'T','r','a','n','s','l','a','t','i','o','n',0};
2722     static const WCHAR szLangFormat[] = {'%','d',0};
2723     UINT ret = 0;
2724     DWORD dwVerLen, gle;
2725     LPVOID lpVer = NULL;
2726     VS_FIXEDFILEINFO *ffi;
2727     USHORT *lang;
2728     UINT puLen;
2729     WCHAR tmp[32];
2730
2731     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
2732           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
2733           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
2734
2735     if ((lpVersionBuf && !pcchVersionBuf) ||
2736         (lpLangBuf && !pcchLangBuf))
2737         return ERROR_INVALID_PARAMETER;
2738
2739     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
2740     if( !dwVerLen )
2741     {
2742         gle = GetLastError();
2743         if (gle == ERROR_BAD_PATHNAME)
2744             return ERROR_FILE_NOT_FOUND;
2745         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
2746             return ERROR_FILE_INVALID;
2747
2748         return gle;
2749     }
2750
2751     lpVer = msi_alloc(dwVerLen);
2752     if( !lpVer )
2753     {
2754         ret = ERROR_OUTOFMEMORY;
2755         goto end;
2756     }
2757
2758     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
2759     {
2760         ret = GetLastError();
2761         goto end;
2762     }
2763
2764     if (pcchVersionBuf)
2765     {
2766         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
2767             (puLen > 0) )
2768         {
2769             wsprintfW(tmp, szVersionFormat,
2770                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
2771                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
2772             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
2773
2774             if (strlenW(tmp) >= *pcchVersionBuf)
2775                 ret = ERROR_MORE_DATA;
2776
2777             *pcchVersionBuf = lstrlenW(tmp);
2778         }
2779         else
2780         {
2781             if (lpVersionBuf) *lpVersionBuf = 0;
2782             *pcchVersionBuf = 0;
2783         }
2784     }
2785
2786     if (pcchLangBuf)
2787     {
2788         if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
2789             (puLen > 0))
2790         {
2791             wsprintfW(tmp, szLangFormat, *lang);
2792             if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
2793
2794             if (strlenW(tmp) >= *pcchLangBuf)
2795                 ret = ERROR_MORE_DATA;
2796
2797             *pcchLangBuf = lstrlenW(tmp);
2798         }
2799         else
2800         {
2801             if (lpLangBuf) *lpLangBuf = 0;
2802             *pcchLangBuf = 0;
2803         }
2804     }
2805
2806 end:
2807     msi_free(lpVer);
2808     return ret;
2809 }
2810
2811 /***********************************************************************
2812  * MsiGetFeatureUsageW           [MSI.@]
2813  */
2814 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
2815                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2816 {
2817     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
2818           pdwUseCount, pwDateUsed);
2819     return ERROR_CALL_NOT_IMPLEMENTED;
2820 }
2821
2822 /***********************************************************************
2823  * MsiGetFeatureUsageA           [MSI.@]
2824  */
2825 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
2826                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2827 {
2828     LPWSTR prod = NULL, feat = NULL;
2829     UINT ret = ERROR_OUTOFMEMORY;
2830
2831     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
2832           pdwUseCount, pwDateUsed);
2833
2834     prod = strdupAtoW( szProduct );
2835     if (szProduct && !prod)
2836         goto end;
2837
2838     feat = strdupAtoW( szFeature );
2839     if (szFeature && !feat)
2840         goto end;
2841
2842     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
2843
2844 end:
2845     msi_free( prod );
2846     msi_free( feat );
2847
2848     return ret;
2849 }
2850
2851 /***********************************************************************
2852  * MsiUseFeatureExW           [MSI.@]
2853  */
2854 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
2855                                       DWORD dwInstallMode, DWORD dwReserved )
2856 {
2857     INSTALLSTATE state;
2858
2859     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2860           dwInstallMode, dwReserved);
2861
2862     state = MsiQueryFeatureStateW( szProduct, szFeature );
2863
2864     if (dwReserved)
2865         return INSTALLSTATE_INVALIDARG;
2866
2867     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
2868     {
2869         FIXME("mark product %s feature %s as used\n",
2870               debugstr_w(szProduct), debugstr_w(szFeature) );
2871     }
2872
2873     return state;
2874 }
2875
2876 /***********************************************************************
2877  * MsiUseFeatureExA           [MSI.@]
2878  */
2879 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
2880                                       DWORD dwInstallMode, DWORD dwReserved )
2881 {
2882     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
2883     LPWSTR prod = NULL, feat = NULL;
2884
2885     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2886           dwInstallMode, dwReserved);
2887
2888     prod = strdupAtoW( szProduct );
2889     if (szProduct && !prod)
2890         goto end;
2891
2892     feat = strdupAtoW( szFeature );
2893     if (szFeature && !feat)
2894         goto end;
2895
2896     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
2897
2898 end:
2899     msi_free( prod );
2900     msi_free( feat );
2901
2902     return ret;
2903 }
2904
2905 /***********************************************************************
2906  * MsiUseFeatureW             [MSI.@]
2907  */
2908 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
2909 {
2910     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
2911 }
2912
2913 /***********************************************************************
2914  * MsiUseFeatureA             [MSI.@]
2915  */
2916 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
2917 {
2918     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
2919 }
2920
2921 /***********************************************************************
2922  * MSI_ProvideQualifiedComponentEx [internal]
2923  */
2924 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
2925                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2926                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
2927                 LPDWORD pcchPathBuf)
2928 {
2929     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
2930           feature[MAX_FEATURE_CHARS+1];
2931     LPWSTR info;
2932     HKEY hkey;
2933     DWORD sz;
2934     UINT rc;
2935
2936     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
2937           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
2938           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2939
2940     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
2941     if (rc != ERROR_SUCCESS)
2942         return ERROR_INDEX_ABSENT;
2943
2944     info = msi_reg_get_val_str( hkey, szQualifier );
2945     RegCloseKey(hkey);
2946
2947     if (!info)
2948         return ERROR_INDEX_ABSENT;
2949
2950     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
2951
2952     if (!szProduct)
2953         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
2954     else
2955         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
2956
2957     msi_free( info );
2958
2959     if (rc != INSTALLSTATE_LOCAL)
2960         return ERROR_FILE_NOT_FOUND;
2961
2962     return ERROR_SUCCESS;
2963 }
2964
2965 /***********************************************************************
2966  * MsiProvideQualifiedComponentExW [MSI.@]
2967  */
2968 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
2969                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2970                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
2971                 LPDWORD pcchPathBuf)
2972 {
2973     awstring path;
2974
2975     path.unicode = TRUE;
2976     path.str.w = lpPathBuf;
2977
2978     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
2979             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
2980 }
2981
2982 /***********************************************************************
2983  * MsiProvideQualifiedComponentExA [MSI.@]
2984  */
2985 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
2986                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
2987                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
2988                 LPDWORD pcchPathBuf)
2989 {
2990     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
2991     UINT r = ERROR_OUTOFMEMORY;
2992     awstring path;
2993
2994     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
2995           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
2996           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2997
2998     szwComponent = strdupAtoW( szComponent );
2999     if (szComponent && !szwComponent)
3000         goto end;
3001
3002     szwQualifier = strdupAtoW( szQualifier );
3003     if (szQualifier && !szwQualifier)
3004         goto end;
3005
3006     szwProduct = strdupAtoW( szProduct );
3007     if (szProduct && !szwProduct)
3008         goto end;
3009
3010     path.unicode = FALSE;
3011     path.str.a = lpPathBuf;
3012
3013     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
3014                               dwInstallMode, szwProduct, Unused1,
3015                               Unused2, &path, pcchPathBuf);
3016 end:
3017     msi_free(szwProduct);
3018     msi_free(szwComponent);
3019     msi_free(szwQualifier);
3020
3021     return r;
3022 }
3023
3024 /***********************************************************************
3025  * MsiProvideQualifiedComponentW [MSI.@]
3026  */
3027 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
3028                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
3029                 LPDWORD pcchPathBuf)
3030 {
3031     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
3032                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3033 }
3034
3035 /***********************************************************************
3036  * MsiProvideQualifiedComponentA [MSI.@]
3037  */
3038 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
3039                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
3040                 LPDWORD pcchPathBuf)
3041 {
3042     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
3043                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
3044 }
3045
3046 /***********************************************************************
3047  * MSI_GetUserInfo [internal]
3048  */
3049 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
3050                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
3051                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3052                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
3053 {
3054     WCHAR squished_pc[SQUISH_GUID_SIZE];
3055     LPWSTR user, org, serial;
3056     USERINFOSTATE state;
3057     HKEY hkey, props;
3058     LPCWSTR orgptr;
3059     UINT r;
3060
3061     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
3062           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
3063           pcchSerialBuf);
3064
3065     if (!szProduct || !squash_guid(szProduct, squished_pc))
3066         return USERINFOSTATE_INVALIDARG;
3067
3068     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
3069                               &hkey, FALSE) != ERROR_SUCCESS &&
3070         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3071                               &hkey, FALSE) != ERROR_SUCCESS &&
3072         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
3073                               &hkey, FALSE) != ERROR_SUCCESS)
3074     {
3075         return USERINFOSTATE_UNKNOWN;
3076     }
3077
3078     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
3079                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
3080         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
3081                                 NULL, &props, FALSE) != ERROR_SUCCESS)
3082     {
3083         RegCloseKey(hkey);
3084         return USERINFOSTATE_ABSENT;
3085     }
3086
3087     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
3088     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
3089     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
3090     state = USERINFOSTATE_ABSENT;
3091
3092     RegCloseKey(hkey);
3093     RegCloseKey(props);
3094
3095     if (user && serial)
3096         state = USERINFOSTATE_PRESENT;
3097
3098     if (pcchUserNameBuf)
3099     {
3100         if (lpUserNameBuf && !user)
3101         {
3102             (*pcchUserNameBuf)--;
3103             goto done;
3104         }
3105
3106         r = msi_strcpy_to_awstring(user, lpUserNameBuf, pcchUserNameBuf);
3107         if (r == ERROR_MORE_DATA)
3108         {
3109             state = USERINFOSTATE_MOREDATA;
3110             goto done;
3111         }
3112     }
3113
3114     if (pcchOrgNameBuf)
3115     {
3116         orgptr = org;
3117         if (!orgptr) orgptr = szEmpty;
3118
3119         r = msi_strcpy_to_awstring(orgptr, lpOrgNameBuf, pcchOrgNameBuf);
3120         if (r == ERROR_MORE_DATA)
3121         {
3122             state = USERINFOSTATE_MOREDATA;
3123             goto done;
3124         }
3125     }
3126
3127     if (pcchSerialBuf)
3128     {
3129         if (!serial)
3130         {
3131             (*pcchSerialBuf)--;
3132             goto done;
3133         }
3134
3135         r = msi_strcpy_to_awstring(serial, lpSerialBuf, pcchSerialBuf);
3136         if (r == ERROR_MORE_DATA)
3137             state = USERINFOSTATE_MOREDATA;
3138     }
3139
3140 done:
3141     msi_free(user);
3142     msi_free(org);
3143     msi_free(serial);
3144
3145     return state;
3146 }
3147
3148 /***********************************************************************
3149  * MsiGetUserInfoW [MSI.@]
3150  */
3151 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3152                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3153                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3154                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3155 {
3156     awstring user, org, serial;
3157
3158     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3159         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3160         (lpSerialBuf && !pcchSerialBuf))
3161         return USERINFOSTATE_INVALIDARG;
3162
3163     user.unicode = TRUE;
3164     user.str.w = lpUserNameBuf;
3165     org.unicode = TRUE;
3166     org.str.w = lpOrgNameBuf;
3167     serial.unicode = TRUE;
3168     serial.str.w = lpSerialBuf;
3169
3170     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3171                             &org, pcchOrgNameBuf,
3172                             &serial, pcchSerialBuf );
3173 }
3174
3175 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3176                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3177                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3178                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3179 {
3180     awstring user, org, serial;
3181     LPWSTR prod;
3182     UINT r;
3183
3184     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3185         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3186         (lpSerialBuf && !pcchSerialBuf))
3187         return USERINFOSTATE_INVALIDARG;
3188
3189     prod = strdupAtoW( szProduct );
3190     if (szProduct && !prod)
3191         return ERROR_OUTOFMEMORY;
3192
3193     user.unicode = FALSE;
3194     user.str.a = lpUserNameBuf;
3195     org.unicode = FALSE;
3196     org.str.a = lpOrgNameBuf;
3197     serial.unicode = FALSE;
3198     serial.str.a = lpSerialBuf;
3199
3200     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3201                          &org, pcchOrgNameBuf,
3202                          &serial, pcchSerialBuf );
3203
3204     msi_free( prod );
3205
3206     return r;
3207 }
3208
3209 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3210 {
3211     MSIHANDLE handle;
3212     UINT rc;
3213     MSIPACKAGE *package;
3214     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3215
3216     TRACE("(%s)\n",debugstr_w(szProduct));
3217
3218     rc = MsiOpenProductW(szProduct,&handle);
3219     if (rc != ERROR_SUCCESS)
3220         return ERROR_INVALID_PARAMETER;
3221
3222     /* MsiCollectUserInfo cannot be called from a custom action. */
3223     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3224     if (!package)
3225         return ERROR_CALL_NOT_IMPLEMENTED;
3226
3227     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
3228     msiobj_release( &package->hdr );
3229
3230     MsiCloseHandle(handle);
3231
3232     return rc;
3233 }
3234
3235 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3236 {
3237     MSIHANDLE handle;
3238     UINT rc;
3239     MSIPACKAGE *package;
3240     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3241
3242     TRACE("(%s)\n",debugstr_a(szProduct));
3243
3244     rc = MsiOpenProductA(szProduct,&handle);
3245     if (rc != ERROR_SUCCESS)
3246         return ERROR_INVALID_PARAMETER;
3247
3248     /* MsiCollectUserInfo cannot be called from a custom action. */
3249     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3250     if (!package)
3251         return ERROR_CALL_NOT_IMPLEMENTED;
3252
3253     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
3254     msiobj_release( &package->hdr );
3255
3256     MsiCloseHandle(handle);
3257
3258     return rc;
3259 }
3260
3261 /***********************************************************************
3262  * MsiConfigureFeatureA            [MSI.@]
3263  */
3264 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3265 {
3266     LPWSTR prod, feat = NULL;
3267     UINT r = ERROR_OUTOFMEMORY;
3268
3269     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3270
3271     prod = strdupAtoW( szProduct );
3272     if (szProduct && !prod)
3273         goto end;
3274
3275     feat = strdupAtoW( szFeature );
3276     if (szFeature && !feat)
3277         goto end;
3278
3279     r = MsiConfigureFeatureW(prod, feat, eInstallState);
3280
3281 end:
3282     msi_free(feat);
3283     msi_free(prod);
3284
3285     return r;
3286 }
3287
3288 /***********************************************************************
3289  * MsiConfigureFeatureW            [MSI.@]
3290  */
3291 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
3292 {
3293     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
3294     MSIPACKAGE *package = NULL;
3295     UINT r;
3296     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
3297     DWORD sz;
3298
3299     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
3300
3301     if (!szProduct || !szFeature)
3302         return ERROR_INVALID_PARAMETER;
3303
3304     switch (eInstallState)
3305     {
3306     case INSTALLSTATE_DEFAULT:
3307         /* FIXME: how do we figure out the default location? */
3308         eInstallState = INSTALLSTATE_LOCAL;
3309         break;
3310     case INSTALLSTATE_LOCAL:
3311     case INSTALLSTATE_SOURCE:
3312     case INSTALLSTATE_ABSENT:
3313     case INSTALLSTATE_ADVERTISED:
3314         break;
3315     default:
3316         return ERROR_INVALID_PARAMETER;
3317     }
3318
3319     r = MSI_OpenProductW( szProduct, &package );
3320     if (r != ERROR_SUCCESS)
3321         return r;
3322
3323     sz = sizeof(sourcepath);
3324     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3325                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3326
3327     sz = sizeof(filename);
3328     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3329                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3330
3331     lstrcatW( sourcepath, filename );
3332
3333     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
3334
3335     r = ACTION_PerformUIAction( package, szCostInit, -1 );
3336     if (r != ERROR_SUCCESS)
3337         goto end;
3338
3339     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
3340     if (r != ERROR_SUCCESS)
3341         goto end;
3342
3343     r = MSI_InstallPackage( package, sourcepath, NULL );
3344
3345 end:
3346     msiobj_release( &package->hdr );
3347
3348     return r;
3349 }
3350
3351 /***********************************************************************
3352  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
3353  *
3354  * Notes: undocumented
3355  */
3356 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
3357 {
3358     WCHAR path[MAX_PATH];
3359
3360     TRACE("%d\n", dwReserved);
3361
3362     if (dwReserved)
3363     {
3364         FIXME("dwReserved=%d\n", dwReserved);
3365         return ERROR_INVALID_PARAMETER;
3366     }
3367
3368     if (!GetWindowsDirectoryW(path, MAX_PATH))
3369         return ERROR_FUNCTION_FAILED;
3370
3371     lstrcatW(path, installerW);
3372
3373     if (!CreateDirectoryW(path, NULL))
3374         return ERROR_FUNCTION_FAILED;
3375
3376     return ERROR_SUCCESS;
3377 }
3378
3379 /***********************************************************************
3380  * MsiGetShortcutTargetA           [MSI.@]
3381  */
3382 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
3383                                    LPSTR szProductCode, LPSTR szFeatureId,
3384                                    LPSTR szComponentCode )
3385 {
3386     LPWSTR target;
3387     const int len = MAX_FEATURE_CHARS+1;
3388     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
3389     UINT r;
3390
3391     target = strdupAtoW( szShortcutTarget );
3392     if (szShortcutTarget && !target )
3393         return ERROR_OUTOFMEMORY;
3394     product[0] = 0;
3395     feature[0] = 0;
3396     component[0] = 0;
3397     r = MsiGetShortcutTargetW( target, product, feature, component );
3398     msi_free( target );
3399     if (r == ERROR_SUCCESS)
3400     {
3401         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
3402         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
3403         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
3404     }
3405     return r;
3406 }
3407
3408 /***********************************************************************
3409  * MsiGetShortcutTargetW           [MSI.@]
3410  */
3411 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
3412                                    LPWSTR szProductCode, LPWSTR szFeatureId,
3413                                    LPWSTR szComponentCode )
3414 {
3415     IShellLinkDataList *dl = NULL;
3416     IPersistFile *pf = NULL;
3417     LPEXP_DARWIN_LINK darwin = NULL;
3418     HRESULT r, init;
3419
3420     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
3421           szProductCode, szFeatureId, szComponentCode );
3422
3423     init = CoInitialize(NULL);
3424
3425     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3426                           &IID_IPersistFile, (LPVOID*) &pf );
3427     if( SUCCEEDED( r ) )
3428     {
3429         r = IPersistFile_Load( pf, szShortcutTarget,
3430                                STGM_READ | STGM_SHARE_DENY_WRITE );
3431         if( SUCCEEDED( r ) )
3432         {
3433             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
3434                                              (LPVOID*) &dl );
3435             if( SUCCEEDED( r ) )
3436             {
3437                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
3438                                                   (LPVOID) &darwin );
3439                 IShellLinkDataList_Release( dl );
3440             }
3441         }
3442         IPersistFile_Release( pf );
3443     }
3444
3445     if (SUCCEEDED(init))
3446         CoUninitialize();
3447
3448     TRACE("darwin = %p\n", darwin);
3449
3450     if (darwin)
3451     {
3452         DWORD sz;
3453         UINT ret;
3454
3455         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
3456                   szProductCode, szFeatureId, szComponentCode, &sz );
3457         LocalFree( darwin );
3458         return ret;
3459     }
3460
3461     return ERROR_FUNCTION_FAILED;
3462 }
3463
3464 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
3465                                   DWORD dwReinstallMode )
3466 {
3467     MSIPACKAGE* package = NULL;
3468     UINT r;
3469     WCHAR sourcepath[MAX_PATH];
3470     WCHAR filename[MAX_PATH];
3471     static const WCHAR szLogVerbose[] = {
3472         ' ','L','O','G','V','E','R','B','O','S','E',0 };
3473     WCHAR reinstallmode[11];
3474     LPWSTR ptr;
3475     DWORD sz;
3476
3477     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
3478                            dwReinstallMode);
3479
3480     ptr = reinstallmode;
3481
3482     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
3483         *ptr++ = 'p';
3484     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
3485         *ptr++ = 'o';
3486     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
3487         *ptr++ = 'w';
3488     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
3489         *ptr++ = 'd';
3490     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
3491         *ptr++ = 'c';
3492     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
3493         *ptr++ = 'a';
3494     if (dwReinstallMode & REINSTALLMODE_USERDATA)
3495         *ptr++ = 'u';
3496     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
3497         *ptr++ = 'm';
3498     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
3499         *ptr++ = 's';
3500     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3501         *ptr++ = 'v';
3502     *ptr = 0;
3503     
3504     sz = sizeof(sourcepath);
3505     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3506             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3507
3508     sz = sizeof(filename);
3509     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3510             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3511
3512     lstrcatW( sourcepath, filename );
3513
3514     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3515         r = MSI_OpenPackageW( sourcepath, &package );
3516     else
3517         r = MSI_OpenProductW( szProduct, &package );
3518
3519     if (r != ERROR_SUCCESS)
3520         return r;
3521
3522     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
3523     MSI_SetPropertyW( package, szInstalled, szOne );
3524     MSI_SetPropertyW( package, szLogVerbose, szOne );
3525     MSI_SetPropertyW( package, szReinstall, szFeature );
3526
3527     r = MSI_InstallPackage( package, sourcepath, NULL );
3528
3529     msiobj_release( &package->hdr );
3530
3531     return r;
3532 }
3533
3534 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
3535                                   DWORD dwReinstallMode )
3536 {
3537     LPWSTR wszProduct;
3538     LPWSTR wszFeature;
3539     UINT rc;
3540
3541     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
3542                            dwReinstallMode);
3543
3544     wszProduct = strdupAtoW(szProduct);
3545     wszFeature = strdupAtoW(szFeature);
3546
3547     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
3548
3549     msi_free(wszProduct);
3550     msi_free(wszFeature);
3551     return rc;
3552 }
3553
3554 typedef struct
3555 {
3556     unsigned int i[2];
3557     unsigned int buf[4];
3558     unsigned char in[64];
3559     unsigned char digest[16];
3560 } MD5_CTX;
3561
3562 extern VOID WINAPI MD5Init( MD5_CTX *);
3563 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
3564 extern VOID WINAPI MD5Final( MD5_CTX *);
3565
3566 /***********************************************************************
3567  * MsiGetFileHashW            [MSI.@]
3568  */
3569 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
3570                              PMSIFILEHASHINFO pHash )
3571 {
3572     HANDLE handle, mapping;
3573     void *p;
3574     DWORD length;
3575     UINT r = ERROR_FUNCTION_FAILED;
3576
3577     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
3578
3579     if (!szFilePath)
3580         return ERROR_INVALID_PARAMETER;
3581
3582     if (!*szFilePath)
3583         return ERROR_PATH_NOT_FOUND;
3584
3585     if (dwOptions)
3586         return ERROR_INVALID_PARAMETER;
3587     if (!pHash)
3588         return ERROR_INVALID_PARAMETER;
3589     if (pHash->dwFileHashInfoSize < sizeof *pHash)
3590         return ERROR_INVALID_PARAMETER;
3591
3592     handle = CreateFileW( szFilePath, GENERIC_READ,
3593                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
3594     if (handle == INVALID_HANDLE_VALUE)
3595         return ERROR_FILE_NOT_FOUND;
3596
3597     length = GetFileSize( handle, NULL );
3598
3599     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
3600     if (mapping)
3601     {
3602         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
3603         if (p)
3604         {
3605             MD5_CTX ctx;
3606
3607             MD5Init( &ctx );
3608             MD5Update( &ctx, p, length );
3609             MD5Final( &ctx );
3610             UnmapViewOfFile( p );
3611
3612             memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
3613             r = ERROR_SUCCESS;
3614         }
3615         CloseHandle( mapping );
3616     }
3617     CloseHandle( handle );
3618
3619     return r;
3620 }
3621
3622 /***********************************************************************
3623  * MsiGetFileHashA            [MSI.@]
3624  */
3625 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
3626                              PMSIFILEHASHINFO pHash )
3627 {
3628     LPWSTR file;
3629     UINT r;
3630
3631     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
3632
3633     file = strdupAtoW( szFilePath );
3634     if (szFilePath && !file)
3635         return ERROR_OUTOFMEMORY;
3636
3637     r = MsiGetFileHashW( file, dwOptions, pHash );
3638     msi_free( file );
3639     return r;
3640 }
3641
3642 /***********************************************************************
3643  * MsiAdvertiseScriptW        [MSI.@]
3644  */
3645 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
3646                                  PHKEY phRegData, BOOL fRemoveItems )
3647 {
3648     FIXME("%s %08x %p %d\n",
3649           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3650     return ERROR_CALL_NOT_IMPLEMENTED;
3651 }
3652
3653 /***********************************************************************
3654  * MsiAdvertiseScriptA        [MSI.@]
3655  */
3656 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
3657                                  PHKEY phRegData, BOOL fRemoveItems )
3658 {
3659     FIXME("%s %08x %p %d\n",
3660           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3661     return ERROR_CALL_NOT_IMPLEMENTED;
3662 }
3663
3664 /***********************************************************************
3665  * MsiIsProductElevatedW        [MSI.@]
3666  */
3667 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
3668 {
3669     FIXME("%s %p - stub\n",
3670           debugstr_w( szProduct ), pfElevated );
3671     *pfElevated = TRUE;
3672     return ERROR_SUCCESS;
3673 }
3674
3675 /***********************************************************************
3676  * MsiIsProductElevatedA        [MSI.@]
3677  */
3678 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
3679 {
3680     FIXME("%s %p - stub\n",
3681           debugstr_a( szProduct ), pfElevated );
3682     *pfElevated = TRUE;
3683     return ERROR_SUCCESS;
3684 }
3685
3686 /***********************************************************************
3687  * MsiSetExternalUIRecord     [MSI.@]
3688  */
3689 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler,
3690                                     DWORD filter, LPVOID context,
3691                                     PINSTALLUI_HANDLER_RECORD prev )
3692 {
3693     TRACE("%p %08x %p %p\n", handler, filter, context, prev);
3694
3695     if (prev)
3696         *prev = gUIHandlerRecord;
3697
3698     gUIHandlerRecord = handler;
3699     gUIFilter        = filter;
3700     gUIContext       = context;
3701
3702     return ERROR_SUCCESS;
3703 }
3704
3705 /***********************************************************************
3706  * MsiInstallMissingComponentW     [MSI.@]
3707  */
3708 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
3709 {
3710     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
3711     return ERROR_SUCCESS;
3712 }