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