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