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