msi: Fix parsing of feature overrides.
[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 MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
1617 {
1618     LPWSTR szwLogFile = NULL;
1619     UINT r;
1620
1621     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
1622
1623     if( szLogFile )
1624     {
1625         szwLogFile = strdupAtoW( szLogFile );
1626         if( !szwLogFile )
1627             return ERROR_OUTOFMEMORY;
1628     }
1629     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
1630     msi_free( szwLogFile );
1631     return r;
1632 }
1633
1634 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
1635 {
1636     HANDLE file = INVALID_HANDLE_VALUE;
1637
1638     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
1639
1640     if (szLogFile)
1641     {
1642         lstrcpyW(gszLogFile,szLogFile);
1643         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
1644             DeleteFileW(szLogFile);
1645         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
1646                                FILE_ATTRIBUTE_NORMAL, NULL);
1647         if (file != INVALID_HANDLE_VALUE)
1648             CloseHandle(file);
1649         else
1650             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
1651     }
1652     else
1653         gszLogFile[0] = '\0';
1654
1655     return ERROR_SUCCESS;
1656 }
1657
1658 UINT WINAPI MsiEnumComponentCostsW(MSIHANDLE hInstall, LPCWSTR szComponent,
1659                                    DWORD dwIndex, INSTALLSTATE iState,
1660                                    LPWSTR lpDriveBuf, DWORD *pcchDriveBuf,
1661                                    int *piCost, int *pTempCost)
1662 {
1663     FIXME("(%d, %s, %d, %d, %p, %p, %p %p): stub!\n", hInstall,
1664           debugstr_w(szComponent), dwIndex, iState, lpDriveBuf,
1665           pcchDriveBuf, piCost, pTempCost);
1666
1667     return ERROR_NO_MORE_ITEMS;
1668 }
1669
1670 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
1671                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1672                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
1673 {
1674     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
1675     UINT r;
1676
1677     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
1678           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
1679
1680     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
1681         return ERROR_OUTOFMEMORY;
1682
1683     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
1684             return ERROR_OUTOFMEMORY;
1685
1686     if (szComponent && !(comp = strdupAtoW(szComponent)))
1687             return ERROR_OUTOFMEMORY;
1688
1689     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
1690
1691     msi_free(prodcode);
1692     msi_free(usersid);
1693     msi_free(comp);
1694
1695     return r;
1696 }
1697
1698 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
1699 {
1700     UINT r;
1701     HKEY hkey;
1702
1703     r = MSIREG_OpenProductKey(prodcode, NULL, context, &hkey, FALSE);
1704     RegCloseKey(hkey);
1705     return (r == ERROR_SUCCESS);
1706 }
1707
1708 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
1709 {
1710     LPCWSTR package;
1711     HKEY hkey;
1712     DWORD sz;
1713     LONG res;
1714     UINT r;
1715
1716     static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
1717     static const WCHAR managed_local_package[] = {
1718         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
1719     };
1720
1721     r = MSIREG_OpenInstallProps(prodcode, context, NULL, &hkey, FALSE);
1722     if (r != ERROR_SUCCESS)
1723         return FALSE;
1724
1725     if (context == MSIINSTALLCONTEXT_USERMANAGED)
1726         package = managed_local_package;
1727     else
1728         package = local_package;
1729
1730     sz = 0;
1731     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
1732     RegCloseKey(hkey);
1733
1734     return (res == ERROR_SUCCESS);
1735 }
1736
1737 static BOOL msi_comp_find_prodcode(LPWSTR squished_pc,
1738                                    MSIINSTALLCONTEXT context,
1739                                    LPCWSTR comp, LPWSTR val, DWORD *sz)
1740 {
1741     HKEY hkey;
1742     LONG res;
1743     UINT r;
1744
1745     if (context == MSIINSTALLCONTEXT_MACHINE)
1746         r = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
1747     else
1748         r = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
1749
1750     if (r != ERROR_SUCCESS)
1751         return FALSE;
1752
1753     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, (BYTE *)val, sz);
1754     if (res != ERROR_SUCCESS)
1755         return FALSE;
1756
1757     RegCloseKey(hkey);
1758     return TRUE;
1759 }
1760
1761 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
1762                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1763                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
1764 {
1765     WCHAR squished_pc[GUID_SIZE];
1766     WCHAR val[MAX_PATH];
1767     BOOL found;
1768     DWORD sz;
1769
1770     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
1771           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
1772
1773     if (!pdwState || !szComponent)
1774         return ERROR_INVALID_PARAMETER;
1775
1776     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
1777         return ERROR_INVALID_PARAMETER;
1778
1779     if (!squash_guid(szProductCode, squished_pc))
1780         return ERROR_INVALID_PARAMETER;
1781
1782     found = msi_comp_find_prod_key(szProductCode, dwContext);
1783
1784     if (!msi_comp_find_package(szProductCode, dwContext))
1785     {
1786         if (found)
1787         {
1788             *pdwState = INSTALLSTATE_UNKNOWN;
1789             return ERROR_UNKNOWN_COMPONENT;
1790         }
1791
1792         return ERROR_UNKNOWN_PRODUCT;
1793     }
1794
1795     *pdwState = INSTALLSTATE_UNKNOWN;
1796
1797     sz = MAX_PATH;
1798     if (!msi_comp_find_prodcode(squished_pc, dwContext, szComponent, val, &sz))
1799         return ERROR_UNKNOWN_COMPONENT;
1800
1801     if (sz == 0)
1802         *pdwState = INSTALLSTATE_NOTUSED;
1803     else
1804     {
1805         if (lstrlenW(val) > 2 &&
1806             val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9')
1807         {
1808             *pdwState = INSTALLSTATE_SOURCE;
1809         }
1810         else
1811             *pdwState = INSTALLSTATE_LOCAL;
1812     }
1813
1814     return ERROR_SUCCESS;
1815 }
1816
1817 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
1818 {
1819     LPWSTR szwProduct = NULL;
1820     INSTALLSTATE r;
1821
1822     if( szProduct )
1823     {
1824          szwProduct = strdupAtoW( szProduct );
1825          if( !szwProduct )
1826              return ERROR_OUTOFMEMORY;
1827     }
1828     r = MsiQueryProductStateW( szwProduct );
1829     msi_free( szwProduct );
1830     return r;
1831 }
1832
1833 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
1834 {
1835     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
1836     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
1837     HKEY prodkey = 0, userdata = 0;
1838     DWORD val;
1839     UINT r;
1840
1841     static const WCHAR szWindowsInstaller[] = {
1842         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1843
1844     TRACE("%s\n", debugstr_w(szProduct));
1845
1846     if (!szProduct || !*szProduct)
1847         return INSTALLSTATE_INVALIDARG;
1848
1849     if (lstrlenW(szProduct) != GUID_SIZE - 1)
1850         return INSTALLSTATE_INVALIDARG;
1851
1852     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1853                               &prodkey, FALSE) != ERROR_SUCCESS &&
1854         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1855                               &prodkey, FALSE) != ERROR_SUCCESS &&
1856         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
1857                               &prodkey, FALSE) == ERROR_SUCCESS)
1858     {
1859         context = MSIINSTALLCONTEXT_MACHINE;
1860     }
1861
1862     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
1863     if (r != ERROR_SUCCESS)
1864         goto done;
1865
1866     if (!msi_reg_get_val_dword(userdata, szWindowsInstaller, &val))
1867         goto done;
1868
1869     if (val)
1870         state = INSTALLSTATE_DEFAULT;
1871     else
1872         state = INSTALLSTATE_UNKNOWN;
1873
1874 done:
1875     if (!prodkey)
1876     {
1877         state = INSTALLSTATE_UNKNOWN;
1878
1879         if (userdata)
1880             state = INSTALLSTATE_ABSENT;
1881     }
1882
1883     RegCloseKey(prodkey);
1884     RegCloseKey(userdata);
1885     return state;
1886 }
1887
1888 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
1889 {
1890     INSTALLUILEVEL old = gUILevel;
1891     HWND oldwnd = gUIhwnd;
1892
1893     TRACE("%08x %p\n", dwUILevel, phWnd);
1894
1895     gUILevel = dwUILevel;
1896     if (phWnd)
1897     {
1898         gUIhwnd = *phWnd;
1899         *phWnd = oldwnd;
1900     }
1901     return old;
1902 }
1903
1904 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
1905                                   DWORD dwMessageFilter, LPVOID pvContext)
1906 {
1907     INSTALLUI_HANDLERA prev = gUIHandlerA;
1908
1909     TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
1910
1911     gUIHandlerA = puiHandler;
1912     gUIHandlerW = NULL;
1913     gUIFilter   = dwMessageFilter;
1914     gUIContext  = pvContext;
1915
1916     return prev;
1917 }
1918
1919 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
1920                                   DWORD dwMessageFilter, LPVOID pvContext)
1921 {
1922     INSTALLUI_HANDLERW prev = gUIHandlerW;
1923
1924     TRACE("%p %08x %p\n", puiHandler, dwMessageFilter, pvContext);
1925
1926     gUIHandlerA = NULL;
1927     gUIHandlerW = puiHandler;
1928     gUIFilter   = dwMessageFilter;
1929     gUIContext  = pvContext;
1930
1931     return prev;
1932 }
1933
1934 /******************************************************************
1935  *  MsiLoadStringW            [MSI.@]
1936  *
1937  * Loads a string from MSI's string resources.
1938  *
1939  * PARAMS
1940  *
1941  *   handle        [I]  only -1 is handled currently
1942  *   id            [I]  id of the string to be loaded
1943  *   lpBuffer      [O]  buffer for the string to be written to
1944  *   nBufferMax    [I]  maximum size of the buffer in characters
1945  *   lang          [I]  the preferred language for the string
1946  *
1947  * RETURNS
1948  *
1949  *   If successful, this function returns the language id of the string loaded
1950  *   If the function fails, the function returns zero.
1951  *
1952  * NOTES
1953  *
1954  *   The type of the first parameter is unknown.  LoadString's prototype
1955  *  suggests that it might be a module handle.  I have made it an MSI handle
1956  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
1957  *  handle.  Maybe strings can be stored in an MSI database somehow.
1958  */
1959 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
1960                 int nBufferMax, LANGID lang )
1961 {
1962     HRSRC hres;
1963     HGLOBAL hResData;
1964     LPWSTR p;
1965     DWORD i, len;
1966
1967     TRACE("%d %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
1968
1969     if( handle != -1 )
1970         FIXME("don't know how to deal with handle = %08x\n", handle);
1971
1972     if( !lang )
1973         lang = GetUserDefaultLangID();
1974
1975     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
1976                             (LPWSTR)1, lang );
1977     if( !hres )
1978         return 0;
1979     hResData = LoadResource( msi_hInstance, hres );
1980     if( !hResData )
1981         return 0;
1982     p = LockResource( hResData );
1983     if( !p )
1984         return 0;
1985
1986     for (i = 0; i < (id&0xf); i++)
1987         p += *p + 1;
1988     len = *p;
1989
1990     if( nBufferMax <= len )
1991         return 0;
1992
1993     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
1994     lpBuffer[ len ] = 0;
1995
1996     TRACE("found -> %s\n", debugstr_w(lpBuffer));
1997
1998     return lang;
1999 }
2000
2001 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
2002                 int nBufferMax, LANGID lang )
2003 {
2004     LPWSTR bufW;
2005     LANGID r;
2006     INT len;
2007
2008     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
2009     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
2010     if( r )
2011     {
2012         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
2013         if( len <= nBufferMax )
2014             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
2015                                  lpBuffer, nBufferMax, NULL, NULL );
2016         else
2017             r = 0;
2018     }
2019     msi_free(bufW);
2020     return r;
2021 }
2022
2023 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
2024                 LPDWORD pcchBuf)
2025 {
2026     char szProduct[GUID_SIZE];
2027
2028     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
2029
2030     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
2031         return INSTALLSTATE_UNKNOWN;
2032
2033     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
2034 }
2035
2036 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
2037                 LPDWORD pcchBuf)
2038 {
2039     WCHAR szProduct[GUID_SIZE];
2040
2041     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
2042
2043     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
2044         return INSTALLSTATE_UNKNOWN;
2045
2046     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
2047 }
2048
2049 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
2050                 WORD wLanguageId, DWORD f)
2051 {
2052     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
2053           uType, wLanguageId, f);
2054     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
2055 }
2056
2057 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
2058                 WORD wLanguageId, DWORD f)
2059 {
2060     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
2061           uType, wLanguageId, f);
2062     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
2063 }
2064
2065 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
2066                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
2067                 LPDWORD pcchPathBuf )
2068 {
2069     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
2070           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2071           pcchPathBuf);
2072     return ERROR_CALL_NOT_IMPLEMENTED;
2073 }
2074
2075 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
2076                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
2077                 LPDWORD pcchPathBuf )
2078 {
2079     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
2080           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2081           pcchPathBuf);
2082     return ERROR_CALL_NOT_IMPLEMENTED;
2083 }
2084
2085 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2086                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2087 {
2088     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2089     return ERROR_CALL_NOT_IMPLEMENTED;
2090 }
2091
2092 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2093                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2094 {
2095     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2096     return ERROR_CALL_NOT_IMPLEMENTED;
2097 }
2098
2099 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
2100                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
2101                 LPDWORD pcbHashData)
2102 {
2103     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
2104           ppcCertContext, pbHashData, pcbHashData);
2105     return ERROR_CALL_NOT_IMPLEMENTED;
2106 }
2107
2108 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
2109                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
2110                 LPDWORD pcbHashData)
2111 {
2112     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
2113           ppcCertContext, pbHashData, pcbHashData);
2114     return ERROR_CALL_NOT_IMPLEMENTED;
2115 }
2116
2117 /******************************************************************
2118  * MsiGetProductPropertyA      [MSI.@]
2119  */
2120 UINT WINAPI MsiGetProductPropertyA(MSIHANDLE hProduct, LPCSTR szProperty,
2121                                    LPSTR szValue, LPDWORD pccbValue)
2122 {
2123     LPWSTR prop = NULL, val = NULL;
2124     DWORD len;
2125     UINT r;
2126
2127     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_a(szProperty),
2128           szValue, pccbValue);
2129
2130     if (szValue && !pccbValue)
2131         return ERROR_INVALID_PARAMETER;
2132
2133     if (szProperty) prop = strdupAtoW(szProperty);
2134
2135     len = 0;
2136     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2137     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2138         goto done;
2139
2140     if (r == ERROR_SUCCESS)
2141     {
2142         if (szValue) *szValue = '\0';
2143         if (pccbValue) *pccbValue = 0;
2144         goto done;
2145     }
2146
2147     val = msi_alloc(++len * sizeof(WCHAR));
2148     if (!val)
2149     {
2150         r = ERROR_OUTOFMEMORY;
2151         goto done;
2152     }
2153
2154     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2155     if (r != ERROR_SUCCESS)
2156         goto done;
2157
2158     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2159
2160     if (szValue)
2161         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2162                             *pccbValue, NULL, NULL);
2163
2164     if (pccbValue)
2165     {
2166         if (len > *pccbValue)
2167             r = ERROR_MORE_DATA;
2168
2169         *pccbValue = len - 1;
2170     }
2171
2172 done:
2173     msi_free(prop);
2174     msi_free(val);
2175
2176     return r;
2177 }
2178
2179 /******************************************************************
2180  * MsiGetProductPropertyW      [MSI.@]
2181  */
2182 UINT WINAPI MsiGetProductPropertyW(MSIHANDLE hProduct, LPCWSTR szProperty,
2183                                    LPWSTR szValue, LPDWORD pccbValue)
2184 {
2185     MSIPACKAGE *package;
2186     MSIQUERY *view = NULL;
2187     MSIRECORD *rec = NULL;
2188     LPCWSTR val;
2189     UINT r;
2190
2191     static const WCHAR query[] = {
2192        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2193        '`','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2194        '`','P','r','o','p','e','r','t','y','`','=','\'','%','s','\'',0};
2195
2196     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_w(szProperty),
2197           szValue, pccbValue);
2198
2199     if (!szProperty)
2200         return ERROR_INVALID_PARAMETER;
2201
2202     if (szValue && !pccbValue)
2203         return ERROR_INVALID_PARAMETER;
2204
2205     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2206     if (!package)
2207         return ERROR_INVALID_HANDLE;
2208
2209     r = MSI_OpenQuery(package->db, &view, query, szProperty);
2210     if (r != ERROR_SUCCESS)
2211         goto done;
2212
2213     r = MSI_ViewExecute(view, 0);
2214     if (r != ERROR_SUCCESS)
2215         goto done;
2216
2217     r = MSI_ViewFetch(view, &rec);
2218     if (r != ERROR_SUCCESS)
2219         goto done;
2220
2221     val = MSI_RecordGetString(rec, 2);
2222     if (!val)
2223         goto done;
2224
2225     if (lstrlenW(val) >= *pccbValue)
2226     {
2227         lstrcpynW(szValue, val, *pccbValue);
2228         *pccbValue = lstrlenW(val);
2229         r = ERROR_MORE_DATA;
2230     }
2231     else
2232     {
2233         lstrcpyW(szValue, val);
2234         *pccbValue = lstrlenW(val);
2235         r = ERROR_SUCCESS;
2236     }
2237
2238 done:
2239     if (view)
2240     {
2241         MSI_ViewClose(view);
2242         msiobj_release(&view->hdr);
2243         if (rec) msiobj_release(&rec->hdr);
2244     }
2245
2246     if (!rec)
2247     {
2248         if (szValue) *szValue = '\0';
2249         if (pccbValue) *pccbValue = 0;
2250         r = ERROR_SUCCESS;
2251     }
2252
2253     return r;
2254 }
2255
2256 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2257 {
2258     UINT r;
2259     LPWSTR szPack = NULL;
2260
2261     TRACE("%s\n", debugstr_a(szPackage) );
2262
2263     if( szPackage )
2264     {
2265         szPack = strdupAtoW( szPackage );
2266         if( !szPack )
2267             return ERROR_OUTOFMEMORY;
2268     }
2269
2270     r = MsiVerifyPackageW( szPack );
2271
2272     msi_free( szPack );
2273
2274     return r;
2275 }
2276
2277 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2278 {
2279     MSIHANDLE handle;
2280     UINT r;
2281
2282     TRACE("%s\n", debugstr_w(szPackage) );
2283
2284     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2285     MsiCloseHandle( handle );
2286
2287     return r;
2288 }
2289
2290 static INSTALLSTATE MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
2291                                          awstring* lpPathBuf, LPDWORD pcchBuf)
2292 {
2293     WCHAR squished_pc[GUID_SIZE];
2294     WCHAR squished_comp[GUID_SIZE];
2295     HKEY hkey;
2296     LPWSTR path = NULL;
2297     INSTALLSTATE state;
2298     DWORD version;
2299
2300     static const WCHAR wininstaller[] = {
2301         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
2302
2303     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
2304            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
2305
2306     if (!szProduct || !szComponent)
2307         return INSTALLSTATE_INVALIDARG;
2308
2309     if (lpPathBuf->str.w && !pcchBuf)
2310         return INSTALLSTATE_INVALIDARG;
2311
2312     if (!squash_guid(szProduct, squished_pc) ||
2313         !squash_guid(szComponent, squished_comp))
2314         return INSTALLSTATE_INVALIDARG;
2315
2316     state = INSTALLSTATE_UNKNOWN;
2317
2318     if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
2319         MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
2320     {
2321         path = msi_reg_get_val_str(hkey, squished_pc);
2322         RegCloseKey(hkey);
2323
2324         state = INSTALLSTATE_ABSENT;
2325
2326         if ((MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL,
2327                                      &hkey, FALSE) == ERROR_SUCCESS ||
2328             MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2329                                           NULL, &hkey, FALSE) == ERROR_SUCCESS) &&
2330             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
2331             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2332         {
2333             RegCloseKey(hkey);
2334             state = INSTALLSTATE_LOCAL;
2335         }
2336     }
2337
2338     if (state != INSTALLSTATE_LOCAL &&
2339         (MSIREG_OpenProductKey(szProduct, NULL,
2340                                MSIINSTALLCONTEXT_USERUNMANAGED,
2341                                &hkey, FALSE) == ERROR_SUCCESS ||
2342          MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2343                                &hkey, FALSE) == ERROR_SUCCESS))
2344     {
2345         RegCloseKey(hkey);
2346
2347         if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
2348             MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
2349         {
2350             msi_free(path);
2351             path = msi_reg_get_val_str(hkey, squished_pc);
2352             RegCloseKey(hkey);
2353
2354             state = INSTALLSTATE_ABSENT;
2355
2356             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2357                 state = INSTALLSTATE_LOCAL;
2358         }
2359     }
2360
2361     if (!path)
2362         return INSTALLSTATE_UNKNOWN;
2363
2364     if (state == INSTALLSTATE_LOCAL && !*path)
2365         state = INSTALLSTATE_NOTUSED;
2366
2367     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
2368     msi_free(path);
2369     return state;
2370 }
2371
2372 /******************************************************************
2373  * MsiGetComponentPathW      [MSI.@]
2374  */
2375 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
2376                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
2377 {
2378     awstring path;
2379
2380     path.unicode = TRUE;
2381     path.str.w = lpPathBuf;
2382
2383     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
2384 }
2385
2386 /******************************************************************
2387  * MsiGetComponentPathA      [MSI.@]
2388  */
2389 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
2390                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
2391 {
2392     LPWSTR szwProduct, szwComponent = NULL;
2393     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2394     awstring path;
2395
2396     szwProduct = strdupAtoW( szProduct );
2397     if( szProduct && !szwProduct)
2398         goto end;
2399
2400     szwComponent = strdupAtoW( szComponent );
2401     if( szComponent && !szwComponent )
2402         goto end;
2403
2404     path.unicode = FALSE;
2405     path.str.a = lpPathBuf;
2406
2407     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
2408
2409 end:
2410     msi_free( szwProduct );
2411     msi_free( szwComponent );
2412
2413     return r;
2414 }
2415
2416 /******************************************************************
2417  * MsiQueryFeatureStateA      [MSI.@]
2418  */
2419 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
2420 {
2421     LPWSTR szwProduct = NULL, szwFeature= NULL;
2422     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
2423
2424     szwProduct = strdupAtoW( szProduct );
2425     if ( szProduct && !szwProduct )
2426         goto end;
2427
2428     szwFeature = strdupAtoW( szFeature );
2429     if ( szFeature && !szwFeature )
2430         goto end;
2431
2432     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
2433
2434 end:
2435     msi_free( szwProduct);
2436     msi_free( szwFeature);
2437
2438     return rc;
2439 }
2440
2441 /******************************************************************
2442  * MsiQueryFeatureStateW      [MSI.@]
2443  *
2444  * Checks the state of a feature
2445  *
2446  * PARAMS
2447  *   szProduct     [I]  Product's GUID string
2448  *   szFeature     [I]  Feature's GUID string
2449  *
2450  * RETURNS
2451  *   INSTALLSTATE_LOCAL        Feature is installed and usable
2452  *   INSTALLSTATE_ABSENT       Feature is absent
2453  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
2454  *   INSTALLSTATE_UNKNOWN      An error occurred
2455  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
2456  *
2457  */
2458 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
2459 {
2460     WCHAR squishProduct[33], comp[GUID_SIZE];
2461     GUID guid;
2462     LPWSTR components, p, parent_feature, path;
2463     UINT rc;
2464     HKEY hkey;
2465     INSTALLSTATE r;
2466     BOOL missing = FALSE;
2467     BOOL machine = FALSE;
2468     BOOL source = FALSE;
2469
2470     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
2471
2472     if (!szProduct || !szFeature)
2473         return INSTALLSTATE_INVALIDARG;
2474
2475     if (!squash_guid( szProduct, squishProduct ))
2476         return INSTALLSTATE_INVALIDARG;
2477
2478     if (MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERMANAGED,
2479                                &hkey, FALSE) != ERROR_SUCCESS &&
2480         MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2481                                &hkey, FALSE) != ERROR_SUCCESS)
2482     {
2483         rc = MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_MACHINE,
2484                                     &hkey, FALSE);
2485         if (rc != ERROR_SUCCESS)
2486             return INSTALLSTATE_UNKNOWN;
2487
2488         machine = TRUE;
2489     }
2490
2491     parent_feature = msi_reg_get_val_str( hkey, szFeature );
2492     RegCloseKey(hkey);
2493
2494     if (!parent_feature)
2495         return INSTALLSTATE_UNKNOWN;
2496
2497     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2498     msi_free(parent_feature);
2499     if (r == INSTALLSTATE_ABSENT)
2500         return r;
2501
2502     if (machine)
2503         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
2504                                             MSIINSTALLCONTEXT_MACHINE,
2505                                             &hkey, FALSE);
2506     else
2507         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
2508                                             MSIINSTALLCONTEXT_USERUNMANAGED,
2509                                             &hkey, FALSE);
2510
2511     if (rc != ERROR_SUCCESS)
2512         return INSTALLSTATE_ADVERTISED;
2513
2514     components = msi_reg_get_val_str( hkey, szFeature );
2515     RegCloseKey(hkey);
2516
2517     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
2518
2519     if (!components)
2520         return INSTALLSTATE_ADVERTISED;
2521
2522     for( p = components; *p && *p != 2 ; p += 20)
2523     {
2524         if (!decode_base85_guid( p, &guid ))
2525         {
2526             if (p != components)
2527                 break;
2528
2529             msi_free(components);
2530             return INSTALLSTATE_BADCONFIG;
2531         }
2532
2533         StringFromGUID2(&guid, comp, GUID_SIZE);
2534
2535         if (machine)
2536             rc = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
2537         else
2538             rc = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
2539
2540         if (rc != ERROR_SUCCESS)
2541         {
2542             msi_free(components);
2543             return INSTALLSTATE_ADVERTISED;
2544         }
2545
2546         path = msi_reg_get_val_str(hkey, squishProduct);
2547         if (!path)
2548             missing = TRUE;
2549         else if (lstrlenW(path) > 2 &&
2550                  path[0] >= '0' && path[0] <= '9' &&
2551                  path[1] >= '0' && path[1] <= '9')
2552         {
2553             source = TRUE;
2554         }
2555
2556         msi_free(path);
2557     }
2558
2559     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
2560     msi_free(components);
2561
2562     if (missing)
2563         return INSTALLSTATE_ADVERTISED;
2564
2565     if (source)
2566         return INSTALLSTATE_SOURCE;
2567
2568     return INSTALLSTATE_LOCAL;
2569 }
2570
2571 /******************************************************************
2572  * MsiGetFileVersionA         [MSI.@]
2573  */
2574 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
2575                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
2576 {
2577     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
2578     UINT ret = ERROR_OUTOFMEMORY;
2579
2580     if ((lpVersionBuf && !pcchVersionBuf) ||
2581         (lpLangBuf && !pcchLangBuf))
2582         return ERROR_INVALID_PARAMETER;
2583
2584     if( szFilePath )
2585     {
2586         szwFilePath = strdupAtoW( szFilePath );
2587         if( !szwFilePath )
2588             goto end;
2589     }
2590
2591     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
2592     {
2593         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
2594         if( !lpwVersionBuff )
2595             goto end;
2596     }
2597
2598     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
2599     {
2600         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
2601         if( !lpwLangBuff )
2602             goto end;
2603     }
2604
2605     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
2606                              lpwLangBuff, pcchLangBuf);
2607
2608     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
2609         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
2610                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
2611     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
2612         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
2613                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
2614
2615 end:
2616     msi_free(szwFilePath);
2617     msi_free(lpwVersionBuff);
2618     msi_free(lpwLangBuff);
2619
2620     return ret;
2621 }
2622
2623 /******************************************************************
2624  * MsiGetFileVersionW         [MSI.@]
2625  */
2626 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
2627                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
2628 {
2629     static const WCHAR szVersionResource[] = {'\\',0};
2630     static const WCHAR szVersionFormat[] = {
2631         '%','d','.','%','d','.','%','d','.','%','d',0};
2632     static const WCHAR szLangResource[] = {
2633         '\\','V','a','r','F','i','l','e','I','n','f','o','\\',
2634         'T','r','a','n','s','l','a','t','i','o','n',0};
2635     static const WCHAR szLangFormat[] = {'%','d',0};
2636     UINT ret = 0;
2637     DWORD dwVerLen, gle;
2638     LPVOID lpVer = NULL;
2639     VS_FIXEDFILEINFO *ffi;
2640     USHORT *lang;
2641     UINT puLen;
2642     WCHAR tmp[32];
2643
2644     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
2645           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
2646           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
2647
2648     if ((lpVersionBuf && !pcchVersionBuf) ||
2649         (lpLangBuf && !pcchLangBuf))
2650         return ERROR_INVALID_PARAMETER;
2651
2652     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
2653     if( !dwVerLen )
2654     {
2655         gle = GetLastError();
2656         if (gle == ERROR_BAD_PATHNAME)
2657             return ERROR_FILE_NOT_FOUND;
2658         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
2659             return ERROR_FILE_INVALID;
2660
2661         return gle;
2662     }
2663
2664     lpVer = msi_alloc(dwVerLen);
2665     if( !lpVer )
2666     {
2667         ret = ERROR_OUTOFMEMORY;
2668         goto end;
2669     }
2670
2671     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
2672     {
2673         ret = GetLastError();
2674         goto end;
2675     }
2676
2677     if (pcchVersionBuf)
2678     {
2679         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
2680             (puLen > 0) )
2681         {
2682             wsprintfW(tmp, szVersionFormat,
2683                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
2684                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
2685             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
2686
2687             if (strlenW(tmp) >= *pcchVersionBuf)
2688                 ret = ERROR_MORE_DATA;
2689
2690             *pcchVersionBuf = lstrlenW(tmp);
2691         }
2692         else
2693         {
2694             if (lpVersionBuf) *lpVersionBuf = 0;
2695             *pcchVersionBuf = 0;
2696         }
2697     }
2698
2699     if (pcchLangBuf)
2700     {
2701         if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
2702             (puLen > 0))
2703         {
2704             wsprintfW(tmp, szLangFormat, *lang);
2705             if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
2706
2707             if (strlenW(tmp) >= *pcchLangBuf)
2708                 ret = ERROR_MORE_DATA;
2709
2710             *pcchLangBuf = lstrlenW(tmp);
2711         }
2712         else
2713         {
2714             if (lpLangBuf) *lpLangBuf = 0;
2715             *pcchLangBuf = 0;
2716         }
2717     }
2718
2719 end:
2720     msi_free(lpVer);
2721     return ret;
2722 }
2723
2724 /***********************************************************************
2725  * MsiGetFeatureUsageW           [MSI.@]
2726  */
2727 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
2728                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2729 {
2730     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
2731           pdwUseCount, pwDateUsed);
2732     return ERROR_CALL_NOT_IMPLEMENTED;
2733 }
2734
2735 /***********************************************************************
2736  * MsiGetFeatureUsageA           [MSI.@]
2737  */
2738 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
2739                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2740 {
2741     LPWSTR prod = NULL, feat = NULL;
2742     UINT ret = ERROR_OUTOFMEMORY;
2743
2744     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
2745           pdwUseCount, pwDateUsed);
2746
2747     prod = strdupAtoW( szProduct );
2748     if (szProduct && !prod)
2749         goto end;
2750
2751     feat = strdupAtoW( szFeature );
2752     if (szFeature && !feat)
2753         goto end;
2754
2755     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
2756
2757 end:
2758     msi_free( prod );
2759     msi_free( feat );
2760
2761     return ret;
2762 }
2763
2764 /***********************************************************************
2765  * MsiUseFeatureExW           [MSI.@]
2766  */
2767 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
2768                                       DWORD dwInstallMode, DWORD dwReserved )
2769 {
2770     INSTALLSTATE state;
2771
2772     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2773           dwInstallMode, dwReserved);
2774
2775     state = MsiQueryFeatureStateW( szProduct, szFeature );
2776
2777     if (dwReserved)
2778         return INSTALLSTATE_INVALIDARG;
2779
2780     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
2781     {
2782         FIXME("mark product %s feature %s as used\n",
2783               debugstr_w(szProduct), debugstr_w(szFeature) );
2784     }
2785
2786     return state;
2787 }
2788
2789 /***********************************************************************
2790  * MsiUseFeatureExA           [MSI.@]
2791  */
2792 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
2793                                       DWORD dwInstallMode, DWORD dwReserved )
2794 {
2795     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
2796     LPWSTR prod = NULL, feat = NULL;
2797
2798     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2799           dwInstallMode, dwReserved);
2800
2801     prod = strdupAtoW( szProduct );
2802     if (szProduct && !prod)
2803         goto end;
2804
2805     feat = strdupAtoW( szFeature );
2806     if (szFeature && !feat)
2807         goto end;
2808
2809     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
2810
2811 end:
2812     msi_free( prod );
2813     msi_free( feat );
2814
2815     return ret;
2816 }
2817
2818 /***********************************************************************
2819  * MsiUseFeatureW             [MSI.@]
2820  */
2821 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
2822 {
2823     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
2824 }
2825
2826 /***********************************************************************
2827  * MsiUseFeatureA             [MSI.@]
2828  */
2829 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
2830 {
2831     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
2832 }
2833
2834 /***********************************************************************
2835  * MSI_ProvideQualifiedComponentEx [internal]
2836  */
2837 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
2838                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2839                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
2840                 LPDWORD pcchPathBuf)
2841 {
2842     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
2843           feature[MAX_FEATURE_CHARS+1];
2844     LPWSTR info;
2845     HKEY hkey;
2846     DWORD sz;
2847     UINT rc;
2848
2849     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
2850           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
2851           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2852
2853     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
2854     if (rc != ERROR_SUCCESS)
2855         return ERROR_INDEX_ABSENT;
2856
2857     info = msi_reg_get_val_str( hkey, szQualifier );
2858     RegCloseKey(hkey);
2859
2860     if (!info)
2861         return ERROR_INDEX_ABSENT;
2862
2863     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
2864
2865     if (!szProduct)
2866         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
2867     else
2868         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
2869
2870     msi_free( info );
2871
2872     if (rc != INSTALLSTATE_LOCAL)
2873         return ERROR_FILE_NOT_FOUND;
2874
2875     return ERROR_SUCCESS;
2876 }
2877
2878 /***********************************************************************
2879  * MsiProvideQualifiedComponentExW [MSI.@]
2880  */
2881 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
2882                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2883                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
2884                 LPDWORD pcchPathBuf)
2885 {
2886     awstring path;
2887
2888     path.unicode = TRUE;
2889     path.str.w = lpPathBuf;
2890
2891     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
2892             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
2893 }
2894
2895 /***********************************************************************
2896  * MsiProvideQualifiedComponentExA [MSI.@]
2897  */
2898 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
2899                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
2900                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
2901                 LPDWORD pcchPathBuf)
2902 {
2903     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
2904     UINT r = ERROR_OUTOFMEMORY;
2905     awstring path;
2906
2907     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
2908           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
2909           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2910
2911     szwComponent = strdupAtoW( szComponent );
2912     if (szComponent && !szwComponent)
2913         goto end;
2914
2915     szwQualifier = strdupAtoW( szQualifier );
2916     if (szQualifier && !szwQualifier)
2917         goto end;
2918
2919     szwProduct = strdupAtoW( szProduct );
2920     if (szProduct && !szwProduct)
2921         goto end;
2922
2923     path.unicode = FALSE;
2924     path.str.a = lpPathBuf;
2925
2926     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
2927                               dwInstallMode, szwProduct, Unused1,
2928                               Unused2, &path, pcchPathBuf);
2929 end:
2930     msi_free(szwProduct);
2931     msi_free(szwComponent);
2932     msi_free(szwQualifier);
2933
2934     return r;
2935 }
2936
2937 /***********************************************************************
2938  * MsiProvideQualifiedComponentW [MSI.@]
2939  */
2940 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
2941                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
2942                 LPDWORD pcchPathBuf)
2943 {
2944     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
2945                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2946 }
2947
2948 /***********************************************************************
2949  * MsiProvideQualifiedComponentA [MSI.@]
2950  */
2951 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
2952                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
2953                 LPDWORD pcchPathBuf)
2954 {
2955     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
2956                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2957 }
2958
2959 /***********************************************************************
2960  * MSI_GetUserInfo [internal]
2961  */
2962 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
2963                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
2964                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2965                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
2966 {
2967     WCHAR squished_pc[SQUISH_GUID_SIZE];
2968     LPWSTR user, org, serial;
2969     USERINFOSTATE state;
2970     HKEY hkey, props;
2971     LPCWSTR orgptr;
2972     UINT r;
2973
2974     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
2975           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
2976           pcchSerialBuf);
2977
2978     if (!szProduct || !squash_guid(szProduct, squished_pc))
2979         return USERINFOSTATE_INVALIDARG;
2980
2981     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2982                               &hkey, FALSE) != ERROR_SUCCESS &&
2983         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2984                               &hkey, FALSE) != ERROR_SUCCESS &&
2985         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2986                               &hkey, FALSE) != ERROR_SUCCESS)
2987     {
2988         return USERINFOSTATE_UNKNOWN;
2989     }
2990
2991     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2992                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
2993         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
2994                                 NULL, &props, FALSE) != ERROR_SUCCESS)
2995     {
2996         RegCloseKey(hkey);
2997         return USERINFOSTATE_ABSENT;
2998     }
2999
3000     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
3001     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
3002     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
3003     state = USERINFOSTATE_ABSENT;
3004
3005     RegCloseKey(hkey);
3006     RegCloseKey(props);
3007
3008     if (user && serial)
3009         state = USERINFOSTATE_PRESENT;
3010
3011     if (pcchUserNameBuf)
3012     {
3013         if (lpUserNameBuf && !user)
3014         {
3015             (*pcchUserNameBuf)--;
3016             goto done;
3017         }
3018
3019         r = msi_strcpy_to_awstring(user, lpUserNameBuf, pcchUserNameBuf);
3020         if (r == ERROR_MORE_DATA)
3021         {
3022             state = USERINFOSTATE_MOREDATA;
3023             goto done;
3024         }
3025     }
3026
3027     if (pcchOrgNameBuf)
3028     {
3029         orgptr = org;
3030         if (!orgptr) orgptr = szEmpty;
3031
3032         r = msi_strcpy_to_awstring(orgptr, lpOrgNameBuf, pcchOrgNameBuf);
3033         if (r == ERROR_MORE_DATA)
3034         {
3035             state = USERINFOSTATE_MOREDATA;
3036             goto done;
3037         }
3038     }
3039
3040     if (pcchSerialBuf)
3041     {
3042         if (!serial)
3043         {
3044             (*pcchSerialBuf)--;
3045             goto done;
3046         }
3047
3048         r = msi_strcpy_to_awstring(serial, lpSerialBuf, pcchSerialBuf);
3049         if (r == ERROR_MORE_DATA)
3050             state = USERINFOSTATE_MOREDATA;
3051     }
3052
3053 done:
3054     msi_free(user);
3055     msi_free(org);
3056     msi_free(serial);
3057
3058     return state;
3059 }
3060
3061 /***********************************************************************
3062  * MsiGetUserInfoW [MSI.@]
3063  */
3064 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3065                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3066                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3067                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3068 {
3069     awstring user, org, serial;
3070
3071     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3072         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3073         (lpSerialBuf && !pcchSerialBuf))
3074         return USERINFOSTATE_INVALIDARG;
3075
3076     user.unicode = TRUE;
3077     user.str.w = lpUserNameBuf;
3078     org.unicode = TRUE;
3079     org.str.w = lpOrgNameBuf;
3080     serial.unicode = TRUE;
3081     serial.str.w = lpSerialBuf;
3082
3083     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3084                             &org, pcchOrgNameBuf,
3085                             &serial, pcchSerialBuf );
3086 }
3087
3088 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3089                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3090                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3091                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3092 {
3093     awstring user, org, serial;
3094     LPWSTR prod;
3095     UINT r;
3096
3097     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3098         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3099         (lpSerialBuf && !pcchSerialBuf))
3100         return USERINFOSTATE_INVALIDARG;
3101
3102     prod = strdupAtoW( szProduct );
3103     if (szProduct && !prod)
3104         return ERROR_OUTOFMEMORY;
3105
3106     user.unicode = FALSE;
3107     user.str.a = lpUserNameBuf;
3108     org.unicode = FALSE;
3109     org.str.a = lpOrgNameBuf;
3110     serial.unicode = FALSE;
3111     serial.str.a = lpSerialBuf;
3112
3113     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3114                          &org, pcchOrgNameBuf,
3115                          &serial, pcchSerialBuf );
3116
3117     msi_free( prod );
3118
3119     return r;
3120 }
3121
3122 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3123 {
3124     MSIHANDLE handle;
3125     UINT rc;
3126     MSIPACKAGE *package;
3127     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3128
3129     TRACE("(%s)\n",debugstr_w(szProduct));
3130
3131     rc = MsiOpenProductW(szProduct,&handle);
3132     if (rc != ERROR_SUCCESS)
3133         return ERROR_INVALID_PARAMETER;
3134
3135     /* MsiCollectUserInfo cannot be called from a custom action. */
3136     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3137     if (!package)
3138         return ERROR_CALL_NOT_IMPLEMENTED;
3139
3140     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
3141     msiobj_release( &package->hdr );
3142
3143     MsiCloseHandle(handle);
3144
3145     return rc;
3146 }
3147
3148 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3149 {
3150     MSIHANDLE handle;
3151     UINT rc;
3152     MSIPACKAGE *package;
3153     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3154
3155     TRACE("(%s)\n",debugstr_a(szProduct));
3156
3157     rc = MsiOpenProductA(szProduct,&handle);
3158     if (rc != ERROR_SUCCESS)
3159         return ERROR_INVALID_PARAMETER;
3160
3161     /* MsiCollectUserInfo cannot be called from a custom action. */
3162     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3163     if (!package)
3164         return ERROR_CALL_NOT_IMPLEMENTED;
3165
3166     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
3167     msiobj_release( &package->hdr );
3168
3169     MsiCloseHandle(handle);
3170
3171     return rc;
3172 }
3173
3174 /***********************************************************************
3175  * MsiConfigureFeatureA            [MSI.@]
3176  */
3177 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3178 {
3179     LPWSTR prod, feat = NULL;
3180     UINT r = ERROR_OUTOFMEMORY;
3181
3182     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3183
3184     prod = strdupAtoW( szProduct );
3185     if (szProduct && !prod)
3186         goto end;
3187
3188     feat = strdupAtoW( szFeature );
3189     if (szFeature && !feat)
3190         goto end;
3191
3192     r = MsiConfigureFeatureW(prod, feat, eInstallState);
3193
3194 end:
3195     msi_free(feat);
3196     msi_free(prod);
3197
3198     return r;
3199 }
3200
3201 /***********************************************************************
3202  * MsiConfigureFeatureW            [MSI.@]
3203  */
3204 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
3205 {
3206     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
3207     MSIPACKAGE *package = NULL;
3208     UINT r;
3209     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
3210     DWORD sz;
3211
3212     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
3213
3214     if (!szProduct || !szFeature)
3215         return ERROR_INVALID_PARAMETER;
3216
3217     switch (eInstallState)
3218     {
3219     case INSTALLSTATE_DEFAULT:
3220         /* FIXME: how do we figure out the default location? */
3221         eInstallState = INSTALLSTATE_LOCAL;
3222         break;
3223     case INSTALLSTATE_LOCAL:
3224     case INSTALLSTATE_SOURCE:
3225     case INSTALLSTATE_ABSENT:
3226     case INSTALLSTATE_ADVERTISED:
3227         break;
3228     default:
3229         return ERROR_INVALID_PARAMETER;
3230     }
3231
3232     r = MSI_OpenProductW( szProduct, &package );
3233     if (r != ERROR_SUCCESS)
3234         return r;
3235
3236     sz = sizeof(sourcepath);
3237     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3238                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3239
3240     sz = sizeof(filename);
3241     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3242                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3243
3244     lstrcatW( sourcepath, filename );
3245
3246     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
3247
3248     r = ACTION_PerformUIAction( package, szCostInit, -1 );
3249     if (r != ERROR_SUCCESS)
3250         goto end;
3251
3252     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
3253     if (r != ERROR_SUCCESS)
3254         goto end;
3255
3256     r = MSI_InstallPackage( package, sourcepath, NULL );
3257
3258 end:
3259     msiobj_release( &package->hdr );
3260
3261     return r;
3262 }
3263
3264 /***********************************************************************
3265  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
3266  *
3267  * Notes: undocumented
3268  */
3269 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
3270 {
3271     WCHAR path[MAX_PATH];
3272
3273     TRACE("%d\n", dwReserved);
3274
3275     if (dwReserved)
3276     {
3277         FIXME("dwReserved=%d\n", dwReserved);
3278         return ERROR_INVALID_PARAMETER;
3279     }
3280
3281     if (!GetWindowsDirectoryW(path, MAX_PATH))
3282         return ERROR_FUNCTION_FAILED;
3283
3284     lstrcatW(path, installerW);
3285
3286     if (!CreateDirectoryW(path, NULL))
3287         return ERROR_FUNCTION_FAILED;
3288
3289     return ERROR_SUCCESS;
3290 }
3291
3292 /***********************************************************************
3293  * MsiGetShortcutTargetA           [MSI.@]
3294  */
3295 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
3296                                    LPSTR szProductCode, LPSTR szFeatureId,
3297                                    LPSTR szComponentCode )
3298 {
3299     LPWSTR target;
3300     const int len = MAX_FEATURE_CHARS+1;
3301     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
3302     UINT r;
3303
3304     target = strdupAtoW( szShortcutTarget );
3305     if (szShortcutTarget && !target )
3306         return ERROR_OUTOFMEMORY;
3307     product[0] = 0;
3308     feature[0] = 0;
3309     component[0] = 0;
3310     r = MsiGetShortcutTargetW( target, product, feature, component );
3311     msi_free( target );
3312     if (r == ERROR_SUCCESS)
3313     {
3314         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
3315         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
3316         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
3317     }
3318     return r;
3319 }
3320
3321 /***********************************************************************
3322  * MsiGetShortcutTargetW           [MSI.@]
3323  */
3324 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
3325                                    LPWSTR szProductCode, LPWSTR szFeatureId,
3326                                    LPWSTR szComponentCode )
3327 {
3328     IShellLinkDataList *dl = NULL;
3329     IPersistFile *pf = NULL;
3330     LPEXP_DARWIN_LINK darwin = NULL;
3331     HRESULT r, init;
3332
3333     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
3334           szProductCode, szFeatureId, szComponentCode );
3335
3336     init = CoInitialize(NULL);
3337
3338     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3339                           &IID_IPersistFile, (LPVOID*) &pf );
3340     if( SUCCEEDED( r ) )
3341     {
3342         r = IPersistFile_Load( pf, szShortcutTarget,
3343                                STGM_READ | STGM_SHARE_DENY_WRITE );
3344         if( SUCCEEDED( r ) )
3345         {
3346             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
3347                                              (LPVOID*) &dl );
3348             if( SUCCEEDED( r ) )
3349             {
3350                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
3351                                                   (LPVOID) &darwin );
3352                 IShellLinkDataList_Release( dl );
3353             }
3354         }
3355         IPersistFile_Release( pf );
3356     }
3357
3358     if (SUCCEEDED(init))
3359         CoUninitialize();
3360
3361     TRACE("darwin = %p\n", darwin);
3362
3363     if (darwin)
3364     {
3365         DWORD sz;
3366         UINT ret;
3367
3368         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
3369                   szProductCode, szFeatureId, szComponentCode, &sz );
3370         LocalFree( darwin );
3371         return ret;
3372     }
3373
3374     return ERROR_FUNCTION_FAILED;
3375 }
3376
3377 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
3378                                   DWORD dwReinstallMode )
3379 {
3380     MSIPACKAGE* package = NULL;
3381     UINT r;
3382     WCHAR sourcepath[MAX_PATH];
3383     WCHAR filename[MAX_PATH];
3384     static const WCHAR szLogVerbose[] = {
3385         ' ','L','O','G','V','E','R','B','O','S','E',0 };
3386     WCHAR reinstallmode[11];
3387     LPWSTR ptr;
3388     DWORD sz;
3389
3390     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
3391                            dwReinstallMode);
3392
3393     ptr = reinstallmode;
3394
3395     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
3396         *ptr++ = 'p';
3397     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
3398         *ptr++ = 'o';
3399     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
3400         *ptr++ = 'w';
3401     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
3402         *ptr++ = 'd';
3403     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
3404         *ptr++ = 'c';
3405     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
3406         *ptr++ = 'a';
3407     if (dwReinstallMode & REINSTALLMODE_USERDATA)
3408         *ptr++ = 'u';
3409     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
3410         *ptr++ = 'm';
3411     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
3412         *ptr++ = 's';
3413     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3414         *ptr++ = 'v';
3415     *ptr = 0;
3416     
3417     sz = sizeof(sourcepath);
3418     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3419             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3420
3421     sz = sizeof(filename);
3422     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3423             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3424
3425     lstrcatW( sourcepath, filename );
3426
3427     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3428         r = MSI_OpenPackageW( sourcepath, &package );
3429     else
3430         r = MSI_OpenProductW( szProduct, &package );
3431
3432     if (r != ERROR_SUCCESS)
3433         return r;
3434
3435     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
3436     MSI_SetPropertyW( package, szInstalled, szOne );
3437     MSI_SetPropertyW( package, szLogVerbose, szOne );
3438     MSI_SetPropertyW( package, szReinstall, szFeature );
3439
3440     r = MSI_InstallPackage( package, sourcepath, NULL );
3441
3442     msiobj_release( &package->hdr );
3443
3444     return r;
3445 }
3446
3447 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
3448                                   DWORD dwReinstallMode )
3449 {
3450     LPWSTR wszProduct;
3451     LPWSTR wszFeature;
3452     UINT rc;
3453
3454     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
3455                            dwReinstallMode);
3456
3457     wszProduct = strdupAtoW(szProduct);
3458     wszFeature = strdupAtoW(szFeature);
3459
3460     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
3461
3462     msi_free(wszProduct);
3463     msi_free(wszFeature);
3464     return rc;
3465 }
3466
3467 typedef struct
3468 {
3469     unsigned int i[2];
3470     unsigned int buf[4];
3471     unsigned char in[64];
3472     unsigned char digest[16];
3473 } MD5_CTX;
3474
3475 extern VOID WINAPI MD5Init( MD5_CTX *);
3476 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
3477 extern VOID WINAPI MD5Final( MD5_CTX *);
3478
3479 /***********************************************************************
3480  * MsiGetFileHashW            [MSI.@]
3481  */
3482 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
3483                              PMSIFILEHASHINFO pHash )
3484 {
3485     HANDLE handle, mapping;
3486     void *p;
3487     DWORD length;
3488     UINT r = ERROR_FUNCTION_FAILED;
3489
3490     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
3491
3492     if (!szFilePath)
3493         return ERROR_INVALID_PARAMETER;
3494
3495     if (!*szFilePath)
3496         return ERROR_PATH_NOT_FOUND;
3497
3498     if (dwOptions)
3499         return ERROR_INVALID_PARAMETER;
3500     if (!pHash)
3501         return ERROR_INVALID_PARAMETER;
3502     if (pHash->dwFileHashInfoSize < sizeof *pHash)
3503         return ERROR_INVALID_PARAMETER;
3504
3505     handle = CreateFileW( szFilePath, GENERIC_READ,
3506                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
3507     if (handle == INVALID_HANDLE_VALUE)
3508         return ERROR_FILE_NOT_FOUND;
3509
3510     length = GetFileSize( handle, NULL );
3511
3512     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
3513     if (mapping)
3514     {
3515         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
3516         if (p)
3517         {
3518             MD5_CTX ctx;
3519
3520             MD5Init( &ctx );
3521             MD5Update( &ctx, p, length );
3522             MD5Final( &ctx );
3523             UnmapViewOfFile( p );
3524
3525             memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
3526             r = ERROR_SUCCESS;
3527         }
3528         CloseHandle( mapping );
3529     }
3530     CloseHandle( handle );
3531
3532     return r;
3533 }
3534
3535 /***********************************************************************
3536  * MsiGetFileHashA            [MSI.@]
3537  */
3538 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
3539                              PMSIFILEHASHINFO pHash )
3540 {
3541     LPWSTR file;
3542     UINT r;
3543
3544     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
3545
3546     file = strdupAtoW( szFilePath );
3547     if (szFilePath && !file)
3548         return ERROR_OUTOFMEMORY;
3549
3550     r = MsiGetFileHashW( file, dwOptions, pHash );
3551     msi_free( file );
3552     return r;
3553 }
3554
3555 /***********************************************************************
3556  * MsiAdvertiseScriptW        [MSI.@]
3557  */
3558 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
3559                                  PHKEY phRegData, BOOL fRemoveItems )
3560 {
3561     FIXME("%s %08x %p %d\n",
3562           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3563     return ERROR_CALL_NOT_IMPLEMENTED;
3564 }
3565
3566 /***********************************************************************
3567  * MsiAdvertiseScriptA        [MSI.@]
3568  */
3569 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
3570                                  PHKEY phRegData, BOOL fRemoveItems )
3571 {
3572     FIXME("%s %08x %p %d\n",
3573           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3574     return ERROR_CALL_NOT_IMPLEMENTED;
3575 }
3576
3577 /***********************************************************************
3578  * MsiIsProductElevatedW        [MSI.@]
3579  */
3580 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
3581 {
3582     FIXME("%s %p - stub\n",
3583           debugstr_w( szProduct ), pfElevated );
3584     *pfElevated = TRUE;
3585     return ERROR_SUCCESS;
3586 }
3587
3588 /***********************************************************************
3589  * MsiIsProductElevatedA        [MSI.@]
3590  */
3591 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
3592 {
3593     FIXME("%s %p - stub\n",
3594           debugstr_a( szProduct ), pfElevated );
3595     *pfElevated = TRUE;
3596     return ERROR_SUCCESS;
3597 }
3598
3599 /***********************************************************************
3600  * MsiSetExternalUIRecord     [MSI.@]
3601  */
3602 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD handler,
3603                                     DWORD filter, LPVOID context,
3604                                     PINSTALLUI_HANDLER_RECORD prev )
3605 {
3606     TRACE("%p %08x %p %p\n", handler, filter, context, prev);
3607
3608     if (prev)
3609         *prev = gUIHandlerRecord;
3610
3611     gUIHandlerRecord = handler;
3612     gUIFilter        = filter;
3613     gUIContext       = context;
3614
3615     return ERROR_SUCCESS;
3616 }
3617
3618 /***********************************************************************
3619  * MsiInstallMissingComponentW     [MSI.@]
3620  */
3621 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
3622 {
3623     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
3624     return ERROR_SUCCESS;
3625 }