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