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