user32: Simplify the window structure creation. Get rid of the unused clsStyle field.
[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 "wine/debug.h"
32 #include "msi.h"
33 #include "msidefs.h"
34 #include "msiquery.h"
35 #include "msipriv.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 "wine/unicode.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(msi);
45
46 static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
47
48 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
49 {
50     UINT r;
51     LPWSTR szwProd = NULL;
52
53     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
54
55     if( szProduct )
56     {
57         szwProd = strdupAtoW( szProduct );
58         if( !szwProd )
59             return ERROR_OUTOFMEMORY;
60     }
61
62     r = MsiOpenProductW( szwProd, phProduct );
63
64     msi_free( szwProd );
65
66     return r;
67 }
68
69 static UINT MSI_OpenProductW( LPCWSTR szProduct, MSIPACKAGE **ppackage )
70 {
71     LPWSTR path = NULL;
72     UINT r;
73     HKEY hKeyProduct = NULL;
74     DWORD count, type;
75
76     TRACE("%s %p\n", debugstr_w(szProduct), ppackage );
77
78     r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE);
79     if( r != ERROR_SUCCESS )
80     {
81         r = ERROR_UNKNOWN_PRODUCT;
82         goto end;
83     }
84
85     /* find the size of the path */
86     type = count = 0;
87     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
88                           NULL, &type, NULL, &count );
89     if( r != ERROR_SUCCESS )
90     {
91         r = ERROR_UNKNOWN_PRODUCT;
92         goto end;
93     }
94
95     /* now alloc and fetch the path of the database to open */
96     path = msi_alloc( count );
97     if( !path )
98         goto end;
99
100     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
101                           NULL, &type, (LPBYTE) path, &count );
102     if( r != ERROR_SUCCESS )
103     {
104         r = ERROR_UNKNOWN_PRODUCT;
105         goto end;
106     }
107
108     r = MSI_OpenPackageW( path, ppackage );
109
110 end:
111     msi_free( path );
112     if( hKeyProduct )
113         RegCloseKey( hKeyProduct );
114
115     return r;
116 }
117
118 UINT WINAPI MsiOpenProductW( LPCWSTR szProduct, MSIHANDLE *phProduct )
119 {
120    MSIPACKAGE *package = NULL;
121    UINT r;
122
123    r = MSI_OpenProductW( szProduct, &package );
124    if( r == ERROR_SUCCESS )
125    {
126        *phProduct = alloc_msihandle( &package->hdr );
127        if (! *phProduct)
128            r = ERROR_NOT_ENOUGH_MEMORY;
129        msiobj_release( &package->hdr );
130    }
131    return r;
132 }
133
134 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
135                 LPCSTR szTransforms, LANGID lgidLanguage)
136 {
137     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
138           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
139     return ERROR_CALL_NOT_IMPLEMENTED;
140 }
141
142 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
143                 LPCWSTR szTransforms, LANGID lgidLanguage)
144 {
145     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
146           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
147     return ERROR_CALL_NOT_IMPLEMENTED;
148 }
149
150 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
151       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
152 {
153     FIXME("%s %s %s %08x %08x %08x\n", debugstr_a(szPackagePath),
154           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
155           lgidLanguage, dwPlatform, dwOptions);
156     return ERROR_CALL_NOT_IMPLEMENTED;
157 }
158
159 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
160       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
161 {
162     FIXME("%s %s %s %08x %08x %08x\n", debugstr_w(szPackagePath),
163           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
164           lgidLanguage, dwPlatform, dwOptions);
165     return ERROR_CALL_NOT_IMPLEMENTED;
166 }
167
168 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
169 {
170     LPWSTR szwPath = NULL, szwCommand = NULL;
171     UINT r = ERROR_OUTOFMEMORY;
172
173     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
174
175     if( szPackagePath )
176     {
177         szwPath = strdupAtoW( szPackagePath );
178         if( !szwPath )
179             goto end;
180     }
181
182     if( szCommandLine )
183     {
184         szwCommand = strdupAtoW( szCommandLine );
185         if( !szwCommand )
186             goto end;
187     }
188
189     r = MsiInstallProductW( szwPath, szwCommand );
190
191 end:
192     msi_free( szwPath );
193     msi_free( szwCommand );
194
195     return r;
196 }
197
198 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
199 {
200     MSIPACKAGE *package = NULL;
201     UINT r;
202
203     TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
204
205     r = MSI_OpenPackageW( szPackagePath, &package );
206     if (r == ERROR_SUCCESS)
207     {
208         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
209         msiobj_release( &package->hdr );
210     }
211
212     return r;
213 }
214
215 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
216 {
217     FIXME("%s %08x\n", debugstr_a(szProduct), dwReinstallMode);
218     return ERROR_CALL_NOT_IMPLEMENTED;
219 }
220
221 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
222 {
223     FIXME("%s %08x\n", debugstr_w(szProduct), dwReinstallMode);
224     return ERROR_CALL_NOT_IMPLEMENTED;
225 }
226
227 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
228         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
229 {
230     LPWSTR patch_package = NULL;
231     LPWSTR install_package = NULL;
232     LPWSTR command_line = NULL;
233     UINT r = ERROR_OUTOFMEMORY;
234
235     TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
236           eInstallType, debugstr_a(szCommandLine));
237
238     if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage)))
239         goto done;
240
241     if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage)))
242         goto done;
243
244     if (szCommandLine && !(command_line = strdupAtoW(szCommandLine)))
245         goto done;
246
247     r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line);
248
249 done:
250     msi_free(patch_package);
251     msi_free(install_package);
252     msi_free(command_line);
253
254     return r;
255 }
256
257 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
258          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
259 {
260     MSIHANDLE patch, info;
261     UINT r, type;
262     DWORD size = 0;
263     LPCWSTR cmd_ptr = szCommandLine;
264     LPWSTR beg, end;
265     LPWSTR cmd = NULL, codes = NULL;
266
267     static const WCHAR space[] = {' ',0};
268     static const WCHAR patcheq[] = {'P','A','T','C','H','=',0};
269     static WCHAR empty[] = {0};
270
271     TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
272           eInstallType, debugstr_w(szCommandLine));
273
274     if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE ||
275         eInstallType == INSTALLTYPE_SINGLE_INSTANCE)
276     {
277         FIXME("Only reading target products from patch\n");
278         return ERROR_CALL_NOT_IMPLEMENTED;
279     }
280
281     r = MsiOpenDatabaseW(szPatchPackage, MSIDBOPEN_READONLY, &patch);
282     if (r != ERROR_SUCCESS)
283         return r;
284
285     r = MsiGetSummaryInformationW(patch, NULL, 0, &info);
286     if (r != ERROR_SUCCESS)
287         goto done;
288
289     r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, empty, &size);
290     if (r != ERROR_MORE_DATA || !size || type != VT_LPSTR)
291     {
292         ERR("Failed to read product codes from patch\n");
293         goto done;
294     }
295
296     codes = msi_alloc(++size * sizeof(WCHAR));
297     if (!codes)
298     {
299         r = ERROR_OUTOFMEMORY;
300         goto done;
301     }
302
303     r = MsiSummaryInfoGetPropertyW(info, PID_TEMPLATE, &type, NULL, NULL, codes, &size);
304     if (r != ERROR_SUCCESS)
305         goto done;
306
307     if (!szCommandLine)
308         cmd_ptr = empty;
309
310     size = lstrlenW(cmd_ptr) + lstrlenW(patcheq) + lstrlenW(szPatchPackage) + 1;
311     cmd = msi_alloc(size * sizeof(WCHAR));
312     if (!cmd)
313     {
314         r = ERROR_OUTOFMEMORY;
315         goto done;
316     }
317
318     lstrcpyW(cmd, cmd_ptr);
319     if (szCommandLine) lstrcatW(cmd, space);
320     lstrcatW(cmd, patcheq);
321     lstrcatW(cmd, szPatchPackage);
322
323     beg = codes;
324     while ((end = strchrW(beg, '}')))
325     {
326         *(end + 1) = '\0';
327
328         r = MsiConfigureProductExW(beg, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd);
329         if (r != ERROR_SUCCESS)
330             goto done;
331
332         beg = end + 2;
333     }
334
335 done:
336     msi_free(cmd);
337     msi_free(codes);
338
339     MsiCloseHandle(info);
340     MsiCloseHandle(patch);
341
342     return r;
343 }
344
345 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
346                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
347 {
348     MSIPACKAGE* package = NULL;
349     UINT r;
350     DWORD sz;
351     WCHAR sourcepath[MAX_PATH];
352     WCHAR filename[MAX_PATH];
353     static const WCHAR szInstalled[] = {
354         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
355     LPWSTR commandline;
356
357     TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
358           debugstr_w(szCommandLine));
359
360     if (eInstallState != INSTALLSTATE_LOCAL &&
361         eInstallState != INSTALLSTATE_DEFAULT)
362     {
363         FIXME("Not implemented for anything other than local installs\n");
364         return ERROR_CALL_NOT_IMPLEMENTED;
365     }
366
367     sz = sizeof(sourcepath);
368     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
369             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
370             &sz);
371
372     sz = sizeof(filename);
373     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
374             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
375
376     lstrcatW(sourcepath,filename);
377
378     /*
379      * ok 1, we need to find the msi file for this product.
380      *    2, find the source dir for the files
381      *    3, do the configure/install.
382      *    4, cleanupany runonce entry.
383      */
384
385     r = MSI_OpenProductW( szProduct, &package );
386     if (r != ERROR_SUCCESS)
387         return r;
388
389     sz = lstrlenW(szInstalled) + 1;
390
391     if (szCommandLine)
392         sz += lstrlenW(szCommandLine);
393
394     commandline = msi_alloc(sz * sizeof(WCHAR));
395     if (!commandline )
396     {
397         r = ERROR_OUTOFMEMORY;
398         goto end;
399     }
400
401     commandline[0] = 0;
402     if (szCommandLine)
403         lstrcpyW(commandline,szCommandLine);
404
405     if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN)
406         lstrcatW(commandline,szInstalled);
407
408     r = MSI_InstallPackage( package, sourcepath, commandline );
409
410     msi_free(commandline);
411
412 end:
413     msiobj_release( &package->hdr );
414
415     return r;
416 }
417
418 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
419                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
420 {
421     LPWSTR szwProduct = NULL;
422     LPWSTR szwCommandLine = NULL;
423     UINT r = ERROR_OUTOFMEMORY;
424
425     if( szProduct )
426     {
427         szwProduct = strdupAtoW( szProduct );
428         if( !szwProduct )
429             goto end;
430     }
431
432     if( szCommandLine)
433     {
434         szwCommandLine = strdupAtoW( szCommandLine );
435         if( !szwCommandLine)
436             goto end;
437     }
438
439     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
440                                 szwCommandLine );
441 end:
442     msi_free( szwProduct );
443     msi_free( szwCommandLine);
444
445     return r;
446 }
447
448 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
449                                  INSTALLSTATE eInstallState)
450 {
451     LPWSTR szwProduct = NULL;
452     UINT r;
453
454     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
455
456     if( szProduct )
457     {
458         szwProduct = strdupAtoW( szProduct );
459         if( !szwProduct )
460             return ERROR_OUTOFMEMORY;
461     }
462
463     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
464     msi_free( szwProduct );
465
466     return r;
467 }
468
469 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
470                                  INSTALLSTATE eInstallState)
471 {
472     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
473 }
474
475 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
476 {
477     LPWSTR szwComponent = NULL;
478     UINT r;
479     WCHAR szwBuffer[GUID_SIZE];
480
481     TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
482
483     if( szComponent )
484     {
485         szwComponent = strdupAtoW( szComponent );
486         if( !szwComponent )
487             return ERROR_OUTOFMEMORY;
488     }
489
490     *szwBuffer = '\0';
491     r = MsiGetProductCodeW( szwComponent, szwBuffer );
492
493     if(*szwBuffer)
494         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
495
496     msi_free( szwComponent );
497
498     return r;
499 }
500
501 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
502 {
503     UINT rc, index;
504     HKEY compkey, prodkey;
505     WCHAR squished_comp[GUID_SIZE];
506     WCHAR squished_prod[GUID_SIZE];
507     DWORD sz = GUID_SIZE;
508
509     TRACE("%s %p\n", debugstr_w(szComponent), szBuffer);
510
511     if (!szComponent || !*szComponent)
512         return ERROR_INVALID_PARAMETER;
513
514     if (!squash_guid(szComponent, squished_comp))
515         return ERROR_INVALID_PARAMETER;
516
517     if (MSIREG_OpenUserDataComponentKey(szComponent, &compkey, FALSE) != ERROR_SUCCESS &&
518         MSIREG_OpenLocalSystemComponentKey(szComponent, &compkey, FALSE) != ERROR_SUCCESS)
519     {
520         return ERROR_UNKNOWN_COMPONENT;
521     }
522
523     rc = RegEnumValueW(compkey, 0, squished_prod, &sz, NULL, NULL, NULL, NULL);
524     if (rc != ERROR_SUCCESS)
525     {
526         RegCloseKey(compkey);
527         return ERROR_UNKNOWN_COMPONENT;
528     }
529
530     /* check simple case, only one product */
531     rc = RegEnumValueW(compkey, 1, squished_prod, &sz, NULL, NULL, NULL, NULL);
532     if (rc == ERROR_NO_MORE_ITEMS)
533     {
534         rc = ERROR_SUCCESS;
535         goto done;
536     }
537
538     index = 0;
539     while ((rc = RegEnumValueW(compkey, index, squished_prod, &sz,
540            NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS)
541     {
542         index++;
543         sz = GUID_SIZE;
544         unsquash_guid(squished_prod, szBuffer);
545
546         if (MSIREG_OpenLocalManagedProductKey(szBuffer, &prodkey, FALSE) == ERROR_SUCCESS ||
547             MSIREG_OpenUserProductsKey(szBuffer, &prodkey, FALSE) == ERROR_SUCCESS ||
548             MSIREG_OpenLocalClassesProductKey(szBuffer, &prodkey, FALSE) == ERROR_SUCCESS)
549         {
550             RegCloseKey(prodkey);
551             rc = ERROR_SUCCESS;
552             goto done;
553         }
554     }
555
556     rc = ERROR_INSTALL_FAILURE;
557
558 done:
559     RegCloseKey(compkey);
560     unsquash_guid(squished_prod, szBuffer);
561     return rc;
562 }
563
564 static LPWSTR msi_reg_get_value(HKEY hkey, LPCWSTR name, DWORD *type)
565 {
566     DWORD dval;
567     LONG res;
568     WCHAR temp[20];
569
570     static const WCHAR format[] = {'%','d',0};
571
572     res = RegQueryValueExW(hkey, name, NULL, type, NULL, NULL);
573     if (res != ERROR_SUCCESS)
574         return NULL;
575
576     if (*type == REG_SZ)
577         return msi_reg_get_val_str(hkey, name);
578
579     if (!msi_reg_get_val_dword(hkey, name, &dval))
580         return NULL;
581
582     sprintfW(temp, format, dval);
583     return strdupW(temp);
584 }
585
586 static UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
587                                       awstring *szValue, LPDWORD pcchValueBuf)
588 {
589     UINT r = ERROR_UNKNOWN_PROPERTY;
590     HKEY prodkey, userdata, source;
591     LPWSTR val = NULL;
592     WCHAR squished_pc[GUID_SIZE];
593     WCHAR packagecode[GUID_SIZE];
594     BOOL classes = FALSE;
595     BOOL badconfig = FALSE;
596     LONG res;
597     DWORD save, type;
598
599     static WCHAR empty[] = {0};
600     static const WCHAR sourcelist[] = {
601         'S','o','u','r','c','e','L','i','s','t',0};
602     static const WCHAR display_name[] = {
603         'D','i','s','p','l','a','y','N','a','m','e',0};
604     static const WCHAR display_version[] = {
605         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
606     static const WCHAR assignment[] = {
607         'A','s','s','i','g','n','m','e','n','t',0};
608
609     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
610           debugstr_w(szAttribute), szValue, pcchValueBuf);
611
612     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
613         return ERROR_INVALID_PARAMETER;
614
615     if (!squash_guid(szProduct, squished_pc))
616         return ERROR_INVALID_PARAMETER;
617
618     r = MSIREG_OpenLocalManagedProductKey(szProduct, &prodkey, FALSE);
619     if (r != ERROR_SUCCESS)
620     {
621         r = MSIREG_OpenUserProductsKey(szProduct, &prodkey, FALSE);
622         if (r != ERROR_SUCCESS)
623         {
624             r = MSIREG_OpenLocalClassesProductKey(szProduct, &prodkey, FALSE);
625             if (r == ERROR_SUCCESS)
626                 classes = TRUE;
627         }
628     }
629
630     if (classes)
631         MSIREG_OpenLocalSystemProductKey(szProduct, &userdata, FALSE);
632     else
633         MSIREG_OpenInstallPropertiesKey(szProduct, &userdata, FALSE);
634
635     if (!lstrcmpW(szAttribute, INSTALLPROPERTY_HELPLINKW) ||
636         !lstrcmpW(szAttribute, INSTALLPROPERTY_HELPTELEPHONEW) ||
637         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLDATEW) ||
638         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
639         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW) ||
640         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLSOURCEW) ||
641         !lstrcmpW(szAttribute, INSTALLPROPERTY_LOCALPACKAGEW) ||
642         !lstrcmpW(szAttribute, INSTALLPROPERTY_PUBLISHERW) ||
643         !lstrcmpW(szAttribute, INSTALLPROPERTY_URLINFOABOUTW) ||
644         !lstrcmpW(szAttribute, INSTALLPROPERTY_URLUPDATEINFOW) ||
645         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMINORW) ||
646         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMAJORW) ||
647         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW) ||
648         !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTIDW) ||
649         !lstrcmpW(szAttribute, INSTALLPROPERTY_REGCOMPANYW) ||
650         !lstrcmpW(szAttribute, INSTALLPROPERTY_REGOWNERW))
651     {
652         if (!prodkey)
653         {
654             r = ERROR_UNKNOWN_PRODUCT;
655             goto done;
656         }
657
658         if (!userdata)
659             return ERROR_UNKNOWN_PROPERTY;
660
661         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
662             szAttribute = display_name;
663         else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW))
664             szAttribute = display_version;
665
666         val = msi_reg_get_value(userdata, szAttribute, &type);
667         if (!val)
668             val = empty;
669     }
670     else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTANCETYPEW) ||
671              !lstrcmpW(szAttribute, INSTALLPROPERTY_TRANSFORMSW) ||
672              !lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
673              !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW) ||
674              !lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW) ||
675              !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW) ||
676              !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW) ||
677              !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTICONW) ||
678              !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW) ||
679              !lstrcmpW(szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
680     {
681         if (!prodkey)
682         {
683             r = ERROR_UNKNOWN_PRODUCT;
684             goto done;
685         }
686
687         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
688             szAttribute = assignment;
689
690         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW))
691         {
692             res = RegOpenKeyW(prodkey, sourcelist, &source);
693             if (res == ERROR_SUCCESS)
694                 val = msi_reg_get_value(source, szAttribute, &type);
695
696             RegCloseKey(source);
697         }
698         else
699         {
700             val = msi_reg_get_value(prodkey, szAttribute, &type);
701             if (!val)
702                 val = empty;
703         }
704
705         if (val != empty && type != REG_DWORD &&
706             !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
707         {
708             if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
709                 badconfig = TRUE;
710             else
711             {
712                 unsquash_guid(val, packagecode);
713                 msi_free(val);
714                 val = strdupW(packagecode);
715             }
716         }
717     }
718
719     if (!val)
720     {
721         r = ERROR_UNKNOWN_PROPERTY;
722         goto done;
723     }
724
725     save = *pcchValueBuf;
726
727     if (lstrlenW(val) < *pcchValueBuf)
728         r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
729     else if (szValue->str.a || szValue->str.w)
730         r = ERROR_MORE_DATA;
731
732     if (!badconfig)
733         *pcchValueBuf = lstrlenW(val);
734     else if (r == ERROR_SUCCESS)
735     {
736         *pcchValueBuf = save;
737         r = ERROR_BAD_CONFIGURATION;
738     }
739
740     if (val != empty)
741         msi_free(val);
742
743 done:
744     RegCloseKey(prodkey);
745     RegCloseKey(userdata);
746     return r;
747 }
748
749 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
750                                LPSTR szBuffer, LPDWORD pcchValueBuf)
751 {
752     LPWSTR szwProduct, szwAttribute = NULL;
753     UINT r = ERROR_OUTOFMEMORY;
754     awstring buffer;
755
756     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
757           szBuffer, pcchValueBuf);
758
759     szwProduct = strdupAtoW( szProduct );
760     if( szProduct && !szwProduct )
761         goto end;
762
763     szwAttribute = strdupAtoW( szAttribute );
764     if( szAttribute && !szwAttribute )
765         goto end;
766
767     buffer.unicode = FALSE;
768     buffer.str.a = szBuffer;
769
770     r = MSI_GetProductInfo( szwProduct, szwAttribute,
771                             &buffer, pcchValueBuf );
772
773 end:
774     msi_free( szwProduct );
775     msi_free( szwAttribute );
776
777     return r;
778 }
779
780 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
781                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
782 {
783     awstring buffer;
784
785     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
786           szBuffer, pcchValueBuf);
787
788     buffer.unicode = TRUE;
789     buffer.str.w = szBuffer;
790
791     return MSI_GetProductInfo( szProduct, szAttribute,
792                                &buffer, pcchValueBuf );
793 }
794
795 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
796 {
797     LPWSTR szwLogFile = NULL;
798     UINT r;
799
800     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
801
802     if( szLogFile )
803     {
804         szwLogFile = strdupAtoW( szLogFile );
805         if( !szwLogFile )
806             return ERROR_OUTOFMEMORY;
807     }
808     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
809     msi_free( szwLogFile );
810     return r;
811 }
812
813 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
814 {
815     HANDLE file = INVALID_HANDLE_VALUE;
816
817     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
818
819     if (szLogFile)
820     {
821         lstrcpyW(gszLogFile,szLogFile);
822         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
823             DeleteFileW(szLogFile);
824         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
825                                FILE_ATTRIBUTE_NORMAL, NULL);
826         if (file != INVALID_HANDLE_VALUE)
827             CloseHandle(file);
828         else
829             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
830     }
831     else
832         gszLogFile[0] = '\0';
833
834     return ERROR_SUCCESS;
835 }
836
837 UINT WINAPI MsiEnumComponentCostsW(MSIHANDLE hInstall, LPCWSTR szComponent,
838                                    DWORD dwIndex, INSTALLSTATE iState,
839                                    LPWSTR lpDriveBuf, DWORD *pcchDriveBuf,
840                                    int *piCost, int *pTempCost)
841 {
842     FIXME("(%ld, %s, %d, %d, %p, %p, %p %p): stub!\n", hInstall,
843           debugstr_w(szComponent), dwIndex, iState, lpDriveBuf,
844           pcchDriveBuf, piCost, pTempCost);
845
846     return ERROR_NO_MORE_ITEMS;
847 }
848
849 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
850                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
851                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
852 {
853     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
854     UINT r;
855
856     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
857           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
858
859     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
860         return ERROR_OUTOFMEMORY;
861
862     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
863             return ERROR_OUTOFMEMORY;
864
865     if (szComponent && !(comp = strdupAtoW(szComponent)))
866             return ERROR_OUTOFMEMORY;
867
868     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
869
870     msi_free(prodcode);
871     msi_free(usersid);
872     msi_free(comp);
873
874     return r;
875 }
876
877 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
878 {
879     UINT r;
880     HKEY hkey;
881
882     if (context == MSIINSTALLCONTEXT_MACHINE)
883         r = MSIREG_OpenLocalClassesProductKey(prodcode, &hkey, FALSE);
884     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
885         r = MSIREG_OpenUserProductsKey(prodcode, &hkey, FALSE);
886     else
887         r = MSIREG_OpenLocalManagedProductKey(prodcode, &hkey, FALSE);
888
889     RegCloseKey(hkey);
890     return (r == ERROR_SUCCESS);
891 }
892
893 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
894 {
895     LPCWSTR package;
896     HKEY hkey;
897     DWORD sz;
898     LONG res;
899     UINT r;
900
901     static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
902     static const WCHAR managed_local_package[] = {
903         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
904     };
905
906     if (context == MSIINSTALLCONTEXT_MACHINE)
907         r = MSIREG_OpenLocalSystemProductKey(prodcode, &hkey, FALSE);
908     else
909         r = MSIREG_OpenInstallPropertiesKey(prodcode, &hkey, FALSE);
910
911     if (r != ERROR_SUCCESS)
912         return FALSE;
913
914     if (context == MSIINSTALLCONTEXT_USERMANAGED)
915         package = managed_local_package;
916     else
917         package = local_package;
918
919     sz = 0;
920     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
921     RegCloseKey(hkey);
922
923     return (res == ERROR_SUCCESS);
924 }
925
926 static BOOL msi_comp_find_prodcode(LPWSTR squished_pc,
927                                    MSIINSTALLCONTEXT context,
928                                    LPCWSTR comp, DWORD *sz)
929 {
930     HKEY hkey;
931     LONG res;
932     UINT r;
933
934     if (context == MSIINSTALLCONTEXT_MACHINE)
935         r = MSIREG_OpenLocalSystemComponentKey(comp, &hkey, FALSE);
936     else
937         r = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
938
939     if (r != ERROR_SUCCESS)
940         return FALSE;
941
942     *sz = 0;
943     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, NULL, sz);
944     if (res != ERROR_SUCCESS)
945         return FALSE;
946
947     RegCloseKey(hkey);
948     return TRUE;
949 }
950
951 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
952                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
953                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
954 {
955     WCHAR squished_pc[GUID_SIZE];
956     BOOL found;
957     DWORD sz;
958
959     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
960           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
961
962     if (!pdwState)
963         return ERROR_INVALID_PARAMETER;
964
965     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
966         return ERROR_INVALID_PARAMETER;
967
968     if (!squash_guid(szProductCode, squished_pc))
969         return ERROR_INVALID_PARAMETER;
970
971     found = msi_comp_find_prod_key(szProductCode, dwContext);
972
973     if (!msi_comp_find_package(szProductCode, dwContext))
974     {
975         if (found)
976         {
977             *pdwState = INSTALLSTATE_UNKNOWN;
978             return ERROR_UNKNOWN_COMPONENT;
979         }
980
981         return ERROR_UNKNOWN_PRODUCT;
982     }
983
984     *pdwState = INSTALLSTATE_UNKNOWN;
985
986     if (!msi_comp_find_prodcode(squished_pc, dwContext, szComponent, &sz))
987         return ERROR_UNKNOWN_COMPONENT;
988
989     if (sz == 0)
990         *pdwState = INSTALLSTATE_NOTUSED;
991     else
992         *pdwState = INSTALLSTATE_LOCAL;
993
994     return ERROR_SUCCESS;
995 }
996
997 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
998 {
999     LPWSTR szwProduct = NULL;
1000     INSTALLSTATE r;
1001
1002     if( szProduct )
1003     {
1004          szwProduct = strdupAtoW( szProduct );
1005          if( !szwProduct )
1006              return ERROR_OUTOFMEMORY;
1007     }
1008     r = MsiQueryProductStateW( szwProduct );
1009     msi_free( szwProduct );
1010     return r;
1011 }
1012
1013 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
1014 {
1015     UINT rc;
1016     INSTALLSTATE state = INSTALLSTATE_UNKNOWN;
1017     HKEY hkey = 0, props = 0;
1018     DWORD sz;
1019     BOOL userkey_exists = FALSE;
1020
1021     static const int GUID_LEN = 38;
1022     static const WCHAR szInstallProperties[] = {
1023             'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0
1024     };
1025     static const WCHAR szWindowsInstaller[] = {
1026             'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0
1027     };
1028
1029     TRACE("%s\n", debugstr_w(szProduct));
1030
1031     if (!szProduct || !*szProduct || lstrlenW(szProduct) != GUID_LEN)
1032         return INSTALLSTATE_INVALIDARG;
1033
1034     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
1035     if (rc == ERROR_SUCCESS)
1036     {
1037         userkey_exists = TRUE;
1038         state = INSTALLSTATE_ADVERTISED;
1039         RegCloseKey(hkey);
1040     }
1041
1042     rc = MSIREG_OpenUserDataProductKey(szProduct,&hkey,FALSE);
1043     if (rc != ERROR_SUCCESS)
1044         goto end;
1045
1046     rc = RegOpenKeyW(hkey, szInstallProperties, &props);
1047     if (rc != ERROR_SUCCESS)
1048         goto end;
1049
1050     sz = sizeof(state);
1051     rc = RegQueryValueExW(props,szWindowsInstaller,NULL,NULL,(LPVOID)&state, &sz);
1052     if (rc != ERROR_SUCCESS)
1053         goto end;
1054
1055     if (state)
1056         state = INSTALLSTATE_DEFAULT;
1057     else
1058         state = INSTALLSTATE_UNKNOWN;
1059
1060     if (state == INSTALLSTATE_DEFAULT && !userkey_exists)
1061         state = INSTALLSTATE_ABSENT;
1062
1063 end:
1064     RegCloseKey(props);
1065     RegCloseKey(hkey);
1066     return state;
1067 }
1068
1069 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
1070 {
1071     INSTALLUILEVEL old = gUILevel;
1072     HWND oldwnd = gUIhwnd;
1073
1074     TRACE("%08x %p\n", dwUILevel, phWnd);
1075
1076     gUILevel = dwUILevel;
1077     if (phWnd)
1078     {
1079         gUIhwnd = *phWnd;
1080         *phWnd = oldwnd;
1081     }
1082     return old;
1083 }
1084
1085 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
1086                                   DWORD dwMessageFilter, LPVOID pvContext)
1087 {
1088     INSTALLUI_HANDLERA prev = gUIHandlerA;
1089
1090     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
1091     gUIHandlerA = puiHandler;
1092     gUIFilter = dwMessageFilter;
1093     gUIContext = pvContext;
1094
1095     return prev;
1096 }
1097
1098 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
1099                                   DWORD dwMessageFilter, LPVOID pvContext)
1100 {
1101     INSTALLUI_HANDLERW prev = gUIHandlerW;
1102
1103     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
1104     gUIHandlerW = puiHandler;
1105     gUIFilter = dwMessageFilter;
1106     gUIContext = pvContext;
1107
1108     return prev;
1109 }
1110
1111 /******************************************************************
1112  *  MsiLoadStringW            [MSI.@]
1113  *
1114  * Loads a string from MSI's string resources.
1115  *
1116  * PARAMS
1117  *
1118  *   handle        [I]  only -1 is handled currently
1119  *   id            [I]  id of the string to be loaded
1120  *   lpBuffer      [O]  buffer for the string to be written to
1121  *   nBufferMax    [I]  maximum size of the buffer in characters
1122  *   lang          [I]  the preferred language for the string
1123  *
1124  * RETURNS
1125  *
1126  *   If successful, this function returns the language id of the string loaded
1127  *   If the function fails, the function returns zero.
1128  *
1129  * NOTES
1130  *
1131  *   The type of the first parameter is unknown.  LoadString's prototype
1132  *  suggests that it might be a module handle.  I have made it an MSI handle
1133  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
1134  *  handle.  Maybe strings can be stored in an MSI database somehow.
1135  */
1136 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
1137                 int nBufferMax, LANGID lang )
1138 {
1139     HRSRC hres;
1140     HGLOBAL hResData;
1141     LPWSTR p;
1142     DWORD i, len;
1143
1144     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
1145
1146     if( handle != -1 )
1147         FIXME("don't know how to deal with handle = %08lx\n", handle);
1148
1149     if( !lang )
1150         lang = GetUserDefaultLangID();
1151
1152     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
1153                             (LPWSTR)1, lang );
1154     if( !hres )
1155         return 0;
1156     hResData = LoadResource( msi_hInstance, hres );
1157     if( !hResData )
1158         return 0;
1159     p = LockResource( hResData );
1160     if( !p )
1161         return 0;
1162
1163     for (i = 0; i < (id&0xf); i++)
1164         p += *p + 1;
1165     len = *p;
1166
1167     if( nBufferMax <= len )
1168         return 0;
1169
1170     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
1171     lpBuffer[ len ] = 0;
1172
1173     TRACE("found -> %s\n", debugstr_w(lpBuffer));
1174
1175     return lang;
1176 }
1177
1178 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
1179                 int nBufferMax, LANGID lang )
1180 {
1181     LPWSTR bufW;
1182     LANGID r;
1183     DWORD len;
1184
1185     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
1186     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
1187     if( r )
1188     {
1189         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
1190         if( len <= nBufferMax )
1191             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
1192                                  lpBuffer, nBufferMax, NULL, NULL );
1193         else
1194             r = 0;
1195     }
1196     msi_free(bufW);
1197     return r;
1198 }
1199
1200 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
1201                 LPDWORD pcchBuf)
1202 {
1203     char szProduct[GUID_SIZE];
1204
1205     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
1206
1207     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
1208         return INSTALLSTATE_UNKNOWN;
1209
1210     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
1211 }
1212
1213 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
1214                 LPDWORD pcchBuf)
1215 {
1216     WCHAR szProduct[GUID_SIZE];
1217
1218     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
1219
1220     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
1221         return INSTALLSTATE_UNKNOWN;
1222
1223     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
1224 }
1225
1226 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
1227                 WORD wLanguageId, DWORD f)
1228 {
1229     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
1230           uType, wLanguageId, f);
1231     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
1232 }
1233
1234 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
1235                 WORD wLanguageId, DWORD f)
1236 {
1237     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
1238           uType, wLanguageId, f);
1239     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
1240 }
1241
1242 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
1243                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
1244                 LPDWORD pcchPathBuf )
1245 {
1246     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
1247           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1248           pcchPathBuf);
1249     return ERROR_CALL_NOT_IMPLEMENTED;
1250 }
1251
1252 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
1253                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
1254                 LPDWORD pcchPathBuf )
1255 {
1256     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
1257           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1258           pcchPathBuf);
1259     return ERROR_CALL_NOT_IMPLEMENTED;
1260 }
1261
1262 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
1263                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1264 {
1265     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
1266     return ERROR_CALL_NOT_IMPLEMENTED;
1267 }
1268
1269 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
1270                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1271 {
1272     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1273     return ERROR_CALL_NOT_IMPLEMENTED;
1274 }
1275
1276 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
1277                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1278                 LPDWORD pcbHashData)
1279 {
1280     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
1281           ppcCertContext, pbHashData, pcbHashData);
1282     return ERROR_CALL_NOT_IMPLEMENTED;
1283 }
1284
1285 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
1286                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1287                 LPDWORD pcbHashData)
1288 {
1289     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
1290           ppcCertContext, pbHashData, pcbHashData);
1291     return ERROR_CALL_NOT_IMPLEMENTED;
1292 }
1293
1294 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1295                                     LPSTR szValue, LPDWORD pccbValue )
1296 {
1297     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1298     return ERROR_CALL_NOT_IMPLEMENTED;
1299 }
1300
1301 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1302                                     LPWSTR szValue, LPDWORD pccbValue )
1303 {
1304     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1305     return ERROR_CALL_NOT_IMPLEMENTED;
1306 }
1307
1308 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1309 {
1310     UINT r;
1311     LPWSTR szPack = NULL;
1312
1313     TRACE("%s\n", debugstr_a(szPackage) );
1314
1315     if( szPackage )
1316     {
1317         szPack = strdupAtoW( szPackage );
1318         if( !szPack )
1319             return ERROR_OUTOFMEMORY;
1320     }
1321
1322     r = MsiVerifyPackageW( szPack );
1323
1324     msi_free( szPack );
1325
1326     return r;
1327 }
1328
1329 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1330 {
1331     MSIHANDLE handle;
1332     UINT r;
1333
1334     TRACE("%s\n", debugstr_w(szPackage) );
1335
1336     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
1337     MsiCloseHandle( handle );
1338
1339     return r;
1340 }
1341
1342 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
1343                                                 awstring* lpPathBuf, LPDWORD pcchBuf)
1344 {
1345     WCHAR squished_pc[GUID_SIZE];
1346     WCHAR squished_comp[GUID_SIZE];
1347     HKEY hkey;
1348     LPWSTR path = NULL;
1349     INSTALLSTATE state;
1350     DWORD version;
1351
1352     static const WCHAR wininstaller[] = {
1353         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1354
1355     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1356            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
1357
1358     if (!szProduct || !szComponent)
1359         return INSTALLSTATE_INVALIDARG;
1360
1361     if (lpPathBuf->str.w && !pcchBuf)
1362         return INSTALLSTATE_INVALIDARG;
1363
1364     if (!squash_guid(szProduct, squished_pc) ||
1365         !squash_guid(szComponent, squished_comp))
1366         return INSTALLSTATE_INVALIDARG;
1367
1368     state = INSTALLSTATE_UNKNOWN;
1369
1370     if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1371         MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1372     {
1373         path = msi_reg_get_val_str(hkey, squished_pc);
1374         RegCloseKey(hkey);
1375
1376         state = INSTALLSTATE_ABSENT;
1377
1378         if ((MSIREG_OpenLocalSystemProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1379             MSIREG_OpenUserDataProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS) &&
1380             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
1381             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1382         {
1383             RegCloseKey(hkey);
1384             state = INSTALLSTATE_LOCAL;
1385         }
1386     }
1387
1388     if (state != INSTALLSTATE_LOCAL &&
1389         (MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1390          MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS))
1391     {
1392         RegCloseKey(hkey);
1393
1394         if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1395             MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1396         {
1397             msi_free(path);
1398             path = msi_reg_get_val_str(hkey, squished_pc);
1399             RegCloseKey(hkey);
1400
1401             state = INSTALLSTATE_ABSENT;
1402
1403             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1404                 state = INSTALLSTATE_LOCAL;
1405         }
1406     }
1407
1408     if (!path)
1409         return INSTALLSTATE_UNKNOWN;
1410
1411     if (state == INSTALLSTATE_LOCAL && !*path)
1412         state = INSTALLSTATE_NOTUSED;
1413
1414     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
1415     msi_free(path);
1416     return state;
1417 }
1418
1419 /******************************************************************
1420  * MsiGetComponentPathW      [MSI.@]
1421  */
1422 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1423                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
1424 {
1425     awstring path;
1426
1427     path.unicode = TRUE;
1428     path.str.w = lpPathBuf;
1429
1430     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1431 }
1432
1433 /******************************************************************
1434  * MsiGetComponentPathA      [MSI.@]
1435  */
1436 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1437                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
1438 {
1439     LPWSTR szwProduct, szwComponent = NULL;
1440     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1441     awstring path;
1442
1443     szwProduct = strdupAtoW( szProduct );
1444     if( szProduct && !szwProduct)
1445         goto end;
1446
1447     szwComponent = strdupAtoW( szComponent );
1448     if( szComponent && !szwComponent )
1449         goto end;
1450
1451     path.unicode = FALSE;
1452     path.str.a = lpPathBuf;
1453
1454     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1455
1456 end:
1457     msi_free( szwProduct );
1458     msi_free( szwComponent );
1459
1460     return r;
1461 }
1462
1463 /******************************************************************
1464  * MsiQueryFeatureStateA      [MSI.@]
1465  */
1466 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1467 {
1468     LPWSTR szwProduct = NULL, szwFeature= NULL;
1469     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1470
1471     szwProduct = strdupAtoW( szProduct );
1472     if ( szProduct && !szwProduct )
1473         goto end;
1474
1475     szwFeature = strdupAtoW( szFeature );
1476     if ( szFeature && !szwFeature )
1477         goto end;
1478
1479     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1480
1481 end:
1482     msi_free( szwProduct);
1483     msi_free( szwFeature);
1484
1485     return rc;
1486 }
1487
1488 /******************************************************************
1489  * MsiQueryFeatureStateW      [MSI.@]
1490  *
1491  * Checks the state of a feature
1492  *
1493  * PARAMS
1494  *   szProduct     [I]  Product's GUID string
1495  *   szFeature     [I]  Feature's GUID string
1496  *
1497  * RETURNS
1498  *   INSTALLSTATE_LOCAL        Feature is installed and useable
1499  *   INSTALLSTATE_ABSENT       Feature is absent
1500  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1501  *   INSTALLSTATE_UNKNOWN      An error occurred
1502  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1503  *
1504  */
1505 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1506 {
1507     WCHAR squishProduct[33], comp[GUID_SIZE];
1508     GUID guid;
1509     LPWSTR components, p, parent_feature, path;
1510     UINT rc;
1511     HKEY hkey;
1512     INSTALLSTATE r;
1513     BOOL missing = FALSE;
1514
1515     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1516
1517     if (!szProduct || !szFeature)
1518         return INSTALLSTATE_INVALIDARG;
1519
1520     if (!squash_guid( szProduct, squishProduct ))
1521         return INSTALLSTATE_INVALIDARG;
1522
1523     /* check that it's installed at all */
1524     rc = MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE);
1525     if (rc != ERROR_SUCCESS)
1526         return INSTALLSTATE_UNKNOWN;
1527
1528     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1529     RegCloseKey(hkey);
1530
1531     if (!parent_feature)
1532         return INSTALLSTATE_UNKNOWN;
1533
1534     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1535     msi_free(parent_feature);
1536     if (r == INSTALLSTATE_ABSENT)
1537         return r;
1538
1539     /* now check if it's complete or advertised */
1540     rc = MSIREG_OpenUserDataFeaturesKey(szProduct, &hkey, FALSE);
1541     if (rc != ERROR_SUCCESS)
1542         return INSTALLSTATE_ADVERTISED;
1543
1544     components = msi_reg_get_val_str( hkey, szFeature );
1545     RegCloseKey(hkey);
1546
1547     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1548
1549     if (!components)
1550         return INSTALLSTATE_ADVERTISED;
1551
1552     for( p = components; *p && *p != 2 ; p += 20)
1553     {
1554         if (!decode_base85_guid( p, &guid ))
1555         {
1556             if (p != components)
1557                 break;
1558
1559             msi_free(components);
1560             return INSTALLSTATE_BADCONFIG;
1561         }
1562
1563         StringFromGUID2(&guid, comp, GUID_SIZE);
1564         rc = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
1565         if (rc != ERROR_SUCCESS)
1566         {
1567             msi_free(components);
1568             return INSTALLSTATE_ADVERTISED;
1569         }
1570
1571         path = msi_reg_get_val_str(hkey, squishProduct);
1572         if (!path)
1573             missing = TRUE;
1574
1575         msi_free(path);
1576     }
1577
1578     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1579     msi_free(components);
1580
1581     if (missing)
1582         return INSTALLSTATE_ADVERTISED;
1583
1584     return INSTALLSTATE_LOCAL;
1585 }
1586
1587 /******************************************************************
1588  * MsiGetFileVersionA         [MSI.@]
1589  */
1590 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1591                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
1592 {
1593     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1594     UINT ret = ERROR_OUTOFMEMORY;
1595
1596     if ((lpVersionBuf && !pcchVersionBuf) ||
1597         (lpLangBuf && !pcchLangBuf))
1598         return ERROR_INVALID_PARAMETER;
1599
1600     if( szFilePath )
1601     {
1602         szwFilePath = strdupAtoW( szFilePath );
1603         if( !szwFilePath )
1604             goto end;
1605     }
1606
1607     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1608     {
1609         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1610         if( !lpwVersionBuff )
1611             goto end;
1612     }
1613
1614     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1615     {
1616         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
1617         if( !lpwLangBuff )
1618             goto end;
1619     }
1620
1621     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1622                              lpwLangBuff, pcchLangBuf);
1623
1624     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
1625         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1626                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
1627     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
1628         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1629                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
1630
1631 end:
1632     msi_free(szwFilePath);
1633     msi_free(lpwVersionBuff);
1634     msi_free(lpwLangBuff);
1635
1636     return ret;
1637 }
1638
1639 /******************************************************************
1640  * MsiGetFileVersionW         [MSI.@]
1641  */
1642 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1643                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
1644 {
1645     static const WCHAR szVersionResource[] = {'\\',0};
1646     static const WCHAR szVersionFormat[] = {
1647         '%','d','.','%','d','.','%','d','.','%','d',0};
1648     static const WCHAR szLangResource[] = {
1649         '\\','V','a','r','F','i','l','e','I','n','f','o','\\',
1650         'T','r','a','n','s','l','a','t','i','o','n',0};
1651     static const WCHAR szLangFormat[] = {'%','d',0};
1652     UINT ret = 0;
1653     DWORD dwVerLen, gle;
1654     LPVOID lpVer = NULL;
1655     VS_FIXEDFILEINFO *ffi;
1656     USHORT *lang;
1657     UINT puLen;
1658     WCHAR tmp[32];
1659
1660     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
1661           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1662           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1663
1664     if ((lpVersionBuf && !pcchVersionBuf) ||
1665         (lpLangBuf && !pcchLangBuf))
1666         return ERROR_INVALID_PARAMETER;
1667
1668     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1669     if( !dwVerLen )
1670     {
1671         gle = GetLastError();
1672         if (gle == ERROR_BAD_PATHNAME)
1673             return ERROR_FILE_NOT_FOUND;
1674         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
1675             return ERROR_FILE_INVALID;
1676
1677         return gle;
1678     }
1679
1680     lpVer = msi_alloc(dwVerLen);
1681     if( !lpVer )
1682     {
1683         ret = ERROR_OUTOFMEMORY;
1684         goto end;
1685     }
1686
1687     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1688     {
1689         ret = GetLastError();
1690         goto end;
1691     }
1692
1693     if (pcchVersionBuf)
1694     {
1695         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1696             (puLen > 0) )
1697         {
1698             wsprintfW(tmp, szVersionFormat,
1699                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1700                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1701             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1702
1703             if (lstrlenW(tmp) >= *pcchVersionBuf)
1704                 ret = ERROR_MORE_DATA;
1705
1706             *pcchVersionBuf = lstrlenW(tmp);
1707         }
1708         else
1709         {
1710             if (lpVersionBuf) *lpVersionBuf = 0;
1711             *pcchVersionBuf = 0;
1712         }
1713     }
1714
1715     if (pcchLangBuf)
1716     {
1717         if (VerQueryValueW(lpVer, szLangResource, (LPVOID*)&lang, &puLen) &&
1718             (puLen > 0))
1719         {
1720             wsprintfW(tmp, szLangFormat, *lang);
1721             if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1722
1723             if (lstrlenW(tmp) >= *pcchLangBuf)
1724                 ret = ERROR_MORE_DATA;
1725
1726             *pcchLangBuf = lstrlenW(tmp);
1727         }
1728         else
1729         {
1730             if (lpLangBuf) *lpLangBuf = 0;
1731             *pcchLangBuf = 0;
1732         }
1733     }
1734
1735 end:
1736     msi_free(lpVer);
1737     return ret;
1738 }
1739
1740 /***********************************************************************
1741  * MsiGetFeatureUsageW           [MSI.@]
1742  */
1743 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1744                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
1745 {
1746     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1747           pdwUseCount, pwDateUsed);
1748     return ERROR_CALL_NOT_IMPLEMENTED;
1749 }
1750
1751 /***********************************************************************
1752  * MsiGetFeatureUsageA           [MSI.@]
1753  */
1754 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1755                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
1756 {
1757     LPWSTR prod = NULL, feat = NULL;
1758     UINT ret = ERROR_OUTOFMEMORY;
1759
1760     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1761           pdwUseCount, pwDateUsed);
1762
1763     prod = strdupAtoW( szProduct );
1764     if (szProduct && !prod)
1765         goto end;
1766
1767     feat = strdupAtoW( szFeature );
1768     if (szFeature && !feat)
1769         goto end;
1770
1771     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1772
1773 end:
1774     msi_free( prod );
1775     msi_free( feat );
1776
1777     return ret;
1778 }
1779
1780 /***********************************************************************
1781  * MsiUseFeatureExW           [MSI.@]
1782  */
1783 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1784                                       DWORD dwInstallMode, DWORD dwReserved )
1785 {
1786     INSTALLSTATE state;
1787
1788     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1789           dwInstallMode, dwReserved);
1790
1791     state = MsiQueryFeatureStateW( szProduct, szFeature );
1792
1793     if (dwReserved)
1794         return INSTALLSTATE_INVALIDARG;
1795
1796     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1797     {
1798         FIXME("mark product %s feature %s as used\n",
1799               debugstr_w(szProduct), debugstr_w(szFeature) );
1800     }
1801
1802     return state;
1803 }
1804
1805 /***********************************************************************
1806  * MsiUseFeatureExA           [MSI.@]
1807  */
1808 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1809                                       DWORD dwInstallMode, DWORD dwReserved )
1810 {
1811     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1812     LPWSTR prod = NULL, feat = NULL;
1813
1814     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1815           dwInstallMode, dwReserved);
1816
1817     prod = strdupAtoW( szProduct );
1818     if (szProduct && !prod)
1819         goto end;
1820
1821     feat = strdupAtoW( szFeature );
1822     if (szFeature && !feat)
1823         goto end;
1824
1825     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1826
1827 end:
1828     msi_free( prod );
1829     msi_free( feat );
1830
1831     return ret;
1832 }
1833
1834 /***********************************************************************
1835  * MsiUseFeatureW             [MSI.@]
1836  */
1837 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1838 {
1839     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
1840 }
1841
1842 /***********************************************************************
1843  * MsiUseFeatureA             [MSI.@]
1844  */
1845 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1846 {
1847     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
1848 }
1849
1850 /***********************************************************************
1851  * MSI_ProvideQualifiedComponentEx [internal]
1852  */
1853 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
1854                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
1855                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
1856                 LPDWORD pcchPathBuf)
1857 {
1858     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
1859           feature[MAX_FEATURE_CHARS+1];
1860     LPWSTR info;
1861     HKEY hkey;
1862     DWORD sz;
1863     UINT rc;
1864
1865     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
1866           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1867           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1868
1869     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1870     if (rc != ERROR_SUCCESS)
1871         return ERROR_INDEX_ABSENT;
1872
1873     info = msi_reg_get_val_str( hkey, szQualifier );
1874     RegCloseKey(hkey);
1875
1876     if (!info)
1877         return ERROR_INDEX_ABSENT;
1878
1879     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1880
1881     if (!szProduct)
1882         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
1883     else
1884         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
1885
1886     msi_free( info );
1887
1888     if (rc != INSTALLSTATE_LOCAL)
1889         return ERROR_FILE_NOT_FOUND;
1890
1891     return ERROR_SUCCESS;
1892 }
1893
1894 /***********************************************************************
1895  * MsiProvideQualifiedComponentExW [MSI.@]
1896  */
1897 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1898                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
1899                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1900                 LPDWORD pcchPathBuf)
1901 {
1902     awstring path;
1903
1904     path.unicode = TRUE;
1905     path.str.w = lpPathBuf;
1906
1907     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
1908             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
1909 }
1910
1911 /***********************************************************************
1912  * MsiProvideQualifiedComponentExA [MSI.@]
1913  */
1914 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
1915                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
1916                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
1917                 LPDWORD pcchPathBuf)
1918 {
1919     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
1920     UINT r = ERROR_OUTOFMEMORY;
1921     awstring path;
1922
1923     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
1924           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
1925           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1926
1927     szwComponent = strdupAtoW( szComponent );
1928     if (szComponent && !szwComponent)
1929         goto end;
1930
1931     szwQualifier = strdupAtoW( szQualifier );
1932     if (szQualifier && !szwQualifier)
1933         goto end;
1934
1935     szwProduct = strdupAtoW( szProduct );
1936     if (szProduct && !szwProduct)
1937         goto end;
1938
1939     path.unicode = FALSE;
1940     path.str.a = lpPathBuf;
1941
1942     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
1943                               dwInstallMode, szwProduct, Unused1,
1944                               Unused2, &path, pcchPathBuf);
1945 end:
1946     msi_free(szwProduct);
1947     msi_free(szwComponent);
1948     msi_free(szwQualifier);
1949
1950     return r;
1951 }
1952
1953 /***********************************************************************
1954  * MsiProvideQualifiedComponentW [MSI.@]
1955  */
1956 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1957                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1958                 LPDWORD pcchPathBuf)
1959 {
1960     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1961                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1962 }
1963
1964 /***********************************************************************
1965  * MsiProvideQualifiedComponentA [MSI.@]
1966  */
1967 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1968                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1969                 LPDWORD pcchPathBuf)
1970 {
1971     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
1972                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1973 }
1974
1975 /***********************************************************************
1976  * MSI_GetUserInfo [internal]
1977  */
1978 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
1979                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
1980                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
1981                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
1982 {
1983     HKEY hkey;
1984     LPWSTR user, org, serial;
1985     UINT r;
1986     USERINFOSTATE state;
1987
1988     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1989           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1990           pcchSerialBuf);
1991
1992     if (!szProduct)
1993         return USERINFOSTATE_INVALIDARG;
1994
1995     r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1996     if (r != ERROR_SUCCESS)
1997         return USERINFOSTATE_UNKNOWN;
1998
1999     user = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGOWNERW );
2000     org = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGCOMPANYW );
2001     serial = msi_reg_get_val_str( hkey, INSTALLPROPERTY_PRODUCTIDW );
2002
2003     RegCloseKey(hkey);
2004
2005     state = USERINFOSTATE_PRESENT;
2006
2007     if (user)
2008     {
2009         r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
2010         if (r == ERROR_MORE_DATA)
2011             state = USERINFOSTATE_MOREDATA;
2012     }
2013     else
2014         state = USERINFOSTATE_ABSENT;
2015     if (org)
2016     {
2017         r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
2018         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
2019             state = USERINFOSTATE_MOREDATA;
2020     }
2021     /* msdn states: The user information is considered to be present even in the absence of a company name. */
2022     if (serial)
2023     {
2024         r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
2025         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
2026             state = USERINFOSTATE_MOREDATA;
2027     }
2028     else
2029         state = USERINFOSTATE_ABSENT;
2030
2031     msi_free( user );
2032     msi_free( org );
2033     msi_free( serial );
2034
2035     return state;
2036 }
2037
2038 /***********************************************************************
2039  * MsiGetUserInfoW [MSI.@]
2040  */
2041 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
2042                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2043                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2044                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2045 {
2046     awstring user, org, serial;
2047
2048     user.unicode = TRUE;
2049     user.str.w = lpUserNameBuf;
2050     org.unicode = TRUE;
2051     org.str.w = lpOrgNameBuf;
2052     serial.unicode = TRUE;
2053     serial.str.w = lpSerialBuf;
2054
2055     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
2056                             &org, pcchOrgNameBuf,
2057                             &serial, pcchSerialBuf );
2058 }
2059
2060 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
2061                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2062                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2063                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2064 {
2065     awstring user, org, serial;
2066     LPWSTR prod;
2067     UINT r;
2068
2069     prod = strdupAtoW( szProduct );
2070     if (szProduct && !prod)
2071         return ERROR_OUTOFMEMORY;
2072
2073     user.unicode = FALSE;
2074     user.str.a = lpUserNameBuf;
2075     org.unicode = FALSE;
2076     org.str.a = lpOrgNameBuf;
2077     serial.unicode = FALSE;
2078     serial.str.a = lpSerialBuf;
2079
2080     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
2081                          &org, pcchOrgNameBuf,
2082                          &serial, pcchSerialBuf );
2083
2084     msi_free( prod );
2085
2086     return r;
2087 }
2088
2089 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
2090 {
2091     MSIHANDLE handle;
2092     UINT rc;
2093     MSIPACKAGE *package;
2094     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2095
2096     TRACE("(%s)\n",debugstr_w(szProduct));
2097
2098     rc = MsiOpenProductW(szProduct,&handle);
2099     if (rc != ERROR_SUCCESS)
2100         return ERROR_INVALID_PARAMETER;
2101
2102     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2103     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2104     msiobj_release( &package->hdr );
2105
2106     MsiCloseHandle(handle);
2107
2108     return rc;
2109 }
2110
2111 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
2112 {
2113     MSIHANDLE handle;
2114     UINT rc;
2115     MSIPACKAGE *package;
2116     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2117
2118     TRACE("(%s)\n",debugstr_a(szProduct));
2119
2120     rc = MsiOpenProductA(szProduct,&handle);
2121     if (rc != ERROR_SUCCESS)
2122         return ERROR_INVALID_PARAMETER;
2123
2124     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2125     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2126     msiobj_release( &package->hdr );
2127
2128     MsiCloseHandle(handle);
2129
2130     return rc;
2131 }
2132
2133 /***********************************************************************
2134  * MsiConfigureFeatureA            [MSI.@]
2135  */
2136 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
2137 {
2138     LPWSTR prod, feat = NULL;
2139     UINT r = ERROR_OUTOFMEMORY;
2140
2141     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
2142
2143     prod = strdupAtoW( szProduct );
2144     if (szProduct && !prod)
2145         goto end;
2146
2147     feat = strdupAtoW( szFeature );
2148     if (szFeature && !feat)
2149         goto end;
2150
2151     r = MsiConfigureFeatureW(prod, feat, eInstallState);
2152
2153 end:
2154     msi_free(feat);
2155     msi_free(prod);
2156
2157     return r;
2158 }
2159
2160 /***********************************************************************
2161  * MsiConfigureFeatureW            [MSI.@]
2162  */
2163 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
2164 {
2165     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
2166     MSIPACKAGE *package = NULL;
2167     UINT r;
2168     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
2169     DWORD sz;
2170
2171     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
2172
2173     if (!szProduct || !szFeature)
2174         return ERROR_INVALID_PARAMETER;
2175
2176     switch (eInstallState)
2177     {
2178     case INSTALLSTATE_DEFAULT:
2179         /* FIXME: how do we figure out the default location? */
2180         eInstallState = INSTALLSTATE_LOCAL;
2181         break;
2182     case INSTALLSTATE_LOCAL:
2183     case INSTALLSTATE_SOURCE:
2184     case INSTALLSTATE_ABSENT:
2185     case INSTALLSTATE_ADVERTISED:
2186         break;
2187     default:
2188         return ERROR_INVALID_PARAMETER;
2189     }
2190
2191     r = MSI_OpenProductW( szProduct, &package );
2192     if (r != ERROR_SUCCESS)
2193         return r;
2194
2195     sz = sizeof(sourcepath);
2196     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2197                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2198
2199     sz = sizeof(filename);
2200     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2201                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2202
2203     lstrcatW( sourcepath, filename );
2204
2205     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
2206
2207     r = ACTION_PerformUIAction( package, szCostInit, -1 );
2208     if (r != ERROR_SUCCESS)
2209         goto end;
2210
2211     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
2212     if (r != ERROR_SUCCESS)
2213         goto end;
2214
2215     r = MSI_InstallPackage( package, sourcepath, NULL );
2216
2217 end:
2218     msiobj_release( &package->hdr );
2219
2220     return r;
2221 }
2222
2223 /***********************************************************************
2224  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
2225  *
2226  * Notes: undocumented
2227  */
2228 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
2229 {
2230     WCHAR path[MAX_PATH];
2231
2232     TRACE("%d\n", dwReserved);
2233
2234     if (dwReserved)
2235     {
2236         FIXME("dwReserved=%d\n", dwReserved);
2237         return ERROR_INVALID_PARAMETER;
2238     }
2239
2240     if (!GetWindowsDirectoryW(path, MAX_PATH))
2241         return ERROR_FUNCTION_FAILED;
2242
2243     lstrcatW(path, installerW);
2244
2245     if (!CreateDirectoryW(path, NULL))
2246         return ERROR_FUNCTION_FAILED;
2247
2248     return ERROR_SUCCESS;
2249 }
2250
2251 /***********************************************************************
2252  * MsiGetShortcutTargetA           [MSI.@]
2253  */
2254 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
2255                                    LPSTR szProductCode, LPSTR szFeatureId,
2256                                    LPSTR szComponentCode )
2257 {
2258     LPWSTR target;
2259     const int len = MAX_FEATURE_CHARS+1;
2260     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
2261     UINT r;
2262
2263     target = strdupAtoW( szShortcutTarget );
2264     if (szShortcutTarget && !target )
2265         return ERROR_OUTOFMEMORY;
2266     product[0] = 0;
2267     feature[0] = 0;
2268     component[0] = 0;
2269     r = MsiGetShortcutTargetW( target, product, feature, component );
2270     msi_free( target );
2271     if (r == ERROR_SUCCESS)
2272     {
2273         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
2274         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
2275         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
2276     }
2277     return r;
2278 }
2279
2280 /***********************************************************************
2281  * MsiGetShortcutTargetW           [MSI.@]
2282  */
2283 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
2284                                    LPWSTR szProductCode, LPWSTR szFeatureId,
2285                                    LPWSTR szComponentCode )
2286 {
2287     IShellLinkDataList *dl = NULL;
2288     IPersistFile *pf = NULL;
2289     LPEXP_DARWIN_LINK darwin = NULL;
2290     HRESULT r, init;
2291
2292     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
2293           szProductCode, szFeatureId, szComponentCode );
2294
2295     init = CoInitialize(NULL);
2296
2297     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2298                           &IID_IPersistFile, (LPVOID*) &pf );
2299     if( SUCCEEDED( r ) )
2300     {
2301         r = IPersistFile_Load( pf, szShortcutTarget,
2302                                STGM_READ | STGM_SHARE_DENY_WRITE );
2303         if( SUCCEEDED( r ) )
2304         {
2305             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
2306                                              (LPVOID*) &dl );
2307             if( SUCCEEDED( r ) )
2308             {
2309                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
2310                                                   (LPVOID) &darwin );
2311                 IShellLinkDataList_Release( dl );
2312             }
2313         }
2314         IPersistFile_Release( pf );
2315     }
2316
2317     if (SUCCEEDED(init))
2318         CoUninitialize();
2319
2320     TRACE("darwin = %p\n", darwin);
2321
2322     if (darwin)
2323     {
2324         DWORD sz;
2325         UINT ret;
2326
2327         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
2328                   szProductCode, szFeatureId, szComponentCode, &sz );
2329         LocalFree( darwin );
2330         return ret;
2331     }
2332
2333     return ERROR_FUNCTION_FAILED;
2334 }
2335
2336 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
2337                                   DWORD dwReinstallMode )
2338 {
2339     MSIPACKAGE* package = NULL;
2340     UINT r;
2341     WCHAR sourcepath[MAX_PATH];
2342     WCHAR filename[MAX_PATH];
2343     static const WCHAR szLogVerbose[] = {
2344         ' ','L','O','G','V','E','R','B','O','S','E',0 };
2345     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
2346     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
2347     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
2348     static const WCHAR szOne[] = {'1',0};
2349     WCHAR reinstallmode[11];
2350     LPWSTR ptr;
2351     DWORD sz;
2352
2353     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2354                            dwReinstallMode);
2355
2356     ptr = reinstallmode;
2357
2358     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
2359         *ptr++ = 'p';
2360     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2361         *ptr++ = 'o';
2362     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2363         *ptr++ = 'w';
2364     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2365         *ptr++ = 'd';
2366     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2367         *ptr++ = 'c';
2368     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2369         *ptr++ = 'a';
2370     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2371         *ptr++ = 'u';
2372     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2373         *ptr++ = 'm';
2374     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2375         *ptr++ = 's';
2376     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2377         *ptr++ = 'v';
2378     *ptr = 0;
2379     
2380     sz = sizeof(sourcepath);
2381     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2382             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2383
2384     sz = sizeof(filename);
2385     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2386             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2387
2388     lstrcatW( sourcepath, filename );
2389
2390     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2391         r = MSI_OpenPackageW( sourcepath, &package );
2392     else
2393         r = MSI_OpenProductW( szProduct, &package );
2394
2395     if (r != ERROR_SUCCESS)
2396         return r;
2397
2398     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2399     MSI_SetPropertyW( package, szInstalled, szOne );
2400     MSI_SetPropertyW( package, szLogVerbose, szOne );
2401     MSI_SetPropertyW( package, szReinstall, szFeature );
2402
2403     r = MSI_InstallPackage( package, sourcepath, NULL );
2404
2405     msiobj_release( &package->hdr );
2406
2407     return r;
2408 }
2409
2410 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2411                                   DWORD dwReinstallMode )
2412 {
2413     LPWSTR wszProduct;
2414     LPWSTR wszFeature;
2415     UINT rc;
2416
2417     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2418                            dwReinstallMode);
2419
2420     wszProduct = strdupAtoW(szProduct);
2421     wszFeature = strdupAtoW(szFeature);
2422
2423     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2424
2425     msi_free(wszProduct);
2426     msi_free(wszFeature);
2427     return rc;
2428 }
2429
2430 typedef struct
2431 {
2432     unsigned int i[2];
2433     unsigned int buf[4];
2434     unsigned char in[64];
2435     unsigned char digest[16];
2436 } MD5_CTX;
2437
2438 extern VOID WINAPI MD5Init( MD5_CTX *);
2439 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2440 extern VOID WINAPI MD5Final( MD5_CTX *);
2441
2442 /***********************************************************************
2443  * MsiGetFileHashW            [MSI.@]
2444  */
2445 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2446                              PMSIFILEHASHINFO pHash )
2447 {
2448     HANDLE handle, mapping;
2449     void *p;
2450     DWORD length;
2451     UINT r = ERROR_FUNCTION_FAILED;
2452
2453     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2454
2455     if (!szFilePath)
2456         return ERROR_INVALID_PARAMETER;
2457
2458     if (!*szFilePath)
2459         return ERROR_PATH_NOT_FOUND;
2460
2461     if (dwOptions)
2462         return ERROR_INVALID_PARAMETER;
2463     if (!pHash)
2464         return ERROR_INVALID_PARAMETER;
2465     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2466         return ERROR_INVALID_PARAMETER;
2467
2468     handle = CreateFileW( szFilePath, GENERIC_READ,
2469                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2470     if (handle == INVALID_HANDLE_VALUE)
2471         return ERROR_FILE_NOT_FOUND;
2472
2473     length = GetFileSize( handle, NULL );
2474
2475     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2476     if (mapping)
2477     {
2478         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2479         if (p)
2480         {
2481             MD5_CTX ctx;
2482
2483             MD5Init( &ctx );
2484             MD5Update( &ctx, p, length );
2485             MD5Final( &ctx );
2486             UnmapViewOfFile( p );
2487
2488             memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
2489             r = ERROR_SUCCESS;
2490         }
2491         CloseHandle( mapping );
2492     }
2493     CloseHandle( handle );
2494
2495     return r;
2496 }
2497
2498 /***********************************************************************
2499  * MsiGetFileHashA            [MSI.@]
2500  */
2501 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2502                              PMSIFILEHASHINFO pHash )
2503 {
2504     LPWSTR file;
2505     UINT r;
2506
2507     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2508
2509     file = strdupAtoW( szFilePath );
2510     if (szFilePath && !file)
2511         return ERROR_OUTOFMEMORY;
2512
2513     r = MsiGetFileHashW( file, dwOptions, pHash );
2514     msi_free( file );
2515     return r;
2516 }
2517
2518 /***********************************************************************
2519  * MsiAdvertiseScriptW        [MSI.@]
2520  */
2521 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2522                                  PHKEY phRegData, BOOL fRemoveItems )
2523 {
2524     FIXME("%s %08x %p %d\n",
2525           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2526     return ERROR_CALL_NOT_IMPLEMENTED;
2527 }
2528
2529 /***********************************************************************
2530  * MsiAdvertiseScriptA        [MSI.@]
2531  */
2532 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2533                                  PHKEY phRegData, BOOL fRemoveItems )
2534 {
2535     FIXME("%s %08x %p %d\n",
2536           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2537     return ERROR_CALL_NOT_IMPLEMENTED;
2538 }
2539
2540 /***********************************************************************
2541  * MsiIsProductElevatedW        [MSI.@]
2542  */
2543 UINT WINAPI MsiIsProductElevatedW( LPCWSTR szProduct, BOOL *pfElevated )
2544 {
2545     FIXME("%s %p - stub\n",
2546           debugstr_w( szProduct ), pfElevated );
2547     *pfElevated = TRUE;
2548     return ERROR_SUCCESS;
2549 }
2550
2551 /***********************************************************************
2552  * MsiIsProductElevatedA        [MSI.@]
2553  */
2554 UINT WINAPI MsiIsProductElevatedA( LPCSTR szProduct, BOOL *pfElevated )
2555 {
2556     FIXME("%s %p - stub\n",
2557           debugstr_a( szProduct ), pfElevated );
2558     *pfElevated = TRUE;
2559     return ERROR_SUCCESS;
2560 }