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