msi/tests: Add test for merging string types.
[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 save, 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         save = *pcchValueBuf;
1040
1041         if (strlenW(val) < *pcchValueBuf)
1042             r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
1043         else if (szValue->str.a || szValue->str.w)
1044             r = ERROR_MORE_DATA;
1045
1046         if (!badconfig)
1047             *pcchValueBuf = lstrlenW(val);
1048         else if (r == ERROR_SUCCESS)
1049         {
1050             *pcchValueBuf = save;
1051             r = ERROR_BAD_CONFIGURATION;
1052         }
1053     }
1054     else if (badconfig)
1055         r = ERROR_BAD_CONFIGURATION;
1056
1057     if (val != empty)
1058         msi_free(val);
1059
1060 done:
1061     RegCloseKey(prodkey);
1062     RegCloseKey(userdata);
1063     return r;
1064 }
1065
1066 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
1067                                LPSTR szBuffer, LPDWORD pcchValueBuf)
1068 {
1069     LPWSTR szwProduct, szwAttribute = NULL;
1070     UINT r = ERROR_OUTOFMEMORY;
1071     awstring buffer;
1072
1073     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
1074           szBuffer, pcchValueBuf);
1075
1076     szwProduct = strdupAtoW( szProduct );
1077     if( szProduct && !szwProduct )
1078         goto end;
1079
1080     szwAttribute = strdupAtoW( szAttribute );
1081     if( szAttribute && !szwAttribute )
1082         goto end;
1083
1084     buffer.unicode = FALSE;
1085     buffer.str.a = szBuffer;
1086
1087     r = MSI_GetProductInfo( szwProduct, szwAttribute,
1088                             &buffer, pcchValueBuf );
1089
1090 end:
1091     msi_free( szwProduct );
1092     msi_free( szwAttribute );
1093
1094     return r;
1095 }
1096
1097 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
1098                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
1099 {
1100     awstring buffer;
1101
1102     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
1103           szBuffer, pcchValueBuf);
1104
1105     buffer.unicode = TRUE;
1106     buffer.str.w = szBuffer;
1107
1108     return MSI_GetProductInfo( szProduct, szAttribute,
1109                                &buffer, pcchValueBuf );
1110 }
1111
1112 UINT WINAPI MsiGetProductInfoExA(LPCSTR szProductCode, LPCSTR szUserSid,
1113                                  MSIINSTALLCONTEXT dwContext, LPCSTR szProperty,
1114                                  LPSTR szValue, LPDWORD pcchValue)
1115 {
1116     LPWSTR product = NULL;
1117     LPWSTR usersid = NULL;
1118     LPWSTR property = NULL;
1119     LPWSTR value = NULL;
1120     DWORD len = 0;
1121     UINT r;
1122
1123     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_a(szProductCode),
1124           debugstr_a(szUserSid), dwContext, debugstr_a(szProperty),
1125            szValue, pcchValue);
1126
1127     if (szValue && !pcchValue)
1128         return ERROR_INVALID_PARAMETER;
1129
1130     if (szProductCode) product = strdupAtoW(szProductCode);
1131     if (szUserSid) usersid = strdupAtoW(szUserSid);
1132     if (szProperty) property = strdupAtoW(szProperty);
1133
1134     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1135                              NULL, &len);
1136     if (r != ERROR_SUCCESS)
1137         goto done;
1138
1139     value = msi_alloc(++len * sizeof(WCHAR));
1140     if (!value)
1141     {
1142         r = ERROR_OUTOFMEMORY;
1143         goto done;
1144     }
1145
1146     r = MsiGetProductInfoExW(product, usersid, dwContext, property,
1147                              value, &len);
1148     if (r != ERROR_SUCCESS)
1149         goto done;
1150
1151     if (!pcchValue)
1152         goto done;
1153
1154     len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
1155     if (*pcchValue >= len)
1156         WideCharToMultiByte(CP_ACP, 0, value, -1, szValue, len, NULL, NULL);
1157     else if (szValue)
1158     {
1159         r = ERROR_MORE_DATA;
1160         if (*pcchValue > 0)
1161             *szValue = '\0';
1162     }
1163
1164     if (*pcchValue <= len || !szValue)
1165         len = len * sizeof(WCHAR) - 1;
1166
1167     *pcchValue = len - 1;
1168
1169 done:
1170     msi_free(product);
1171     msi_free(usersid);
1172     msi_free(property);
1173     msi_free(value);
1174
1175     return r;
1176 }
1177
1178 static UINT msi_copy_outval(LPWSTR val, LPWSTR out, LPDWORD size)
1179 {
1180     UINT r;
1181
1182     if (!val)
1183         return ERROR_UNKNOWN_PROPERTY;
1184
1185     if (out)
1186     {
1187         if (strlenW(val) >= *size)
1188         {
1189             r = ERROR_MORE_DATA;
1190             if (*size > 0)
1191                 *out = '\0';
1192         }
1193         else
1194             lstrcpyW(out, val);
1195     }
1196
1197     if (size)
1198         *size = lstrlenW(val);
1199
1200     return ERROR_SUCCESS;
1201 }
1202
1203 UINT WINAPI MsiGetProductInfoExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
1204                                  MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty,
1205                                  LPWSTR szValue, LPDWORD pcchValue)
1206 {
1207     WCHAR squished_pc[GUID_SIZE];
1208     LPWSTR val = NULL;
1209     LPCWSTR package = NULL;
1210     HKEY props = NULL, prod;
1211     HKEY classes = NULL, managed;
1212     HKEY hkey = NULL;
1213     DWORD type;
1214     UINT r = ERROR_UNKNOWN_PRODUCT;
1215
1216     static const WCHAR five[] = {'5',0};
1217     static const WCHAR displayname[] = {
1218         'D','i','s','p','l','a','y','N','a','m','e',0};
1219     static const WCHAR displayversion[] = {
1220         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
1221     static const WCHAR managed_local_package[] = {
1222         'M','a','n','a','g','e','d','L','o','c','a','l',
1223         'P','a','c','k','a','g','e',0};
1224
1225     TRACE("(%s, %s, %d, %s, %p, %p)\n", debugstr_w(szProductCode),
1226           debugstr_w(szUserSid), dwContext, debugstr_w(szProperty),
1227            szValue, pcchValue);
1228
1229     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
1230         return ERROR_INVALID_PARAMETER;
1231
1232     if (szValue && !pcchValue)
1233         return ERROR_INVALID_PARAMETER;
1234
1235     if (dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1236         dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1237         dwContext != MSIINSTALLCONTEXT_MACHINE)
1238         return ERROR_INVALID_PARAMETER;
1239
1240     if (!szProperty || !*szProperty)
1241         return ERROR_INVALID_PARAMETER;
1242
1243     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1244         return ERROR_INVALID_PARAMETER;
1245
1246     /* FIXME: dwContext is provided, no need to search for it */
1247     MSIREG_OpenProductKey(szProductCode, NULL,MSIINSTALLCONTEXT_USERMANAGED,
1248                           &managed, FALSE);
1249     MSIREG_OpenProductKey(szProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1250                           &prod, FALSE);
1251
1252     MSIREG_OpenInstallProps(szProductCode, dwContext, NULL, &props, FALSE);
1253
1254     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1255     {
1256         package = INSTALLPROPERTY_LOCALPACKAGEW;
1257
1258         if (!props && !prod)
1259             goto done;
1260     }
1261     else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1262     {
1263         package = managed_local_package;
1264
1265         if (!props && !managed)
1266             goto done;
1267     }
1268     else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1269     {
1270         package = INSTALLPROPERTY_LOCALPACKAGEW;
1271         MSIREG_OpenProductKey(szProductCode, NULL, dwContext, &classes, FALSE);
1272
1273         if (!props && !classes)
1274             goto done;
1275     }
1276
1277     if (!lstrcmpW(szProperty, INSTALLPROPERTY_HELPLINKW) ||
1278         !lstrcmpW(szProperty, INSTALLPROPERTY_HELPTELEPHONEW) ||
1279         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLDATEW) ||
1280         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
1281         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLLOCATIONW) ||
1282         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLSOURCEW) ||
1283         !lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW) ||
1284         !lstrcmpW(szProperty, INSTALLPROPERTY_PUBLISHERW) ||
1285         !lstrcmpW(szProperty, INSTALLPROPERTY_URLINFOABOUTW) ||
1286         !lstrcmpW(szProperty, INSTALLPROPERTY_URLUPDATEINFOW) ||
1287         !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMINORW) ||
1288         !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONMAJORW) ||
1289         !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW) ||
1290         !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTIDW) ||
1291         !lstrcmpW(szProperty, INSTALLPROPERTY_REGCOMPANYW) ||
1292         !lstrcmpW(szProperty, INSTALLPROPERTY_REGOWNERW) ||
1293         !lstrcmpW(szProperty, INSTALLPROPERTY_INSTANCETYPEW))
1294     {
1295         val = msi_reg_get_value(props, package, &type);
1296         if (!val)
1297         {
1298             if (prod || classes)
1299                 r = ERROR_UNKNOWN_PROPERTY;
1300
1301             goto done;
1302         }
1303
1304         msi_free(val);
1305
1306         if (!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
1307             szProperty = displayname;
1308         else if (!lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONSTRINGW))
1309             szProperty = displayversion;
1310
1311         val = msi_reg_get_value(props, szProperty, &type);
1312         if (!val)
1313             val = strdupW(szEmpty);
1314
1315         r = msi_copy_outval(val, szValue, pcchValue);
1316     }
1317     else if (!lstrcmpW(szProperty, INSTALLPROPERTY_TRANSFORMSW) ||
1318              !lstrcmpW(szProperty, INSTALLPROPERTY_LANGUAGEW) ||
1319              !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTNAMEW) ||
1320              !lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGECODEW) ||
1321              !lstrcmpW(szProperty, INSTALLPROPERTY_VERSIONW) ||
1322              !lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTICONW) ||
1323              !lstrcmpW(szProperty, INSTALLPROPERTY_PACKAGENAMEW) ||
1324              !lstrcmpW(szProperty, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
1325     {
1326         if (!prod && !classes)
1327             goto done;
1328
1329         if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
1330             hkey = prod;
1331         else if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1332             hkey = managed;
1333         else if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1334             hkey = classes;
1335
1336         val = msi_reg_get_value(hkey, szProperty, &type);
1337         if (!val)
1338             val = strdupW(szEmpty);
1339
1340         r = msi_copy_outval(val, szValue, pcchValue);
1341     }
1342     else if (!lstrcmpW(szProperty, INSTALLPROPERTY_PRODUCTSTATEW))
1343     {
1344         if (dwContext == MSIINSTALLCONTEXT_MACHINE)
1345         {
1346             if (props)
1347             {
1348                 val = msi_reg_get_value(props, package, &type);
1349                 if (!val)
1350                     goto done;
1351
1352                 msi_free(val);
1353                 val = strdupW(five);
1354             }
1355             else
1356                 val = strdupW(szOne);
1357
1358             r = msi_copy_outval(val, szValue, pcchValue);
1359             goto done;
1360         }
1361         else if (props && (val = msi_reg_get_value(props, package, &type)))
1362         {
1363             msi_free(val);
1364             val = strdupW(five);
1365             r = msi_copy_outval(val, szValue, pcchValue);
1366             goto done;
1367         }
1368
1369         if (prod || managed)
1370             val = strdupW(szOne);
1371         else
1372             goto done;
1373
1374         r = msi_copy_outval(val, szValue, pcchValue);
1375     }
1376     else if (!lstrcmpW(szProperty, INSTALLPROPERTY_ASSIGNMENTTYPEW))
1377     {
1378         if (!prod && !classes)
1379             goto done;
1380
1381         /* FIXME */
1382         val = strdupW(szEmpty);
1383         r = msi_copy_outval(val, szValue, pcchValue);
1384     }
1385     else
1386         r = ERROR_UNKNOWN_PROPERTY;
1387
1388 done:
1389     RegCloseKey(props);
1390     RegCloseKey(prod);
1391     RegCloseKey(managed);
1392     RegCloseKey(classes);
1393     msi_free(val);
1394
1395     return r;
1396 }
1397
1398 UINT WINAPI MsiGetPatchInfoExA(LPCSTR szPatchCode, LPCSTR szProductCode,
1399                                LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1400                                LPCSTR szProperty, LPSTR lpValue, DWORD *pcchValue)
1401 {
1402     LPWSTR patch = NULL, product = NULL, usersid = NULL;
1403     LPWSTR property = NULL, val = NULL;
1404     DWORD len;
1405     UINT r;
1406
1407     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_a(szPatchCode),
1408           debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext,
1409           debugstr_a(szProperty), lpValue, pcchValue);
1410
1411     if (lpValue && !pcchValue)
1412         return ERROR_INVALID_PARAMETER;
1413
1414     if (szPatchCode) patch = strdupAtoW(szPatchCode);
1415     if (szProductCode) product = strdupAtoW(szProductCode);
1416     if (szUserSid) usersid = strdupAtoW(szUserSid);
1417     if (szProperty) property = strdupAtoW(szProperty);
1418
1419     len = 0;
1420     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1421                            NULL, &len);
1422     if (r != ERROR_SUCCESS)
1423         goto done;
1424
1425     val = msi_alloc(++len * sizeof(WCHAR));
1426     if (!val)
1427     {
1428         r = ERROR_OUTOFMEMORY;
1429         goto done;
1430     }
1431
1432     r = MsiGetPatchInfoExW(patch, product, usersid, dwContext, property,
1433                            val, &len);
1434     if (r != ERROR_SUCCESS || !pcchValue)
1435         goto done;
1436
1437     if (lpValue)
1438         WideCharToMultiByte(CP_ACP, 0, val, -1, lpValue,
1439                             *pcchValue - 1, NULL, NULL);
1440
1441     len = lstrlenW(val);
1442     if ((*val && *pcchValue < len + 1) || !lpValue)
1443     {
1444         if (lpValue)
1445         {
1446             r = ERROR_MORE_DATA;
1447             lpValue[*pcchValue - 1] = '\0';
1448         }
1449
1450         *pcchValue = len * sizeof(WCHAR);
1451     }
1452     else
1453         *pcchValue = len;
1454
1455 done:
1456     msi_free(val);
1457     msi_free(patch);
1458     msi_free(product);
1459     msi_free(usersid);
1460     msi_free(property);
1461
1462     return r;
1463 }
1464
1465 UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
1466                                LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1467                                LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
1468 {
1469     WCHAR squished_pc[GUID_SIZE];
1470     WCHAR squished_patch[GUID_SIZE];
1471     HKEY udprod = 0, prod = 0, props = 0;
1472     HKEY patch = 0, patches = 0;
1473     HKEY udpatch = 0, datakey = 0;
1474     HKEY prodpatches = 0;
1475     LPWSTR val = NULL;
1476     UINT r = ERROR_UNKNOWN_PRODUCT;
1477     DWORD len;
1478     LONG res;
1479
1480     static const WCHAR szManagedPackage[] = {'M','a','n','a','g','e','d',
1481         'L','o','c','a','l','P','a','c','k','a','g','e',0};
1482
1483     TRACE("(%s, %s, %s, %d, %s, %p, %p)\n", debugstr_w(szPatchCode),
1484           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext,
1485           debugstr_w(szProperty), lpValue, pcchValue);
1486
1487     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
1488         return ERROR_INVALID_PARAMETER;
1489
1490     if (!szPatchCode || !squash_guid(szPatchCode, squished_patch))
1491         return ERROR_INVALID_PARAMETER;
1492
1493     if (!szProperty)
1494         return ERROR_INVALID_PARAMETER;
1495
1496     if (lpValue && !pcchValue)
1497         return ERROR_INVALID_PARAMETER;
1498
1499     if (dwContext != MSIINSTALLCONTEXT_USERMANAGED &&
1500         dwContext != MSIINSTALLCONTEXT_USERUNMANAGED &&
1501         dwContext != MSIINSTALLCONTEXT_MACHINE)
1502         return ERROR_INVALID_PARAMETER;
1503
1504     if (dwContext == MSIINSTALLCONTEXT_MACHINE && szUserSid)
1505         return ERROR_INVALID_PARAMETER;
1506
1507     if (!lstrcmpW(szUserSid, szLocalSid))
1508         return ERROR_INVALID_PARAMETER;
1509
1510     if (MSIREG_OpenUserDataProductKey(szProductCode, dwContext, NULL,
1511                                       &udprod, FALSE) != ERROR_SUCCESS)
1512         goto done;
1513
1514     if (MSIREG_OpenInstallProps(szProductCode, dwContext, NULL,
1515                                 &props, FALSE) != ERROR_SUCCESS)
1516         goto done;
1517
1518     r = ERROR_UNKNOWN_PATCH;
1519
1520     res = RegOpenKeyExW(udprod, szPatches, 0, KEY_READ, &patches);
1521     if (res != ERROR_SUCCESS)
1522         goto done;
1523
1524     res = RegOpenKeyExW(patches, squished_patch, 0, KEY_READ, &patch);
1525     if (res != ERROR_SUCCESS)
1526         goto done;
1527
1528     if (!lstrcmpW(szProperty, INSTALLPROPERTY_TRANSFORMSW))
1529     {
1530         if (MSIREG_OpenProductKey(szProductCode, NULL, dwContext,
1531                                   &prod, FALSE) != ERROR_SUCCESS)
1532             goto done;
1533
1534         res = RegOpenKeyExW(prod, szPatches, 0, KEY_ALL_ACCESS, &prodpatches);
1535         if (res != ERROR_SUCCESS)
1536             goto done;
1537
1538         datakey = prodpatches;
1539         szProperty = squished_patch;
1540     }
1541     else
1542     {
1543         if (MSIREG_OpenUserDataPatchKey(szPatchCode, dwContext,
1544                                         &udpatch, FALSE) != ERROR_SUCCESS)
1545             goto done;
1546
1547         if (!lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW))
1548         {
1549             if (dwContext == MSIINSTALLCONTEXT_USERMANAGED)
1550                 szProperty = szManagedPackage;
1551             datakey = udpatch;
1552         }
1553         else if (!lstrcmpW(szProperty, INSTALLPROPERTY_INSTALLDATEW))
1554         {
1555             datakey = patch;
1556             szProperty = szInstalled;
1557         }
1558         else if (!lstrcmpW(szProperty, INSTALLPROPERTY_LOCALPACKAGEW))
1559         {
1560             datakey = udpatch;
1561         }
1562         else if (!lstrcmpW(szProperty, INSTALLPROPERTY_UNINSTALLABLEW) ||
1563                  !lstrcmpW(szProperty, INSTALLPROPERTY_PATCHSTATEW) ||
1564                  !lstrcmpW(szProperty, INSTALLPROPERTY_DISPLAYNAMEW) ||
1565                  !lstrcmpW(szProperty, INSTALLPROPERTY_MOREINFOURLW))
1566         {
1567             datakey = patch;
1568         }
1569         else
1570         {
1571             r = ERROR_UNKNOWN_PROPERTY;
1572             goto done;
1573         }
1574     }
1575
1576     val = msi_reg_get_val_str(datakey, szProperty);
1577     if (!val)
1578         val = strdupW(szEmpty);
1579
1580     r = ERROR_SUCCESS;
1581
1582     if (!pcchValue)
1583         goto done;
1584
1585     if (lpValue)
1586         lstrcpynW(lpValue, val, *pcchValue);
1587
1588     len = lstrlenW(val);
1589     if ((*val && *pcchValue < len + 1) || !lpValue)
1590     {
1591         if (lpValue)
1592             r = ERROR_MORE_DATA;
1593
1594         *pcchValue = len * sizeof(WCHAR);
1595     }
1596
1597     *pcchValue = len;
1598
1599 done:
1600     msi_free(val);
1601     RegCloseKey(prodpatches);
1602     RegCloseKey(prod);
1603     RegCloseKey(patch);
1604     RegCloseKey(patches);
1605     RegCloseKey(udpatch);
1606     RegCloseKey(props);
1607     RegCloseKey(udprod);
1608
1609     return r;
1610 }
1611
1612 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
1613 {
1614     LPWSTR szwLogFile = NULL;
1615     UINT r;
1616
1617     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
1618
1619     if( szLogFile )
1620     {
1621         szwLogFile = strdupAtoW( szLogFile );
1622         if( !szwLogFile )
1623             return ERROR_OUTOFMEMORY;
1624     }
1625     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
1626     msi_free( szwLogFile );
1627     return r;
1628 }
1629
1630 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
1631 {
1632     HANDLE file = INVALID_HANDLE_VALUE;
1633
1634     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
1635
1636     if (szLogFile)
1637     {
1638         lstrcpyW(gszLogFile,szLogFile);
1639         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
1640             DeleteFileW(szLogFile);
1641         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
1642                                FILE_ATTRIBUTE_NORMAL, NULL);
1643         if (file != INVALID_HANDLE_VALUE)
1644             CloseHandle(file);
1645         else
1646             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
1647     }
1648     else
1649         gszLogFile[0] = '\0';
1650
1651     return ERROR_SUCCESS;
1652 }
1653
1654 UINT WINAPI MsiEnumComponentCostsW(MSIHANDLE hInstall, LPCWSTR szComponent,
1655                                    DWORD dwIndex, INSTALLSTATE iState,
1656                                    LPWSTR lpDriveBuf, DWORD *pcchDriveBuf,
1657                                    int *piCost, int *pTempCost)
1658 {
1659     FIXME("(%d, %s, %d, %d, %p, %p, %p %p): stub!\n", hInstall,
1660           debugstr_w(szComponent), dwIndex, iState, lpDriveBuf,
1661           pcchDriveBuf, piCost, pTempCost);
1662
1663     return ERROR_NO_MORE_ITEMS;
1664 }
1665
1666 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
1667                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1668                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
1669 {
1670     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
1671     UINT r;
1672
1673     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
1674           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
1675
1676     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
1677         return ERROR_OUTOFMEMORY;
1678
1679     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
1680             return ERROR_OUTOFMEMORY;
1681
1682     if (szComponent && !(comp = strdupAtoW(szComponent)))
1683             return ERROR_OUTOFMEMORY;
1684
1685     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
1686
1687     msi_free(prodcode);
1688     msi_free(usersid);
1689     msi_free(comp);
1690
1691     return r;
1692 }
1693
1694 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
1695 {
1696     UINT r;
1697     HKEY hkey;
1698
1699     r = MSIREG_OpenProductKey(prodcode, NULL, context, &hkey, FALSE);
1700     RegCloseKey(hkey);
1701     return (r == ERROR_SUCCESS);
1702 }
1703
1704 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
1705 {
1706     LPCWSTR package;
1707     HKEY hkey;
1708     DWORD sz;
1709     LONG res;
1710     UINT r;
1711
1712     static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
1713     static const WCHAR managed_local_package[] = {
1714         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
1715     };
1716
1717     r = MSIREG_OpenInstallProps(prodcode, context, NULL, &hkey, FALSE);
1718     if (r != ERROR_SUCCESS)
1719         return FALSE;
1720
1721     if (context == MSIINSTALLCONTEXT_USERMANAGED)
1722         package = managed_local_package;
1723     else
1724         package = local_package;
1725
1726     sz = 0;
1727     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
1728     RegCloseKey(hkey);
1729
1730     return (res == ERROR_SUCCESS);
1731 }
1732
1733 static BOOL msi_comp_find_prodcode(LPWSTR squished_pc,
1734                                    MSIINSTALLCONTEXT context,
1735                                    LPCWSTR comp, LPWSTR val, DWORD *sz)
1736 {
1737     HKEY hkey;
1738     LONG res;
1739     UINT r;
1740
1741     if (context == MSIINSTALLCONTEXT_MACHINE)
1742         r = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
1743     else
1744         r = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
1745
1746     if (r != ERROR_SUCCESS)
1747         return FALSE;
1748
1749     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, (BYTE *)val, sz);
1750     if (res != ERROR_SUCCESS)
1751         return FALSE;
1752
1753     RegCloseKey(hkey);
1754     return TRUE;
1755 }
1756
1757 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
1758                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
1759                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
1760 {
1761     WCHAR squished_pc[GUID_SIZE];
1762     WCHAR val[MAX_PATH];
1763     BOOL found;
1764     DWORD sz;
1765
1766     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
1767           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
1768
1769     if (!pdwState || !szComponent)
1770         return ERROR_INVALID_PARAMETER;
1771
1772     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
1773         return ERROR_INVALID_PARAMETER;
1774
1775     if (!squash_guid(szProductCode, squished_pc))
1776         return ERROR_INVALID_PARAMETER;
1777
1778     found = msi_comp_find_prod_key(szProductCode, dwContext);
1779
1780     if (!msi_comp_find_package(szProductCode, dwContext))
1781     {
1782         if (found)
1783         {
1784             *pdwState = INSTALLSTATE_UNKNOWN;
1785             return ERROR_UNKNOWN_COMPONENT;
1786         }
1787
1788         return ERROR_UNKNOWN_PRODUCT;
1789     }
1790
1791     *pdwState = INSTALLSTATE_UNKNOWN;
1792
1793     sz = MAX_PATH;
1794     if (!msi_comp_find_prodcode(squished_pc, dwContext, szComponent, val, &sz))
1795         return ERROR_UNKNOWN_COMPONENT;
1796
1797     if (sz == 0)
1798         *pdwState = INSTALLSTATE_NOTUSED;
1799     else
1800     {
1801         if (lstrlenW(val) > 2 &&
1802             val[0] >= '0' && val[0] <= '9' && val[1] >= '0' && val[1] <= '9')
1803         {
1804             *pdwState = INSTALLSTATE_SOURCE;
1805         }
1806         else
1807             *pdwState = INSTALLSTATE_LOCAL;
1808     }
1809
1810     return ERROR_SUCCESS;
1811 }
1812
1813 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
1814 {
1815     LPWSTR szwProduct = NULL;
1816     INSTALLSTATE r;
1817
1818     if( szProduct )
1819     {
1820          szwProduct = strdupAtoW( szProduct );
1821          if( !szwProduct )
1822              return ERROR_OUTOFMEMORY;
1823     }
1824     r = MsiQueryProductStateW( szwProduct );
1825     msi_free( szwProduct );
1826     return r;
1827 }
1828
1829 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
1830 {
1831     MSIINSTALLCONTEXT context = MSIINSTALLCONTEXT_USERUNMANAGED;
1832     INSTALLSTATE state = INSTALLSTATE_ADVERTISED;
1833     HKEY prodkey = 0, userdata = 0;
1834     DWORD val;
1835     UINT r;
1836
1837     static const WCHAR szWindowsInstaller[] = {
1838         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1839
1840     TRACE("%s\n", debugstr_w(szProduct));
1841
1842     if (!szProduct || !*szProduct)
1843         return INSTALLSTATE_INVALIDARG;
1844
1845     if (lstrlenW(szProduct) != GUID_SIZE - 1)
1846         return INSTALLSTATE_INVALIDARG;
1847
1848     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1849                               &prodkey, FALSE) != ERROR_SUCCESS &&
1850         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1851                               &prodkey, FALSE) != ERROR_SUCCESS &&
1852         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
1853                               &prodkey, FALSE) == ERROR_SUCCESS)
1854     {
1855         context = MSIINSTALLCONTEXT_MACHINE;
1856     }
1857
1858     r = MSIREG_OpenInstallProps(szProduct, context, NULL, &userdata, FALSE);
1859     if (r != ERROR_SUCCESS)
1860         goto done;
1861
1862     if (!msi_reg_get_val_dword(userdata, szWindowsInstaller, &val))
1863         goto done;
1864
1865     if (val)
1866         state = INSTALLSTATE_DEFAULT;
1867     else
1868         state = INSTALLSTATE_UNKNOWN;
1869
1870 done:
1871     if (!prodkey)
1872     {
1873         state = INSTALLSTATE_UNKNOWN;
1874
1875         if (userdata)
1876             state = INSTALLSTATE_ABSENT;
1877     }
1878
1879     RegCloseKey(prodkey);
1880     RegCloseKey(userdata);
1881     return state;
1882 }
1883
1884 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
1885 {
1886     INSTALLUILEVEL old = gUILevel;
1887     HWND oldwnd = gUIhwnd;
1888
1889     TRACE("%08x %p\n", dwUILevel, phWnd);
1890
1891     gUILevel = dwUILevel;
1892     if (phWnd)
1893     {
1894         gUIhwnd = *phWnd;
1895         *phWnd = oldwnd;
1896     }
1897     return old;
1898 }
1899
1900 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
1901                                   DWORD dwMessageFilter, LPVOID pvContext)
1902 {
1903     INSTALLUI_HANDLERA prev = gUIHandlerA;
1904
1905     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
1906     gUIHandlerA = puiHandler;
1907     gUIFilter = dwMessageFilter;
1908     gUIContext = pvContext;
1909
1910     return prev;
1911 }
1912
1913 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
1914                                   DWORD dwMessageFilter, LPVOID pvContext)
1915 {
1916     INSTALLUI_HANDLERW prev = gUIHandlerW;
1917
1918     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
1919     gUIHandlerW = puiHandler;
1920     gUIFilter = dwMessageFilter;
1921     gUIContext = pvContext;
1922
1923     return prev;
1924 }
1925
1926 /******************************************************************
1927  *  MsiLoadStringW            [MSI.@]
1928  *
1929  * Loads a string from MSI's string resources.
1930  *
1931  * PARAMS
1932  *
1933  *   handle        [I]  only -1 is handled currently
1934  *   id            [I]  id of the string to be loaded
1935  *   lpBuffer      [O]  buffer for the string to be written to
1936  *   nBufferMax    [I]  maximum size of the buffer in characters
1937  *   lang          [I]  the preferred language for the string
1938  *
1939  * RETURNS
1940  *
1941  *   If successful, this function returns the language id of the string loaded
1942  *   If the function fails, the function returns zero.
1943  *
1944  * NOTES
1945  *
1946  *   The type of the first parameter is unknown.  LoadString's prototype
1947  *  suggests that it might be a module handle.  I have made it an MSI handle
1948  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
1949  *  handle.  Maybe strings can be stored in an MSI database somehow.
1950  */
1951 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
1952                 int nBufferMax, LANGID lang )
1953 {
1954     HRSRC hres;
1955     HGLOBAL hResData;
1956     LPWSTR p;
1957     DWORD i, len;
1958
1959     TRACE("%d %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
1960
1961     if( handle != -1 )
1962         FIXME("don't know how to deal with handle = %08x\n", handle);
1963
1964     if( !lang )
1965         lang = GetUserDefaultLangID();
1966
1967     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
1968                             (LPWSTR)1, lang );
1969     if( !hres )
1970         return 0;
1971     hResData = LoadResource( msi_hInstance, hres );
1972     if( !hResData )
1973         return 0;
1974     p = LockResource( hResData );
1975     if( !p )
1976         return 0;
1977
1978     for (i = 0; i < (id&0xf); i++)
1979         p += *p + 1;
1980     len = *p;
1981
1982     if( nBufferMax <= len )
1983         return 0;
1984
1985     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
1986     lpBuffer[ len ] = 0;
1987
1988     TRACE("found -> %s\n", debugstr_w(lpBuffer));
1989
1990     return lang;
1991 }
1992
1993 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
1994                 int nBufferMax, LANGID lang )
1995 {
1996     LPWSTR bufW;
1997     LANGID r;
1998     INT len;
1999
2000     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
2001     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
2002     if( r )
2003     {
2004         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
2005         if( len <= nBufferMax )
2006             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
2007                                  lpBuffer, nBufferMax, NULL, NULL );
2008         else
2009             r = 0;
2010     }
2011     msi_free(bufW);
2012     return r;
2013 }
2014
2015 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
2016                 LPDWORD pcchBuf)
2017 {
2018     char szProduct[GUID_SIZE];
2019
2020     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
2021
2022     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
2023         return INSTALLSTATE_UNKNOWN;
2024
2025     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
2026 }
2027
2028 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
2029                 LPDWORD pcchBuf)
2030 {
2031     WCHAR szProduct[GUID_SIZE];
2032
2033     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
2034
2035     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
2036         return INSTALLSTATE_UNKNOWN;
2037
2038     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
2039 }
2040
2041 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
2042                 WORD wLanguageId, DWORD f)
2043 {
2044     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
2045           uType, wLanguageId, f);
2046     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
2047 }
2048
2049 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
2050                 WORD wLanguageId, DWORD f)
2051 {
2052     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
2053           uType, wLanguageId, f);
2054     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
2055 }
2056
2057 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
2058                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
2059                 LPDWORD pcchPathBuf )
2060 {
2061     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
2062           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2063           pcchPathBuf);
2064     return ERROR_CALL_NOT_IMPLEMENTED;
2065 }
2066
2067 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
2068                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
2069                 LPDWORD pcchPathBuf )
2070 {
2071     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
2072           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
2073           pcchPathBuf);
2074     return ERROR_CALL_NOT_IMPLEMENTED;
2075 }
2076
2077 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
2078                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2079 {
2080     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
2081     return ERROR_CALL_NOT_IMPLEMENTED;
2082 }
2083
2084 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
2085                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
2086 {
2087     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
2088     return ERROR_CALL_NOT_IMPLEMENTED;
2089 }
2090
2091 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
2092                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
2093                 LPDWORD pcbHashData)
2094 {
2095     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
2096           ppcCertContext, pbHashData, pcbHashData);
2097     return ERROR_CALL_NOT_IMPLEMENTED;
2098 }
2099
2100 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
2101                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
2102                 LPDWORD pcbHashData)
2103 {
2104     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
2105           ppcCertContext, pbHashData, pcbHashData);
2106     return ERROR_CALL_NOT_IMPLEMENTED;
2107 }
2108
2109 /******************************************************************
2110  * MsiGetProductPropertyA      [MSI.@]
2111  */
2112 UINT WINAPI MsiGetProductPropertyA(MSIHANDLE hProduct, LPCSTR szProperty,
2113                                    LPSTR szValue, LPDWORD pccbValue)
2114 {
2115     LPWSTR prop = NULL, val = NULL;
2116     DWORD len;
2117     UINT r;
2118
2119     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_a(szProperty),
2120           szValue, pccbValue);
2121
2122     if (szValue && !pccbValue)
2123         return ERROR_INVALID_PARAMETER;
2124
2125     if (szProperty) prop = strdupAtoW(szProperty);
2126
2127     len = 0;
2128     r = MsiGetProductPropertyW(hProduct, prop, NULL, &len);
2129     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2130         goto done;
2131
2132     if (r == ERROR_SUCCESS)
2133     {
2134         if (szValue) *szValue = '\0';
2135         if (pccbValue) *pccbValue = 0;
2136         goto done;
2137     }
2138
2139     val = msi_alloc(++len * sizeof(WCHAR));
2140     if (!val)
2141     {
2142         r = ERROR_OUTOFMEMORY;
2143         goto done;
2144     }
2145
2146     r = MsiGetProductPropertyW(hProduct, prop, val, &len);
2147     if (r != ERROR_SUCCESS)
2148         goto done;
2149
2150     len = WideCharToMultiByte(CP_ACP, 0, val, -1, NULL, 0, NULL, NULL);
2151
2152     if (szValue)
2153         WideCharToMultiByte(CP_ACP, 0, val, -1, szValue,
2154                             *pccbValue, NULL, NULL);
2155
2156     if (pccbValue)
2157     {
2158         if (len > *pccbValue)
2159             r = ERROR_MORE_DATA;
2160
2161         *pccbValue = len - 1;
2162     }
2163
2164 done:
2165     msi_free(prop);
2166     msi_free(val);
2167
2168     return r;
2169 }
2170
2171 /******************************************************************
2172  * MsiGetProductPropertyW      [MSI.@]
2173  */
2174 UINT WINAPI MsiGetProductPropertyW(MSIHANDLE hProduct, LPCWSTR szProperty,
2175                                    LPWSTR szValue, LPDWORD pccbValue)
2176 {
2177     MSIPACKAGE *package;
2178     MSIQUERY *view = NULL;
2179     MSIRECORD *rec = NULL;
2180     LPCWSTR val;
2181     UINT r;
2182
2183     static const WCHAR query[] = {
2184        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2185        '`','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
2186        '`','P','r','o','p','e','r','t','y','`','=','\'','%','s','\'',0};
2187
2188     TRACE("(%d, %s, %p, %p)\n", hProduct, debugstr_w(szProperty),
2189           szValue, pccbValue);
2190
2191     if (!szProperty)
2192         return ERROR_INVALID_PARAMETER;
2193
2194     if (szValue && !pccbValue)
2195         return ERROR_INVALID_PARAMETER;
2196
2197     package = msihandle2msiinfo(hProduct, MSIHANDLETYPE_PACKAGE);
2198     if (!package)
2199         return ERROR_INVALID_HANDLE;
2200
2201     r = MSI_OpenQuery(package->db, &view, query, szProperty);
2202     if (r != ERROR_SUCCESS)
2203         goto done;
2204
2205     r = MSI_ViewExecute(view, 0);
2206     if (r != ERROR_SUCCESS)
2207         goto done;
2208
2209     r = MSI_ViewFetch(view, &rec);
2210     if (r != ERROR_SUCCESS)
2211         goto done;
2212
2213     val = MSI_RecordGetString(rec, 2);
2214     if (!val)
2215         goto done;
2216
2217     if (lstrlenW(val) >= *pccbValue)
2218     {
2219         lstrcpynW(szValue, val, *pccbValue);
2220         *pccbValue = lstrlenW(val);
2221         r = ERROR_MORE_DATA;
2222     }
2223     else
2224     {
2225         lstrcpyW(szValue, val);
2226         *pccbValue = lstrlenW(val);
2227         r = ERROR_SUCCESS;
2228     }
2229
2230 done:
2231     if (view)
2232     {
2233         MSI_ViewClose(view);
2234         msiobj_release(&view->hdr);
2235         if (rec) msiobj_release(&rec->hdr);
2236     }
2237
2238     if (!rec)
2239     {
2240         if (szValue) *szValue = '\0';
2241         if (pccbValue) *pccbValue = 0;
2242         r = ERROR_SUCCESS;
2243     }
2244
2245     return r;
2246 }
2247
2248 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
2249 {
2250     UINT r;
2251     LPWSTR szPack = NULL;
2252
2253     TRACE("%s\n", debugstr_a(szPackage) );
2254
2255     if( szPackage )
2256     {
2257         szPack = strdupAtoW( szPackage );
2258         if( !szPack )
2259             return ERROR_OUTOFMEMORY;
2260     }
2261
2262     r = MsiVerifyPackageW( szPack );
2263
2264     msi_free( szPack );
2265
2266     return r;
2267 }
2268
2269 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
2270 {
2271     MSIHANDLE handle;
2272     UINT r;
2273
2274     TRACE("%s\n", debugstr_w(szPackage) );
2275
2276     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
2277     MsiCloseHandle( handle );
2278
2279     return r;
2280 }
2281
2282 static INSTALLSTATE MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
2283                                          awstring* lpPathBuf, LPDWORD pcchBuf)
2284 {
2285     WCHAR squished_pc[GUID_SIZE];
2286     WCHAR squished_comp[GUID_SIZE];
2287     HKEY hkey;
2288     LPWSTR path = NULL;
2289     INSTALLSTATE state;
2290     DWORD version;
2291
2292     static const WCHAR wininstaller[] = {
2293         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
2294
2295     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
2296            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
2297
2298     if (!szProduct || !szComponent)
2299         return INSTALLSTATE_INVALIDARG;
2300
2301     if (lpPathBuf->str.w && !pcchBuf)
2302         return INSTALLSTATE_INVALIDARG;
2303
2304     if (!squash_guid(szProduct, squished_pc) ||
2305         !squash_guid(szComponent, squished_comp))
2306         return INSTALLSTATE_INVALIDARG;
2307
2308     state = INSTALLSTATE_UNKNOWN;
2309
2310     if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
2311         MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
2312     {
2313         path = msi_reg_get_val_str(hkey, squished_pc);
2314         RegCloseKey(hkey);
2315
2316         state = INSTALLSTATE_ABSENT;
2317
2318         if ((MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE, NULL,
2319                                      &hkey, FALSE) == ERROR_SUCCESS ||
2320             MSIREG_OpenUserDataProductKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2321                                           NULL, &hkey, FALSE) == ERROR_SUCCESS) &&
2322             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
2323             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2324         {
2325             RegCloseKey(hkey);
2326             state = INSTALLSTATE_LOCAL;
2327         }
2328     }
2329
2330     if (state != INSTALLSTATE_LOCAL &&
2331         (MSIREG_OpenProductKey(szProduct, NULL,
2332                                MSIINSTALLCONTEXT_USERUNMANAGED,
2333                                &hkey, FALSE) == ERROR_SUCCESS ||
2334          MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2335                                &hkey, FALSE) == ERROR_SUCCESS))
2336     {
2337         RegCloseKey(hkey);
2338
2339         if (MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkey, FALSE) == ERROR_SUCCESS ||
2340             MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkey, FALSE) == ERROR_SUCCESS)
2341         {
2342             msi_free(path);
2343             path = msi_reg_get_val_str(hkey, squished_pc);
2344             RegCloseKey(hkey);
2345
2346             state = INSTALLSTATE_ABSENT;
2347
2348             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
2349                 state = INSTALLSTATE_LOCAL;
2350         }
2351     }
2352
2353     if (!path)
2354         return INSTALLSTATE_UNKNOWN;
2355
2356     if (state == INSTALLSTATE_LOCAL && !*path)
2357         state = INSTALLSTATE_NOTUSED;
2358
2359     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
2360     msi_free(path);
2361     return state;
2362 }
2363
2364 /******************************************************************
2365  * MsiGetComponentPathW      [MSI.@]
2366  */
2367 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
2368                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
2369 {
2370     awstring path;
2371
2372     path.unicode = TRUE;
2373     path.str.w = lpPathBuf;
2374
2375     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
2376 }
2377
2378 /******************************************************************
2379  * MsiGetComponentPathA      [MSI.@]
2380  */
2381 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
2382                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
2383 {
2384     LPWSTR szwProduct, szwComponent = NULL;
2385     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
2386     awstring path;
2387
2388     szwProduct = strdupAtoW( szProduct );
2389     if( szProduct && !szwProduct)
2390         goto end;
2391
2392     szwComponent = strdupAtoW( szComponent );
2393     if( szComponent && !szwComponent )
2394         goto end;
2395
2396     path.unicode = FALSE;
2397     path.str.a = lpPathBuf;
2398
2399     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
2400
2401 end:
2402     msi_free( szwProduct );
2403     msi_free( szwComponent );
2404
2405     return r;
2406 }
2407
2408 /******************************************************************
2409  * MsiQueryFeatureStateA      [MSI.@]
2410  */
2411 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
2412 {
2413     LPWSTR szwProduct = NULL, szwFeature= NULL;
2414     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
2415
2416     szwProduct = strdupAtoW( szProduct );
2417     if ( szProduct && !szwProduct )
2418         goto end;
2419
2420     szwFeature = strdupAtoW( szFeature );
2421     if ( szFeature && !szwFeature )
2422         goto end;
2423
2424     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
2425
2426 end:
2427     msi_free( szwProduct);
2428     msi_free( szwFeature);
2429
2430     return rc;
2431 }
2432
2433 /******************************************************************
2434  * MsiQueryFeatureStateW      [MSI.@]
2435  *
2436  * Checks the state of a feature
2437  *
2438  * PARAMS
2439  *   szProduct     [I]  Product's GUID string
2440  *   szFeature     [I]  Feature's GUID string
2441  *
2442  * RETURNS
2443  *   INSTALLSTATE_LOCAL        Feature is installed and usable
2444  *   INSTALLSTATE_ABSENT       Feature is absent
2445  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
2446  *   INSTALLSTATE_UNKNOWN      An error occurred
2447  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
2448  *
2449  */
2450 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
2451 {
2452     WCHAR squishProduct[33], comp[GUID_SIZE];
2453     GUID guid;
2454     LPWSTR components, p, parent_feature, path;
2455     UINT rc;
2456     HKEY hkey;
2457     INSTALLSTATE r;
2458     BOOL missing = FALSE;
2459     BOOL machine = FALSE;
2460     BOOL source = FALSE;
2461
2462     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
2463
2464     if (!szProduct || !szFeature)
2465         return INSTALLSTATE_INVALIDARG;
2466
2467     if (!squash_guid( szProduct, squishProduct ))
2468         return INSTALLSTATE_INVALIDARG;
2469
2470     if (MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERMANAGED,
2471                                &hkey, FALSE) != ERROR_SUCCESS &&
2472         MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2473                                &hkey, FALSE) != ERROR_SUCCESS)
2474     {
2475         rc = MSIREG_OpenFeaturesKey(szProduct, MSIINSTALLCONTEXT_MACHINE,
2476                                     &hkey, FALSE);
2477         if (rc != ERROR_SUCCESS)
2478             return INSTALLSTATE_UNKNOWN;
2479
2480         machine = TRUE;
2481     }
2482
2483     parent_feature = msi_reg_get_val_str( hkey, szFeature );
2484     RegCloseKey(hkey);
2485
2486     if (!parent_feature)
2487         return INSTALLSTATE_UNKNOWN;
2488
2489     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
2490     msi_free(parent_feature);
2491     if (r == INSTALLSTATE_ABSENT)
2492         return r;
2493
2494     if (machine)
2495         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
2496                                             MSIINSTALLCONTEXT_MACHINE,
2497                                             &hkey, FALSE);
2498     else
2499         rc = MSIREG_OpenUserDataFeaturesKey(szProduct,
2500                                             MSIINSTALLCONTEXT_USERUNMANAGED,
2501                                             &hkey, FALSE);
2502
2503     if (rc != ERROR_SUCCESS)
2504         return INSTALLSTATE_ADVERTISED;
2505
2506     components = msi_reg_get_val_str( hkey, szFeature );
2507     RegCloseKey(hkey);
2508
2509     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
2510
2511     if (!components)
2512         return INSTALLSTATE_ADVERTISED;
2513
2514     for( p = components; *p && *p != 2 ; p += 20)
2515     {
2516         if (!decode_base85_guid( p, &guid ))
2517         {
2518             if (p != components)
2519                 break;
2520
2521             msi_free(components);
2522             return INSTALLSTATE_BADCONFIG;
2523         }
2524
2525         StringFromGUID2(&guid, comp, GUID_SIZE);
2526
2527         if (machine)
2528             rc = MSIREG_OpenUserDataComponentKey(comp, szLocalSid, &hkey, FALSE);
2529         else
2530             rc = MSIREG_OpenUserDataComponentKey(comp, NULL, &hkey, FALSE);
2531
2532         if (rc != ERROR_SUCCESS)
2533         {
2534             msi_free(components);
2535             return INSTALLSTATE_ADVERTISED;
2536         }
2537
2538         path = msi_reg_get_val_str(hkey, squishProduct);
2539         if (!path)
2540             missing = TRUE;
2541         else if (lstrlenW(path) > 2 &&
2542                  path[0] >= '0' && path[0] <= '9' &&
2543                  path[1] >= '0' && path[1] <= '9')
2544         {
2545             source = TRUE;
2546         }
2547
2548         msi_free(path);
2549     }
2550
2551     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
2552     msi_free(components);
2553
2554     if (missing)
2555         return INSTALLSTATE_ADVERTISED;
2556
2557     if (source)
2558         return INSTALLSTATE_SOURCE;
2559
2560     return INSTALLSTATE_LOCAL;
2561 }
2562
2563 /******************************************************************
2564  * MsiGetFileVersionA         [MSI.@]
2565  */
2566 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
2567                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
2568 {
2569     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
2570     UINT ret = ERROR_OUTOFMEMORY;
2571
2572     if ((lpVersionBuf && !pcchVersionBuf) ||
2573         (lpLangBuf && !pcchLangBuf))
2574         return ERROR_INVALID_PARAMETER;
2575
2576     if( szFilePath )
2577     {
2578         szwFilePath = strdupAtoW( szFilePath );
2579         if( !szwFilePath )
2580             goto end;
2581     }
2582
2583     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
2584     {
2585         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
2586         if( !lpwVersionBuff )
2587             goto end;
2588     }
2589
2590     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
2591     {
2592         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
2593         if( !lpwLangBuff )
2594             goto end;
2595     }
2596
2597     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
2598                              lpwLangBuff, pcchLangBuf);
2599
2600     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
2601         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
2602                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
2603     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
2604         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
2605                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
2606
2607 end:
2608     msi_free(szwFilePath);
2609     msi_free(lpwVersionBuff);
2610     msi_free(lpwLangBuff);
2611
2612     return ret;
2613 }
2614
2615 /******************************************************************
2616  * MsiGetFileVersionW         [MSI.@]
2617  */
2618 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
2619                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
2620 {
2621     static const WCHAR szVersionResource[] = {'\\',0};
2622     static const WCHAR szVersionFormat[] = {
2623         '%','d','.','%','d','.','%','d','.','%','d',0};
2624     static const WCHAR szLangResource[] = {
2625         '\\','V','a','r','F','i','l','e','I','n','f','o','\\',
2626         'T','r','a','n','s','l','a','t','i','o','n',0};
2627     static const WCHAR szLangFormat[] = {'%','d',0};
2628     UINT ret = 0;
2629     DWORD dwVerLen, gle;
2630     LPVOID lpVer = NULL;
2631     VS_FIXEDFILEINFO *ffi;
2632     USHORT *lang;
2633     UINT puLen;
2634     WCHAR tmp[32];
2635
2636     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
2637           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
2638           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
2639
2640     if ((lpVersionBuf && !pcchVersionBuf) ||
2641         (lpLangBuf && !pcchLangBuf))
2642         return ERROR_INVALID_PARAMETER;
2643
2644     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
2645     if( !dwVerLen )
2646     {
2647         gle = GetLastError();
2648         if (gle == ERROR_BAD_PATHNAME)
2649             return ERROR_FILE_NOT_FOUND;
2650         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
2651             return ERROR_FILE_INVALID;
2652
2653         return gle;
2654     }
2655
2656     lpVer = msi_alloc(dwVerLen);
2657     if( !lpVer )
2658     {
2659         ret = ERROR_OUTOFMEMORY;
2660         goto end;
2661     }
2662
2663     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
2664     {
2665         ret = GetLastError();
2666         goto end;
2667     }
2668
2669     if (pcchVersionBuf)
2670     {
2671         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
2672             (puLen > 0) )
2673         {
2674             wsprintfW(tmp, szVersionFormat,
2675                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
2676                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
2677             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
2678
2679             if (strlenW(tmp) >= *pcchVersionBuf)
2680                 ret = ERROR_MORE_DATA;
2681
2682             *pcchVersionBuf = lstrlenW(tmp);
2683         }
2684         else
2685         {
2686             if (lpVersionBuf) *lpVersionBuf = 0;
2687             *pcchVersionBuf = 0;
2688         }
2689     }
2690
2691     if (pcchLangBuf)
2692     {
2693         if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
2694             (puLen > 0))
2695         {
2696             wsprintfW(tmp, szLangFormat, *lang);
2697             if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
2698
2699             if (strlenW(tmp) >= *pcchLangBuf)
2700                 ret = ERROR_MORE_DATA;
2701
2702             *pcchLangBuf = lstrlenW(tmp);
2703         }
2704         else
2705         {
2706             if (lpLangBuf) *lpLangBuf = 0;
2707             *pcchLangBuf = 0;
2708         }
2709     }
2710
2711 end:
2712     msi_free(lpVer);
2713     return ret;
2714 }
2715
2716 /***********************************************************************
2717  * MsiGetFeatureUsageW           [MSI.@]
2718  */
2719 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
2720                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2721 {
2722     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
2723           pdwUseCount, pwDateUsed);
2724     return ERROR_CALL_NOT_IMPLEMENTED;
2725 }
2726
2727 /***********************************************************************
2728  * MsiGetFeatureUsageA           [MSI.@]
2729  */
2730 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
2731                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
2732 {
2733     LPWSTR prod = NULL, feat = NULL;
2734     UINT ret = ERROR_OUTOFMEMORY;
2735
2736     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
2737           pdwUseCount, pwDateUsed);
2738
2739     prod = strdupAtoW( szProduct );
2740     if (szProduct && !prod)
2741         goto end;
2742
2743     feat = strdupAtoW( szFeature );
2744     if (szFeature && !feat)
2745         goto end;
2746
2747     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
2748
2749 end:
2750     msi_free( prod );
2751     msi_free( feat );
2752
2753     return ret;
2754 }
2755
2756 /***********************************************************************
2757  * MsiUseFeatureExW           [MSI.@]
2758  */
2759 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
2760                                       DWORD dwInstallMode, DWORD dwReserved )
2761 {
2762     INSTALLSTATE state;
2763
2764     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2765           dwInstallMode, dwReserved);
2766
2767     state = MsiQueryFeatureStateW( szProduct, szFeature );
2768
2769     if (dwReserved)
2770         return INSTALLSTATE_INVALIDARG;
2771
2772     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
2773     {
2774         FIXME("mark product %s feature %s as used\n",
2775               debugstr_w(szProduct), debugstr_w(szFeature) );
2776     }
2777
2778     return state;
2779 }
2780
2781 /***********************************************************************
2782  * MsiUseFeatureExA           [MSI.@]
2783  */
2784 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
2785                                       DWORD dwInstallMode, DWORD dwReserved )
2786 {
2787     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
2788     LPWSTR prod = NULL, feat = NULL;
2789
2790     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2791           dwInstallMode, dwReserved);
2792
2793     prod = strdupAtoW( szProduct );
2794     if (szProduct && !prod)
2795         goto end;
2796
2797     feat = strdupAtoW( szFeature );
2798     if (szFeature && !feat)
2799         goto end;
2800
2801     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
2802
2803 end:
2804     msi_free( prod );
2805     msi_free( feat );
2806
2807     return ret;
2808 }
2809
2810 /***********************************************************************
2811  * MsiUseFeatureW             [MSI.@]
2812  */
2813 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
2814 {
2815     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
2816 }
2817
2818 /***********************************************************************
2819  * MsiUseFeatureA             [MSI.@]
2820  */
2821 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
2822 {
2823     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
2824 }
2825
2826 /***********************************************************************
2827  * MSI_ProvideQualifiedComponentEx [internal]
2828  */
2829 static UINT MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
2830                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2831                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
2832                 LPDWORD pcchPathBuf)
2833 {
2834     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
2835           feature[MAX_FEATURE_CHARS+1];
2836     LPWSTR info;
2837     HKEY hkey;
2838     DWORD sz;
2839     UINT rc;
2840
2841     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
2842           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
2843           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2844
2845     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
2846     if (rc != ERROR_SUCCESS)
2847         return ERROR_INDEX_ABSENT;
2848
2849     info = msi_reg_get_val_str( hkey, szQualifier );
2850     RegCloseKey(hkey);
2851
2852     if (!info)
2853         return ERROR_INDEX_ABSENT;
2854
2855     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
2856
2857     if (!szProduct)
2858         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
2859     else
2860         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
2861
2862     msi_free( info );
2863
2864     if (rc != INSTALLSTATE_LOCAL)
2865         return ERROR_FILE_NOT_FOUND;
2866
2867     return ERROR_SUCCESS;
2868 }
2869
2870 /***********************************************************************
2871  * MsiProvideQualifiedComponentExW [MSI.@]
2872  */
2873 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
2874                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
2875                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
2876                 LPDWORD pcchPathBuf)
2877 {
2878     awstring path;
2879
2880     path.unicode = TRUE;
2881     path.str.w = lpPathBuf;
2882
2883     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
2884             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
2885 }
2886
2887 /***********************************************************************
2888  * MsiProvideQualifiedComponentExA [MSI.@]
2889  */
2890 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
2891                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
2892                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
2893                 LPDWORD pcchPathBuf)
2894 {
2895     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
2896     UINT r = ERROR_OUTOFMEMORY;
2897     awstring path;
2898
2899     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
2900           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
2901           Unused1, Unused2, lpPathBuf, pcchPathBuf);
2902
2903     szwComponent = strdupAtoW( szComponent );
2904     if (szComponent && !szwComponent)
2905         goto end;
2906
2907     szwQualifier = strdupAtoW( szQualifier );
2908     if (szQualifier && !szwQualifier)
2909         goto end;
2910
2911     szwProduct = strdupAtoW( szProduct );
2912     if (szProduct && !szwProduct)
2913         goto end;
2914
2915     path.unicode = FALSE;
2916     path.str.a = lpPathBuf;
2917
2918     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
2919                               dwInstallMode, szwProduct, Unused1,
2920                               Unused2, &path, pcchPathBuf);
2921 end:
2922     msi_free(szwProduct);
2923     msi_free(szwComponent);
2924     msi_free(szwQualifier);
2925
2926     return r;
2927 }
2928
2929 /***********************************************************************
2930  * MsiProvideQualifiedComponentW [MSI.@]
2931  */
2932 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
2933                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
2934                 LPDWORD pcchPathBuf)
2935 {
2936     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
2937                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2938 }
2939
2940 /***********************************************************************
2941  * MsiProvideQualifiedComponentA [MSI.@]
2942  */
2943 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
2944                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
2945                 LPDWORD pcchPathBuf)
2946 {
2947     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
2948                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
2949 }
2950
2951 /***********************************************************************
2952  * MSI_GetUserInfo [internal]
2953  */
2954 static USERINFOSTATE MSI_GetUserInfo(LPCWSTR szProduct,
2955                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
2956                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2957                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
2958 {
2959     WCHAR squished_pc[SQUISH_GUID_SIZE];
2960     LPWSTR user, org, serial;
2961     USERINFOSTATE state;
2962     HKEY hkey, props;
2963     LPCWSTR orgptr;
2964     UINT r;
2965
2966     TRACE("%s %p %p %p %p %p %p\n", debugstr_w(szProduct), lpUserNameBuf,
2967           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
2968           pcchSerialBuf);
2969
2970     if (!szProduct || !squash_guid(szProduct, squished_pc))
2971         return USERINFOSTATE_INVALIDARG;
2972
2973     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2974                               &hkey, FALSE) != ERROR_SUCCESS &&
2975         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2976                               &hkey, FALSE) != ERROR_SUCCESS &&
2977         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2978                               &hkey, FALSE) != ERROR_SUCCESS)
2979     {
2980         return USERINFOSTATE_UNKNOWN;
2981     }
2982
2983     if (MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_USERUNMANAGED,
2984                                 NULL, &props, FALSE) != ERROR_SUCCESS &&
2985         MSIREG_OpenInstallProps(szProduct, MSIINSTALLCONTEXT_MACHINE,
2986                                 NULL, &props, FALSE) != ERROR_SUCCESS)
2987     {
2988         RegCloseKey(hkey);
2989         return USERINFOSTATE_ABSENT;
2990     }
2991
2992     user = msi_reg_get_val_str(props, INSTALLPROPERTY_REGOWNERW);
2993     org = msi_reg_get_val_str(props, INSTALLPROPERTY_REGCOMPANYW);
2994     serial = msi_reg_get_val_str(props, INSTALLPROPERTY_PRODUCTIDW);
2995     state = USERINFOSTATE_ABSENT;
2996
2997     RegCloseKey(hkey);
2998     RegCloseKey(props);
2999
3000     if (user && serial)
3001         state = USERINFOSTATE_PRESENT;
3002
3003     if (pcchUserNameBuf)
3004     {
3005         if (lpUserNameBuf && !user)
3006         {
3007             (*pcchUserNameBuf)--;
3008             goto done;
3009         }
3010
3011         r = msi_strcpy_to_awstring(user, lpUserNameBuf, pcchUserNameBuf);
3012         if (r == ERROR_MORE_DATA)
3013         {
3014             state = USERINFOSTATE_MOREDATA;
3015             goto done;
3016         }
3017     }
3018
3019     if (pcchOrgNameBuf)
3020     {
3021         orgptr = org;
3022         if (!orgptr) orgptr = szEmpty;
3023
3024         r = msi_strcpy_to_awstring(orgptr, lpOrgNameBuf, pcchOrgNameBuf);
3025         if (r == ERROR_MORE_DATA)
3026         {
3027             state = USERINFOSTATE_MOREDATA;
3028             goto done;
3029         }
3030     }
3031
3032     if (pcchSerialBuf)
3033     {
3034         if (!serial)
3035         {
3036             (*pcchSerialBuf)--;
3037             goto done;
3038         }
3039
3040         r = msi_strcpy_to_awstring(serial, lpSerialBuf, pcchSerialBuf);
3041         if (r == ERROR_MORE_DATA)
3042             state = USERINFOSTATE_MOREDATA;
3043     }
3044
3045 done:
3046     msi_free(user);
3047     msi_free(org);
3048     msi_free(serial);
3049
3050     return state;
3051 }
3052
3053 /***********************************************************************
3054  * MsiGetUserInfoW [MSI.@]
3055  */
3056 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
3057                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3058                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3059                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3060 {
3061     awstring user, org, serial;
3062
3063     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3064         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3065         (lpSerialBuf && !pcchSerialBuf))
3066         return USERINFOSTATE_INVALIDARG;
3067
3068     user.unicode = TRUE;
3069     user.str.w = lpUserNameBuf;
3070     org.unicode = TRUE;
3071     org.str.w = lpOrgNameBuf;
3072     serial.unicode = TRUE;
3073     serial.str.w = lpSerialBuf;
3074
3075     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
3076                             &org, pcchOrgNameBuf,
3077                             &serial, pcchSerialBuf );
3078 }
3079
3080 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
3081                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
3082                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
3083                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
3084 {
3085     awstring user, org, serial;
3086     LPWSTR prod;
3087     UINT r;
3088
3089     if ((lpUserNameBuf && !pcchUserNameBuf) ||
3090         (lpOrgNameBuf && !pcchOrgNameBuf) ||
3091         (lpSerialBuf && !pcchSerialBuf))
3092         return USERINFOSTATE_INVALIDARG;
3093
3094     prod = strdupAtoW( szProduct );
3095     if (szProduct && !prod)
3096         return ERROR_OUTOFMEMORY;
3097
3098     user.unicode = FALSE;
3099     user.str.a = lpUserNameBuf;
3100     org.unicode = FALSE;
3101     org.str.a = lpOrgNameBuf;
3102     serial.unicode = FALSE;
3103     serial.str.a = lpSerialBuf;
3104
3105     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
3106                          &org, pcchOrgNameBuf,
3107                          &serial, pcchSerialBuf );
3108
3109     msi_free( prod );
3110
3111     return r;
3112 }
3113
3114 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
3115 {
3116     MSIHANDLE handle;
3117     UINT rc;
3118     MSIPACKAGE *package;
3119     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3120
3121     TRACE("(%s)\n",debugstr_w(szProduct));
3122
3123     rc = MsiOpenProductW(szProduct,&handle);
3124     if (rc != ERROR_SUCCESS)
3125         return ERROR_INVALID_PARAMETER;
3126
3127     /* MsiCollectUserInfo cannot be called from a custom action. */
3128     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3129     if (!package)
3130         return ERROR_CALL_NOT_IMPLEMENTED;
3131
3132     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
3133     msiobj_release( &package->hdr );
3134
3135     MsiCloseHandle(handle);
3136
3137     return rc;
3138 }
3139
3140 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
3141 {
3142     MSIHANDLE handle;
3143     UINT rc;
3144     MSIPACKAGE *package;
3145     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
3146
3147     TRACE("(%s)\n",debugstr_a(szProduct));
3148
3149     rc = MsiOpenProductA(szProduct,&handle);
3150     if (rc != ERROR_SUCCESS)
3151         return ERROR_INVALID_PARAMETER;
3152
3153     /* MsiCollectUserInfo cannot be called from a custom action. */
3154     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
3155     if (!package)
3156         return ERROR_CALL_NOT_IMPLEMENTED;
3157
3158     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
3159     msiobj_release( &package->hdr );
3160
3161     MsiCloseHandle(handle);
3162
3163     return rc;
3164 }
3165
3166 /***********************************************************************
3167  * MsiConfigureFeatureA            [MSI.@]
3168  */
3169 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
3170 {
3171     LPWSTR prod, feat = NULL;
3172     UINT r = ERROR_OUTOFMEMORY;
3173
3174     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
3175
3176     prod = strdupAtoW( szProduct );
3177     if (szProduct && !prod)
3178         goto end;
3179
3180     feat = strdupAtoW( szFeature );
3181     if (szFeature && !feat)
3182         goto end;
3183
3184     r = MsiConfigureFeatureW(prod, feat, eInstallState);
3185
3186 end:
3187     msi_free(feat);
3188     msi_free(prod);
3189
3190     return r;
3191 }
3192
3193 /***********************************************************************
3194  * MsiConfigureFeatureW            [MSI.@]
3195  */
3196 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
3197 {
3198     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
3199     MSIPACKAGE *package = NULL;
3200     UINT r;
3201     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
3202     DWORD sz;
3203
3204     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
3205
3206     if (!szProduct || !szFeature)
3207         return ERROR_INVALID_PARAMETER;
3208
3209     switch (eInstallState)
3210     {
3211     case INSTALLSTATE_DEFAULT:
3212         /* FIXME: how do we figure out the default location? */
3213         eInstallState = INSTALLSTATE_LOCAL;
3214         break;
3215     case INSTALLSTATE_LOCAL:
3216     case INSTALLSTATE_SOURCE:
3217     case INSTALLSTATE_ABSENT:
3218     case INSTALLSTATE_ADVERTISED:
3219         break;
3220     default:
3221         return ERROR_INVALID_PARAMETER;
3222     }
3223
3224     r = MSI_OpenProductW( szProduct, &package );
3225     if (r != ERROR_SUCCESS)
3226         return r;
3227
3228     sz = sizeof(sourcepath);
3229     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3230                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3231
3232     sz = sizeof(filename);
3233     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3234                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3235
3236     lstrcatW( sourcepath, filename );
3237
3238     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
3239
3240     r = ACTION_PerformUIAction( package, szCostInit, -1 );
3241     if (r != ERROR_SUCCESS)
3242         goto end;
3243
3244     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
3245     if (r != ERROR_SUCCESS)
3246         goto end;
3247
3248     r = MSI_InstallPackage( package, sourcepath, NULL );
3249
3250 end:
3251     msiobj_release( &package->hdr );
3252
3253     return r;
3254 }
3255
3256 /***********************************************************************
3257  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
3258  *
3259  * Notes: undocumented
3260  */
3261 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
3262 {
3263     WCHAR path[MAX_PATH];
3264
3265     TRACE("%d\n", dwReserved);
3266
3267     if (dwReserved)
3268     {
3269         FIXME("dwReserved=%d\n", dwReserved);
3270         return ERROR_INVALID_PARAMETER;
3271     }
3272
3273     if (!GetWindowsDirectoryW(path, MAX_PATH))
3274         return ERROR_FUNCTION_FAILED;
3275
3276     lstrcatW(path, installerW);
3277
3278     if (!CreateDirectoryW(path, NULL))
3279         return ERROR_FUNCTION_FAILED;
3280
3281     return ERROR_SUCCESS;
3282 }
3283
3284 /***********************************************************************
3285  * MsiGetShortcutTargetA           [MSI.@]
3286  */
3287 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
3288                                    LPSTR szProductCode, LPSTR szFeatureId,
3289                                    LPSTR szComponentCode )
3290 {
3291     LPWSTR target;
3292     const int len = MAX_FEATURE_CHARS+1;
3293     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
3294     UINT r;
3295
3296     target = strdupAtoW( szShortcutTarget );
3297     if (szShortcutTarget && !target )
3298         return ERROR_OUTOFMEMORY;
3299     product[0] = 0;
3300     feature[0] = 0;
3301     component[0] = 0;
3302     r = MsiGetShortcutTargetW( target, product, feature, component );
3303     msi_free( target );
3304     if (r == ERROR_SUCCESS)
3305     {
3306         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
3307         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
3308         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
3309     }
3310     return r;
3311 }
3312
3313 /***********************************************************************
3314  * MsiGetShortcutTargetW           [MSI.@]
3315  */
3316 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
3317                                    LPWSTR szProductCode, LPWSTR szFeatureId,
3318                                    LPWSTR szComponentCode )
3319 {
3320     IShellLinkDataList *dl = NULL;
3321     IPersistFile *pf = NULL;
3322     LPEXP_DARWIN_LINK darwin = NULL;
3323     HRESULT r, init;
3324
3325     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
3326           szProductCode, szFeatureId, szComponentCode );
3327
3328     init = CoInitialize(NULL);
3329
3330     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3331                           &IID_IPersistFile, (LPVOID*) &pf );
3332     if( SUCCEEDED( r ) )
3333     {
3334         r = IPersistFile_Load( pf, szShortcutTarget,
3335                                STGM_READ | STGM_SHARE_DENY_WRITE );
3336         if( SUCCEEDED( r ) )
3337         {
3338             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
3339                                              (LPVOID*) &dl );
3340             if( SUCCEEDED( r ) )
3341             {
3342                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
3343                                                   (LPVOID) &darwin );
3344                 IShellLinkDataList_Release( dl );
3345             }
3346         }
3347         IPersistFile_Release( pf );
3348     }
3349
3350     if (SUCCEEDED(init))
3351         CoUninitialize();
3352
3353     TRACE("darwin = %p\n", darwin);
3354
3355     if (darwin)
3356     {
3357         DWORD sz;
3358         UINT ret;
3359
3360         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
3361                   szProductCode, szFeatureId, szComponentCode, &sz );
3362         LocalFree( darwin );
3363         return ret;
3364     }
3365
3366     return ERROR_FUNCTION_FAILED;
3367 }
3368
3369 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
3370                                   DWORD dwReinstallMode )
3371 {
3372     MSIPACKAGE* package = NULL;
3373     UINT r;
3374     WCHAR sourcepath[MAX_PATH];
3375     WCHAR filename[MAX_PATH];
3376     static const WCHAR szLogVerbose[] = {
3377         ' ','L','O','G','V','E','R','B','O','S','E',0 };
3378     WCHAR reinstallmode[11];
3379     LPWSTR ptr;
3380     DWORD sz;
3381
3382     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
3383                            dwReinstallMode);
3384
3385     ptr = reinstallmode;
3386
3387     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
3388         *ptr++ = 'p';
3389     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
3390         *ptr++ = 'o';
3391     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
3392         *ptr++ = 'w';
3393     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
3394         *ptr++ = 'd';
3395     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
3396         *ptr++ = 'c';
3397     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
3398         *ptr++ = 'a';
3399     if (dwReinstallMode & REINSTALLMODE_USERDATA)
3400         *ptr++ = 'u';
3401     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
3402         *ptr++ = 'm';
3403     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
3404         *ptr++ = 's';
3405     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3406         *ptr++ = 'v';
3407     *ptr = 0;
3408     
3409     sz = sizeof(sourcepath);
3410     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3411             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
3412
3413     sz = sizeof(filename);
3414     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
3415             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
3416
3417     lstrcatW( sourcepath, filename );
3418
3419     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
3420         r = MSI_OpenPackageW( sourcepath, &package );
3421     else
3422         r = MSI_OpenProductW( szProduct, &package );
3423
3424     if (r != ERROR_SUCCESS)
3425         return r;
3426
3427     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
3428     MSI_SetPropertyW( package, szInstalled, szOne );
3429     MSI_SetPropertyW( package, szLogVerbose, szOne );
3430     MSI_SetPropertyW( package, szReinstall, szFeature );
3431
3432     r = MSI_InstallPackage( package, sourcepath, NULL );
3433
3434     msiobj_release( &package->hdr );
3435
3436     return r;
3437 }
3438
3439 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
3440                                   DWORD dwReinstallMode )
3441 {
3442     LPWSTR wszProduct;
3443     LPWSTR wszFeature;
3444     UINT rc;
3445
3446     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
3447                            dwReinstallMode);
3448
3449     wszProduct = strdupAtoW(szProduct);
3450     wszFeature = strdupAtoW(szFeature);
3451
3452     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
3453
3454     msi_free(wszProduct);
3455     msi_free(wszFeature);
3456     return rc;
3457 }
3458
3459 typedef struct
3460 {
3461     unsigned int i[2];
3462     unsigned int buf[4];
3463     unsigned char in[64];
3464     unsigned char digest[16];
3465 } MD5_CTX;
3466
3467 extern VOID WINAPI MD5Init( MD5_CTX *);
3468 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
3469 extern VOID WINAPI MD5Final( MD5_CTX *);
3470
3471 /***********************************************************************
3472  * MsiGetFileHashW            [MSI.@]
3473  */
3474 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
3475                              PMSIFILEHASHINFO pHash )
3476 {
3477     HANDLE handle, mapping;
3478     void *p;
3479     DWORD length;
3480     UINT r = ERROR_FUNCTION_FAILED;
3481
3482     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
3483
3484     if (!szFilePath)
3485         return ERROR_INVALID_PARAMETER;
3486
3487     if (!*szFilePath)
3488         return ERROR_PATH_NOT_FOUND;
3489
3490     if (dwOptions)
3491         return ERROR_INVALID_PARAMETER;
3492     if (!pHash)
3493         return ERROR_INVALID_PARAMETER;
3494     if (pHash->dwFileHashInfoSize < sizeof *pHash)
3495         return ERROR_INVALID_PARAMETER;
3496
3497     handle = CreateFileW( szFilePath, GENERIC_READ,
3498                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
3499     if (handle == INVALID_HANDLE_VALUE)
3500         return ERROR_FILE_NOT_FOUND;
3501
3502     length = GetFileSize( handle, NULL );
3503
3504     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
3505     if (mapping)
3506     {
3507         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
3508         if (p)
3509         {
3510             MD5_CTX ctx;
3511
3512             MD5Init( &ctx );
3513             MD5Update( &ctx, p, length );
3514             MD5Final( &ctx );
3515             UnmapViewOfFile( p );
3516
3517             memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
3518             r = ERROR_SUCCESS;
3519         }
3520         CloseHandle( mapping );
3521     }
3522     CloseHandle( handle );
3523
3524     return r;
3525 }
3526
3527 /***********************************************************************
3528  * MsiGetFileHashA            [MSI.@]
3529  */
3530 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
3531                              PMSIFILEHASHINFO pHash )
3532 {
3533     LPWSTR file;
3534     UINT r;
3535
3536     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
3537
3538     file = strdupAtoW( szFilePath );
3539     if (szFilePath && !file)
3540         return ERROR_OUTOFMEMORY;
3541
3542     r = MsiGetFileHashW( file, dwOptions, pHash );
3543     msi_free( file );
3544     return r;
3545 }
3546
3547 /***********************************************************************
3548  * MsiAdvertiseScriptW        [MSI.@]
3549  */
3550 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
3551                                  PHKEY phRegData, BOOL fRemoveItems )
3552 {
3553     FIXME("%s %08x %p %d\n",
3554           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3555     return ERROR_CALL_NOT_IMPLEMENTED;
3556 }
3557
3558 /***********************************************************************
3559  * MsiAdvertiseScriptA        [MSI.@]
3560  */
3561 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
3562                                  PHKEY phRegData, BOOL fRemoveItems )
3563 {
3564     FIXME("%s %08x %p %d\n",
3565           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
3566     return ERROR_CALL_NOT_IMPLEMENTED;
3567 }
3568
3569 /***********************************************************************
3570  * MsiIsProductElevatedW        [MSI.@]
3571  */
3572 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
3573 {
3574     FIXME("%s %p - stub\n",
3575           debugstr_w( szProduct ), pfElevated );
3576     *pfElevated = TRUE;
3577     return ERROR_SUCCESS;
3578 }
3579
3580 /***********************************************************************
3581  * MsiIsProductElevatedA        [MSI.@]
3582  */
3583 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
3584 {
3585     FIXME("%s %p - stub\n",
3586           debugstr_a( szProduct ), pfElevated );
3587     *pfElevated = TRUE;
3588     return ERROR_SUCCESS;
3589 }
3590
3591 /***********************************************************************
3592  * MsiSetExternalUIRecord     [MSI.@]
3593  */
3594 UINT WINAPI MsiSetExternalUIRecord( INSTALLUI_HANDLER_RECORD puiHandler,
3595                                     DWORD dwMessageFilter, LPVOID pvContext,
3596                                     PINSTALLUI_HANDLER_RECORD ppuiPrevHandler)
3597 {
3598     FIXME("%p %08x %p %p\n", puiHandler, dwMessageFilter ,pvContext,
3599                              ppuiPrevHandler);
3600     return ERROR_CALL_NOT_IMPLEMENTED;
3601 }
3602
3603 /***********************************************************************
3604  * MsiInstallMissingComponentW     [MSI.@]
3605  */
3606 UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, INSTALLSTATE eInstallState)
3607 {
3608     FIXME("(%s %s %d\n", debugstr_w(szProduct), debugstr_w(szComponent), eInstallState);
3609     return ERROR_SUCCESS;
3610 }