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