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