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