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