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