msi: Reimplement MsiGetProductInfo.
[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 UINT WINAPI MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute,
565                                       awstring *szValue, LPDWORD pcchValueBuf)
566 {
567     UINT r = ERROR_UNKNOWN_PROPERTY;
568     HKEY prodkey, userdata, source;
569     LPWSTR val = NULL;
570     WCHAR squished_pc[GUID_SIZE];
571     WCHAR packagecode[GUID_SIZE];
572     BOOL classes = FALSE;
573     BOOL badconfig = FALSE;
574     LONG res;
575     DWORD save;
576
577     static WCHAR empty[] = {0};
578     static const WCHAR sourcelist[] = {
579         'S','o','u','r','c','e','L','i','s','t',0};
580     static const WCHAR display_name[] = {
581         'D','i','s','p','l','a','y','N','a','m','e',0};
582     static const WCHAR display_version[] = {
583         'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
584     static const WCHAR assignment[] = {
585         'A','s','s','i','g','n','m','e','n','t',0};
586
587     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
588           debugstr_w(szAttribute), szValue, pcchValueBuf);
589
590     if ((szValue->str.w && !pcchValueBuf) || !szProduct || !szAttribute)
591         return ERROR_INVALID_PARAMETER;
592
593     if (!squash_guid(szProduct, squished_pc))
594         return ERROR_INVALID_PARAMETER;
595
596     r = MSIREG_OpenLocalManagedProductKey(szProduct, &prodkey, FALSE);
597     if (r != ERROR_SUCCESS)
598     {
599         r = MSIREG_OpenUserProductsKey(szProduct, &prodkey, FALSE);
600         if (r != ERROR_SUCCESS)
601         {
602             r = MSIREG_OpenLocalClassesProductKey(szProduct, &prodkey, FALSE);
603             if (r == ERROR_SUCCESS)
604                 classes = TRUE;
605         }
606     }
607
608     if (classes)
609         MSIREG_OpenLocalSystemProductKey(szProduct, &userdata, FALSE);
610     else
611         MSIREG_OpenInstallPropertiesKey(szProduct, &userdata, FALSE);
612
613     if (!lstrcmpW(szAttribute, INSTALLPROPERTY_HELPLINKW) ||
614         !lstrcmpW(szAttribute, INSTALLPROPERTY_HELPTELEPHONEW) ||
615         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLDATEW) ||
616         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW) ||
617         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLLOCATIONW) ||
618         !lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLSOURCEW) ||
619         !lstrcmpW(szAttribute, INSTALLPROPERTY_LOCALPACKAGEW) ||
620         !lstrcmpW(szAttribute, INSTALLPROPERTY_PUBLISHERW) ||
621         !lstrcmpW(szAttribute, INSTALLPROPERTY_URLINFOABOUTW) ||
622         !lstrcmpW(szAttribute, INSTALLPROPERTY_URLUPDATEINFOW) ||
623         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMINORW) ||
624         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONMAJORW) ||
625         !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW) ||
626         !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTIDW) ||
627         !lstrcmpW(szAttribute, INSTALLPROPERTY_REGCOMPANYW) ||
628         !lstrcmpW(szAttribute, INSTALLPROPERTY_REGOWNERW))
629     {
630         if (!prodkey)
631         {
632             r = ERROR_UNKNOWN_PRODUCT;
633             goto done;
634         }
635
636         if (!userdata)
637             return ERROR_UNKNOWN_PROPERTY;
638
639         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTALLEDPRODUCTNAMEW))
640             szAttribute = display_name;
641         else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW))
642             szAttribute = display_version;
643
644         val = msi_reg_get_val_str(userdata, szAttribute);
645         if (!val)
646             val = empty;
647     }
648     else if (!lstrcmpW(szAttribute, INSTALLPROPERTY_INSTANCETYPEW) ||
649              !lstrcmpW(szAttribute, INSTALLPROPERTY_TRANSFORMSW) ||
650              !lstrcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW) ||
651              !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTNAMEW) ||
652              !lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW) ||
653              !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW) ||
654              !lstrcmpW(szAttribute, INSTALLPROPERTY_VERSIONW) ||
655              !lstrcmpW(szAttribute, INSTALLPROPERTY_PRODUCTICONW) ||
656              !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW) ||
657              !lstrcmpW(szAttribute, INSTALLPROPERTY_AUTHORIZED_LUA_APPW))
658     {
659         if (!prodkey)
660         {
661             r = ERROR_UNKNOWN_PRODUCT;
662             goto done;
663         }
664
665         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW))
666             szAttribute = assignment;
667
668         if (!lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGENAMEW))
669         {
670             res = RegOpenKeyW(prodkey, sourcelist, &source);
671             if (res == ERROR_SUCCESS)
672                 val = msi_reg_get_val_str(source, szAttribute);
673
674             RegCloseKey(source);
675         }
676         else
677         {
678             val = msi_reg_get_val_str(prodkey, szAttribute);
679             if (!val)
680                 val = empty;
681         }
682
683         if (val != empty && !lstrcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW))
684         {
685             if (lstrlenW(val) != SQUISH_GUID_SIZE - 1)
686                 badconfig = TRUE;
687             else
688             {
689                 unsquash_guid(val, packagecode);
690                 msi_free(val);
691                 val = strdupW(packagecode);
692             }
693         }
694     }
695
696     if (!val)
697     {
698         r = ERROR_UNKNOWN_PROPERTY;
699         goto done;
700     }
701
702     save = *pcchValueBuf;
703
704     if (lstrlenW(val) < *pcchValueBuf)
705         r = msi_strcpy_to_awstring(val, szValue, pcchValueBuf);
706     else if (szValue->str.a || szValue->str.w)
707         r = ERROR_MORE_DATA;
708
709     if (!badconfig)
710         *pcchValueBuf = lstrlenW(val);
711     else if (r == ERROR_SUCCESS)
712     {
713         *pcchValueBuf = save;
714         r = ERROR_BAD_CONFIGURATION;
715     }
716
717     if (val != empty)
718         msi_free(val);
719
720 done:
721     RegCloseKey(prodkey);
722     RegCloseKey(userdata);
723     return r;
724 }
725
726 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
727                                LPSTR szBuffer, LPDWORD pcchValueBuf)
728 {
729     LPWSTR szwProduct, szwAttribute = NULL;
730     UINT r = ERROR_OUTOFMEMORY;
731     awstring buffer;
732
733     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
734           szBuffer, pcchValueBuf);
735
736     szwProduct = strdupAtoW( szProduct );
737     if( szProduct && !szwProduct )
738         goto end;
739
740     szwAttribute = strdupAtoW( szAttribute );
741     if( szAttribute && !szwAttribute )
742         goto end;
743
744     buffer.unicode = FALSE;
745     buffer.str.a = szBuffer;
746
747     r = MSI_GetProductInfo( szwProduct, szwAttribute,
748                             &buffer, pcchValueBuf );
749
750 end:
751     msi_free( szwProduct );
752     msi_free( szwAttribute );
753
754     return r;
755 }
756
757 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
758                                LPWSTR szBuffer, LPDWORD pcchValueBuf)
759 {
760     awstring buffer;
761
762     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
763           szBuffer, pcchValueBuf);
764
765     buffer.unicode = TRUE;
766     buffer.str.w = szBuffer;
767
768     return MSI_GetProductInfo( szProduct, szAttribute,
769                                &buffer, pcchValueBuf );
770 }
771
772 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
773 {
774     LPWSTR szwLogFile = NULL;
775     UINT r;
776
777     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
778
779     if( szLogFile )
780     {
781         szwLogFile = strdupAtoW( szLogFile );
782         if( !szwLogFile )
783             return ERROR_OUTOFMEMORY;
784     }
785     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
786     msi_free( szwLogFile );
787     return r;
788 }
789
790 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
791 {
792     HANDLE file = INVALID_HANDLE_VALUE;
793
794     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
795
796     if (szLogFile)
797     {
798         lstrcpyW(gszLogFile,szLogFile);
799         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
800             DeleteFileW(szLogFile);
801         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
802                                FILE_ATTRIBUTE_NORMAL, NULL);
803         if (file != INVALID_HANDLE_VALUE)
804             CloseHandle(file);
805         else
806             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
807     }
808     else
809         gszLogFile[0] = '\0';
810
811     return ERROR_SUCCESS;
812 }
813
814 UINT WINAPI MsiEnumComponentCostsW(MSIHANDLE hInstall, LPCWSTR szComponent,
815                                    DWORD dwIndex, INSTALLSTATE iState,
816                                    LPWSTR lpDriveBuf, DWORD *pcchDriveBuf,
817                                    int *piCost, int *pTempCost)
818 {
819     FIXME("(%ld, %s, %d, %d, %p, %p, %p %p): stub!\n", hInstall,
820           debugstr_w(szComponent), dwIndex, iState, lpDriveBuf,
821           pcchDriveBuf, piCost, pTempCost);
822
823     return ERROR_NO_MORE_ITEMS;
824 }
825
826 UINT WINAPI MsiQueryComponentStateA(LPCSTR szProductCode,
827                                     LPCSTR szUserSid, MSIINSTALLCONTEXT dwContext,
828                                     LPCSTR szComponent, INSTALLSTATE *pdwState)
829 {
830     LPWSTR prodcode = NULL, usersid = NULL, comp = NULL;
831     UINT r;
832
833     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_a(szProductCode),
834           debugstr_a(szUserSid), dwContext, debugstr_a(szComponent), pdwState);
835
836     if (szProductCode && !(prodcode = strdupAtoW(szProductCode)))
837         return ERROR_OUTOFMEMORY;
838
839     if (szUserSid && !(usersid = strdupAtoW(szUserSid)))
840             return ERROR_OUTOFMEMORY;
841
842     if (szComponent && !(comp = strdupAtoW(szComponent)))
843             return ERROR_OUTOFMEMORY;
844
845     r = MsiQueryComponentStateW(prodcode, usersid, dwContext, comp, pdwState);
846
847     msi_free(prodcode);
848     msi_free(usersid);
849     msi_free(comp);
850
851     return r;
852 }
853
854 static BOOL msi_comp_find_prod_key(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
855 {
856     UINT r;
857     HKEY hkey;
858
859     if (context == MSIINSTALLCONTEXT_MACHINE)
860         r = MSIREG_OpenLocalClassesProductKey(prodcode, &hkey, FALSE);
861     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
862         r = MSIREG_OpenUserProductsKey(prodcode, &hkey, FALSE);
863     else
864         r = MSIREG_OpenLocalManagedProductKey(prodcode, &hkey, FALSE);
865
866     RegCloseKey(hkey);
867     return (r == ERROR_SUCCESS);
868 }
869
870 static BOOL msi_comp_find_package(LPCWSTR prodcode, MSIINSTALLCONTEXT context)
871 {
872     LPCWSTR package;
873     HKEY hkey;
874     DWORD sz;
875     LONG res;
876     UINT r;
877
878     static const WCHAR local_package[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
879     static const WCHAR managed_local_package[] = {
880         'M','a','n','a','g','e','d','L','o','c','a','l','P','a','c','k','a','g','e',0
881     };
882
883     if (context == MSIINSTALLCONTEXT_MACHINE)
884         r = MSIREG_OpenLocalSystemProductKey(prodcode, &hkey, FALSE);
885     else
886         r = MSIREG_OpenInstallPropertiesKey(prodcode, &hkey, FALSE);
887
888     if (r != ERROR_SUCCESS)
889         return FALSE;
890
891     if (context == MSIINSTALLCONTEXT_USERMANAGED)
892         package = managed_local_package;
893     else
894         package = local_package;
895
896     sz = 0;
897     res = RegQueryValueExW(hkey, package, NULL, NULL, NULL, &sz);
898     RegCloseKey(hkey);
899
900     return (res == ERROR_SUCCESS);
901 }
902
903 static BOOL msi_comp_find_prodcode(LPCWSTR prodcode, LPWSTR squished_pc,
904                                    MSIINSTALLCONTEXT context,
905                                    LPCWSTR comp, DWORD *sz)
906 {
907     HKEY hkey;
908     LONG res;
909     UINT r;
910
911     if (context == MSIINSTALLCONTEXT_MACHINE)
912         r = MSIREG_OpenLocalSystemComponentKey(comp, &hkey, FALSE);
913     else
914         r = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
915
916     if (r != ERROR_SUCCESS)
917         return FALSE;
918
919     *sz = 0;
920     res = RegQueryValueExW(hkey, squished_pc, NULL, NULL, NULL, sz);
921     if (res != ERROR_SUCCESS)
922         return FALSE;
923
924     RegCloseKey(hkey);
925     return TRUE;
926 }
927
928 UINT WINAPI MsiQueryComponentStateW(LPCWSTR szProductCode,
929                                     LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
930                                     LPCWSTR szComponent, INSTALLSTATE *pdwState)
931 {
932     WCHAR squished_pc[GUID_SIZE];
933     BOOL found;
934     DWORD sz;
935
936     TRACE("(%s, %s, %d, %s, %p)\n", debugstr_w(szProductCode),
937           debugstr_w(szUserSid), dwContext, debugstr_w(szComponent), pdwState);
938
939     if (!pdwState)
940         return ERROR_INVALID_PARAMETER;
941
942     if (!szProductCode || !*szProductCode || lstrlenW(szProductCode) != GUID_SIZE - 1)
943         return ERROR_INVALID_PARAMETER;
944
945     if (!squash_guid(szProductCode, squished_pc))
946         return ERROR_INVALID_PARAMETER;
947
948     found = msi_comp_find_prod_key(szProductCode, dwContext);
949
950     if (!msi_comp_find_package(szProductCode, dwContext))
951     {
952         if (found)
953         {
954             *pdwState = INSTALLSTATE_UNKNOWN;
955             return ERROR_UNKNOWN_COMPONENT;
956         }
957
958         return ERROR_UNKNOWN_PRODUCT;
959     }
960
961     *pdwState = INSTALLSTATE_UNKNOWN;
962
963     if (!msi_comp_find_prodcode(szProductCode, squished_pc, dwContext, szComponent, &sz))
964         return ERROR_UNKNOWN_COMPONENT;
965
966     if (sz == 0)
967         *pdwState = INSTALLSTATE_NOTUSED;
968     else
969         *pdwState = INSTALLSTATE_LOCAL;
970
971     return ERROR_SUCCESS;
972 }
973
974 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
975 {
976     LPWSTR szwProduct = NULL;
977     INSTALLSTATE r;
978
979     if( szProduct )
980     {
981          szwProduct = strdupAtoW( szProduct );
982          if( !szwProduct )
983              return ERROR_OUTOFMEMORY;
984     }
985     r = MsiQueryProductStateW( szwProduct );
986     msi_free( szwProduct );
987     return r;
988 }
989
990 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
991 {
992     UINT rc;
993     INSTALLSTATE state = INSTALLSTATE_UNKNOWN;
994     HKEY hkey = 0, props = 0;
995     DWORD sz;
996     BOOL userkey_exists = FALSE;
997
998     static const int GUID_LEN = 38;
999     static const WCHAR szInstallProperties[] = {
1000             'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0
1001     };
1002     static const WCHAR szWindowsInstaller[] = {
1003             'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0
1004     };
1005
1006     TRACE("%s\n", debugstr_w(szProduct));
1007
1008     if (!szProduct || !*szProduct || lstrlenW(szProduct) != GUID_LEN)
1009         return INSTALLSTATE_INVALIDARG;
1010
1011     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
1012     if (rc == ERROR_SUCCESS)
1013     {
1014         userkey_exists = TRUE;
1015         state = INSTALLSTATE_ADVERTISED;
1016         RegCloseKey(hkey);
1017     }
1018
1019     rc = MSIREG_OpenUserDataProductKey(szProduct,&hkey,FALSE);
1020     if (rc != ERROR_SUCCESS)
1021         goto end;
1022
1023     rc = RegOpenKeyW(hkey, szInstallProperties, &props);
1024     if (rc != ERROR_SUCCESS)
1025         goto end;
1026
1027     sz = sizeof(state);
1028     rc = RegQueryValueExW(props,szWindowsInstaller,NULL,NULL,(LPVOID)&state, &sz);
1029     if (rc != ERROR_SUCCESS)
1030         goto end;
1031
1032     if (state)
1033         state = INSTALLSTATE_DEFAULT;
1034     else
1035         state = INSTALLSTATE_UNKNOWN;
1036
1037     if (state == INSTALLSTATE_DEFAULT && !userkey_exists)
1038         state = INSTALLSTATE_ABSENT;
1039
1040 end:
1041     RegCloseKey(props);
1042     RegCloseKey(hkey);
1043     return state;
1044 }
1045
1046 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
1047 {
1048     INSTALLUILEVEL old = gUILevel;
1049     HWND oldwnd = gUIhwnd;
1050
1051     TRACE("%08x %p\n", dwUILevel, phWnd);
1052
1053     gUILevel = dwUILevel;
1054     if (phWnd)
1055     {
1056         gUIhwnd = *phWnd;
1057         *phWnd = oldwnd;
1058     }
1059     return old;
1060 }
1061
1062 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
1063                                   DWORD dwMessageFilter, LPVOID pvContext)
1064 {
1065     INSTALLUI_HANDLERA prev = gUIHandlerA;
1066
1067     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
1068     gUIHandlerA = puiHandler;
1069     gUIFilter = dwMessageFilter;
1070     gUIContext = pvContext;
1071
1072     return prev;
1073 }
1074
1075 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
1076                                   DWORD dwMessageFilter, LPVOID pvContext)
1077 {
1078     INSTALLUI_HANDLERW prev = gUIHandlerW;
1079
1080     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
1081     gUIHandlerW = puiHandler;
1082     gUIFilter = dwMessageFilter;
1083     gUIContext = pvContext;
1084
1085     return prev;
1086 }
1087
1088 /******************************************************************
1089  *  MsiLoadStringW            [MSI.@]
1090  *
1091  * Loads a string from MSI's string resources.
1092  *
1093  * PARAMS
1094  *
1095  *   handle        [I]  only -1 is handled currently
1096  *   id            [I]  id of the string to be loaded
1097  *   lpBuffer      [O]  buffer for the string to be written to
1098  *   nBufferMax    [I]  maximum size of the buffer in characters
1099  *   lang          [I]  the preferred language for the string
1100  *
1101  * RETURNS
1102  *
1103  *   If successful, this function returns the language id of the string loaded
1104  *   If the function fails, the function returns zero.
1105  *
1106  * NOTES
1107  *
1108  *   The type of the first parameter is unknown.  LoadString's prototype
1109  *  suggests that it might be a module handle.  I have made it an MSI handle
1110  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
1111  *  handle.  Maybe strings can be stored in an MSI database somehow.
1112  */
1113 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
1114                 int nBufferMax, LANGID lang )
1115 {
1116     HRSRC hres;
1117     HGLOBAL hResData;
1118     LPWSTR p;
1119     DWORD i, len;
1120
1121     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
1122
1123     if( handle != -1 )
1124         FIXME("don't know how to deal with handle = %08lx\n", handle);
1125
1126     if( !lang )
1127         lang = GetUserDefaultLangID();
1128
1129     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
1130                             (LPWSTR)1, lang );
1131     if( !hres )
1132         return 0;
1133     hResData = LoadResource( msi_hInstance, hres );
1134     if( !hResData )
1135         return 0;
1136     p = LockResource( hResData );
1137     if( !p )
1138         return 0;
1139
1140     for (i = 0; i < (id&0xf); i++)
1141         p += *p + 1;
1142     len = *p;
1143
1144     if( nBufferMax <= len )
1145         return 0;
1146
1147     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
1148     lpBuffer[ len ] = 0;
1149
1150     TRACE("found -> %s\n", debugstr_w(lpBuffer));
1151
1152     return lang;
1153 }
1154
1155 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
1156                 int nBufferMax, LANGID lang )
1157 {
1158     LPWSTR bufW;
1159     LANGID r;
1160     DWORD len;
1161
1162     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
1163     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
1164     if( r )
1165     {
1166         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
1167         if( len <= nBufferMax )
1168             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
1169                                  lpBuffer, nBufferMax, NULL, NULL );
1170         else
1171             r = 0;
1172     }
1173     msi_free(bufW);
1174     return r;
1175 }
1176
1177 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
1178                 LPDWORD pcchBuf)
1179 {
1180     char szProduct[GUID_SIZE];
1181
1182     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
1183
1184     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
1185         return INSTALLSTATE_UNKNOWN;
1186
1187     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
1188 }
1189
1190 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
1191                 LPDWORD pcchBuf)
1192 {
1193     WCHAR szProduct[GUID_SIZE];
1194
1195     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
1196
1197     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
1198         return INSTALLSTATE_UNKNOWN;
1199
1200     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
1201 }
1202
1203 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
1204                 WORD wLanguageId, DWORD f)
1205 {
1206     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
1207           uType, wLanguageId, f);
1208     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
1209 }
1210
1211 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
1212                 WORD wLanguageId, DWORD f)
1213 {
1214     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
1215           uType, wLanguageId, f);
1216     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
1217 }
1218
1219 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
1220                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
1221                 LPDWORD pcchPathBuf )
1222 {
1223     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
1224           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1225           pcchPathBuf);
1226     return ERROR_CALL_NOT_IMPLEMENTED;
1227 }
1228
1229 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
1230                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
1231                 LPDWORD pcchPathBuf )
1232 {
1233     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
1234           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
1235           pcchPathBuf);
1236     return ERROR_CALL_NOT_IMPLEMENTED;
1237 }
1238
1239 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
1240                 LPSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1241 {
1242     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
1243     return ERROR_CALL_NOT_IMPLEMENTED;
1244 }
1245
1246 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
1247                 LPWSTR szPath, LPDWORD pcchPath, LPDWORD pcchArgs )
1248 {
1249     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
1250     return ERROR_CALL_NOT_IMPLEMENTED;
1251 }
1252
1253 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
1254                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1255                 LPDWORD pcbHashData)
1256 {
1257     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
1258           ppcCertContext, pbHashData, pcbHashData);
1259     return ERROR_CALL_NOT_IMPLEMENTED;
1260 }
1261
1262 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
1263                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, LPBYTE pbHashData,
1264                 LPDWORD pcbHashData)
1265 {
1266     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
1267           ppcCertContext, pbHashData, pcbHashData);
1268     return ERROR_CALL_NOT_IMPLEMENTED;
1269 }
1270
1271 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
1272                                     LPSTR szValue, LPDWORD pccbValue )
1273 {
1274     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
1275     return ERROR_CALL_NOT_IMPLEMENTED;
1276 }
1277
1278 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
1279                                     LPWSTR szValue, LPDWORD pccbValue )
1280 {
1281     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
1282     return ERROR_CALL_NOT_IMPLEMENTED;
1283 }
1284
1285 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
1286 {
1287     UINT r;
1288     LPWSTR szPack = NULL;
1289
1290     TRACE("%s\n", debugstr_a(szPackage) );
1291
1292     if( szPackage )
1293     {
1294         szPack = strdupAtoW( szPackage );
1295         if( !szPack )
1296             return ERROR_OUTOFMEMORY;
1297     }
1298
1299     r = MsiVerifyPackageW( szPack );
1300
1301     msi_free( szPack );
1302
1303     return r;
1304 }
1305
1306 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
1307 {
1308     MSIHANDLE handle;
1309     UINT r;
1310
1311     TRACE("%s\n", debugstr_w(szPackage) );
1312
1313     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
1314     MsiCloseHandle( handle );
1315
1316     return r;
1317 }
1318
1319 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
1320                                                 awstring* lpPathBuf, LPDWORD pcchBuf)
1321 {
1322     WCHAR squished_pc[GUID_SIZE];
1323     WCHAR squished_comp[GUID_SIZE];
1324     HKEY hkey;
1325     LPWSTR path = NULL;
1326     INSTALLSTATE state;
1327     DWORD version;
1328
1329     static const WCHAR wininstaller[] = {
1330         'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
1331
1332     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1333            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
1334
1335     if (!szProduct || !szComponent)
1336         return INSTALLSTATE_INVALIDARG;
1337
1338     if (lpPathBuf->str.w && !pcchBuf)
1339         return INSTALLSTATE_INVALIDARG;
1340
1341     if (!squash_guid(szProduct, squished_pc) ||
1342         !squash_guid(szComponent, squished_comp))
1343         return INSTALLSTATE_INVALIDARG;
1344
1345     state = INSTALLSTATE_UNKNOWN;
1346
1347     if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1348         MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1349     {
1350         path = msi_reg_get_val_str(hkey, squished_pc);
1351         RegCloseKey(hkey);
1352
1353         state = INSTALLSTATE_ABSENT;
1354
1355         if ((MSIREG_OpenLocalSystemProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1356             MSIREG_OpenUserDataProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS) &&
1357             msi_reg_get_val_dword(hkey, wininstaller, &version) &&
1358             GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1359         {
1360             RegCloseKey(hkey);
1361             state = INSTALLSTATE_LOCAL;
1362         }
1363     }
1364
1365     if (state != INSTALLSTATE_LOCAL &&
1366         (MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS ||
1367          MSIREG_OpenLocalClassesProductKey(szProduct, &hkey, FALSE) == ERROR_SUCCESS))
1368     {
1369         RegCloseKey(hkey);
1370
1371         if (MSIREG_OpenLocalSystemComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS ||
1372             MSIREG_OpenUserDataComponentKey(szComponent, &hkey, FALSE) == ERROR_SUCCESS)
1373         {
1374             msi_free(path);
1375             path = msi_reg_get_val_str(hkey, squished_pc);
1376             RegCloseKey(hkey);
1377
1378             state = INSTALLSTATE_ABSENT;
1379
1380             if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
1381                 state = INSTALLSTATE_LOCAL;
1382         }
1383     }
1384
1385     if (!path)
1386         return INSTALLSTATE_UNKNOWN;
1387
1388     if (state == INSTALLSTATE_LOCAL && !*path)
1389         state = INSTALLSTATE_NOTUSED;
1390
1391     msi_strcpy_to_awstring(path, lpPathBuf, pcchBuf);
1392     msi_free(path);
1393     return state;
1394 }
1395
1396 /******************************************************************
1397  * MsiGetComponentPathW      [MSI.@]
1398  */
1399 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1400                                          LPWSTR lpPathBuf, LPDWORD pcchBuf)
1401 {
1402     awstring path;
1403
1404     path.unicode = TRUE;
1405     path.str.w = lpPathBuf;
1406
1407     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1408 }
1409
1410 /******************************************************************
1411  * MsiGetComponentPathA      [MSI.@]
1412  */
1413 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1414                                          LPSTR lpPathBuf, LPDWORD pcchBuf)
1415 {
1416     LPWSTR szwProduct, szwComponent = NULL;
1417     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1418     awstring path;
1419
1420     szwProduct = strdupAtoW( szProduct );
1421     if( szProduct && !szwProduct)
1422         goto end;
1423
1424     szwComponent = strdupAtoW( szComponent );
1425     if( szComponent && !szwComponent )
1426         goto end;
1427
1428     path.unicode = FALSE;
1429     path.str.a = lpPathBuf;
1430
1431     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1432
1433 end:
1434     msi_free( szwProduct );
1435     msi_free( szwComponent );
1436
1437     return r;
1438 }
1439
1440 /******************************************************************
1441  * MsiQueryFeatureStateA      [MSI.@]
1442  */
1443 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1444 {
1445     LPWSTR szwProduct = NULL, szwFeature= NULL;
1446     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1447
1448     szwProduct = strdupAtoW( szProduct );
1449     if ( szProduct && !szwProduct )
1450         goto end;
1451
1452     szwFeature = strdupAtoW( szFeature );
1453     if ( szFeature && !szwFeature )
1454         goto end;
1455
1456     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1457
1458 end:
1459     msi_free( szwProduct);
1460     msi_free( szwFeature);
1461
1462     return rc;
1463 }
1464
1465 /******************************************************************
1466  * MsiQueryFeatureStateW      [MSI.@]
1467  *
1468  * Checks the state of a feature
1469  *
1470  * PARAMS
1471  *   szProduct     [I]  Product's GUID string
1472  *   szFeature     [I]  Feature's GUID string
1473  *
1474  * RETURNS
1475  *   INSTALLSTATE_LOCAL        Feature is installed and useable
1476  *   INSTALLSTATE_ABSENT       Feature is absent
1477  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1478  *   INSTALLSTATE_UNKNOWN      An error occurred
1479  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1480  *
1481  */
1482 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1483 {
1484     WCHAR squishProduct[33], comp[GUID_SIZE];
1485     GUID guid;
1486     LPWSTR components, p, parent_feature, path;
1487     UINT rc;
1488     HKEY hkey;
1489     INSTALLSTATE r;
1490     BOOL missing = FALSE;
1491
1492     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1493
1494     if (!szProduct || !szFeature)
1495         return INSTALLSTATE_INVALIDARG;
1496
1497     if (!squash_guid( szProduct, squishProduct ))
1498         return INSTALLSTATE_INVALIDARG;
1499
1500     /* check that it's installed at all */
1501     rc = MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE);
1502     if (rc != ERROR_SUCCESS)
1503         return INSTALLSTATE_UNKNOWN;
1504
1505     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1506     RegCloseKey(hkey);
1507
1508     if (!parent_feature)
1509         return INSTALLSTATE_UNKNOWN;
1510
1511     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1512     msi_free(parent_feature);
1513     if (r == INSTALLSTATE_ABSENT)
1514         return r;
1515
1516     /* now check if it's complete or advertised */
1517     rc = MSIREG_OpenUserDataFeaturesKey(szProduct, &hkey, FALSE);
1518     if (rc != ERROR_SUCCESS)
1519         return INSTALLSTATE_ADVERTISED;
1520
1521     components = msi_reg_get_val_str( hkey, szFeature );
1522     RegCloseKey(hkey);
1523
1524     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1525
1526     if (!components)
1527         return INSTALLSTATE_ADVERTISED;
1528
1529     for( p = components; *p && *p != 2 ; p += 20)
1530     {
1531         if (!decode_base85_guid( p, &guid ))
1532         {
1533             if (p != components)
1534                 break;
1535
1536             msi_free(components);
1537             return INSTALLSTATE_BADCONFIG;
1538         }
1539
1540         StringFromGUID2(&guid, comp, GUID_SIZE);
1541         rc = MSIREG_OpenUserDataComponentKey(comp, &hkey, FALSE);
1542         if (rc != ERROR_SUCCESS)
1543         {
1544             msi_free(components);
1545             return INSTALLSTATE_ADVERTISED;
1546         }
1547
1548         path = msi_reg_get_val_str(hkey, squishProduct);
1549         if (!path)
1550             missing = TRUE;
1551
1552         msi_free(path);
1553     }
1554
1555     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1556     msi_free(components);
1557
1558     if (missing)
1559         return INSTALLSTATE_ADVERTISED;
1560
1561     return INSTALLSTATE_LOCAL;
1562 }
1563
1564 /******************************************************************
1565  * MsiGetFileVersionA         [MSI.@]
1566  */
1567 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1568                 LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf)
1569 {
1570     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1571     UINT ret = ERROR_OUTOFMEMORY;
1572
1573     if ((lpVersionBuf && !pcchVersionBuf) ||
1574         (lpLangBuf && !pcchLangBuf))
1575         return ERROR_INVALID_PARAMETER;
1576
1577     if( szFilePath )
1578     {
1579         szwFilePath = strdupAtoW( szFilePath );
1580         if( !szwFilePath )
1581             goto end;
1582     }
1583
1584     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1585     {
1586         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1587         if( !lpwVersionBuff )
1588             goto end;
1589     }
1590
1591     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1592     {
1593         lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR));
1594         if( !lpwLangBuff )
1595             goto end;
1596     }
1597
1598     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1599                              lpwLangBuff, pcchLangBuf);
1600
1601     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff )
1602         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1603                             lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL);
1604     if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff )
1605         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1606                             lpLangBuf, *pcchLangBuf + 1, NULL, NULL);
1607
1608 end:
1609     msi_free(szwFilePath);
1610     msi_free(lpwVersionBuff);
1611     msi_free(lpwLangBuff);
1612
1613     return ret;
1614 }
1615
1616 /******************************************************************
1617  * MsiGetFileVersionW         [MSI.@]
1618  */
1619 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1620                 LPDWORD pcchVersionBuf, LPWSTR lpLangBuf, LPDWORD pcchLangBuf)
1621 {
1622     static const WCHAR szVersionResource[] = {'\\',0};
1623     static const WCHAR szVersionFormat[] = {
1624         '%','d','.','%','d','.','%','d','.','%','d',0};
1625     static const WCHAR szLangFormat[] = {'%','d',0};
1626     UINT ret = 0;
1627     DWORD dwVerLen, gle;
1628     LPVOID lpVer = NULL;
1629     VS_FIXEDFILEINFO *ffi;
1630     UINT puLen;
1631     WCHAR tmp[32];
1632
1633     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
1634           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1635           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1636
1637     if ((lpVersionBuf && !pcchVersionBuf) ||
1638         (lpLangBuf && !pcchLangBuf))
1639         return ERROR_INVALID_PARAMETER;
1640
1641     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1642     if( !dwVerLen )
1643     {
1644         gle = GetLastError();
1645         if (gle == ERROR_BAD_PATHNAME)
1646             return ERROR_FILE_NOT_FOUND;
1647         else if (gle == ERROR_RESOURCE_DATA_NOT_FOUND)
1648             return ERROR_FILE_INVALID;
1649
1650         return gle;
1651     }
1652
1653     lpVer = msi_alloc(dwVerLen);
1654     if( !lpVer )
1655     {
1656         ret = ERROR_OUTOFMEMORY;
1657         goto end;
1658     }
1659
1660     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1661     {
1662         ret = GetLastError();
1663         goto end;
1664     }
1665
1666     if (pcchVersionBuf)
1667     {
1668         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1669             (puLen > 0) )
1670         {
1671             wsprintfW(tmp, szVersionFormat,
1672                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1673                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1674             if (lpVersionBuf) lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1675
1676             if (lstrlenW(tmp) >= *pcchVersionBuf)
1677                 ret = ERROR_MORE_DATA;
1678
1679             *pcchVersionBuf = lstrlenW(tmp);
1680         }
1681         else
1682         {
1683             if (lpVersionBuf) *lpVersionBuf = 0;
1684             *pcchVersionBuf = 0;
1685         }
1686     }
1687
1688     if (pcchLangBuf)
1689     {
1690         DWORD lang = GetUserDefaultLangID();
1691
1692         FIXME("Retrieve language from file\n");
1693         wsprintfW(tmp, szLangFormat, lang);
1694         if (lpLangBuf) lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1695
1696         if (lstrlenW(tmp) >= *pcchLangBuf)
1697             ret = ERROR_MORE_DATA;
1698
1699         *pcchLangBuf = lstrlenW(tmp);
1700     }
1701
1702 end:
1703     msi_free(lpVer);
1704     return ret;
1705 }
1706
1707 /***********************************************************************
1708  * MsiGetFeatureUsageW           [MSI.@]
1709  */
1710 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1711                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
1712 {
1713     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1714           pdwUseCount, pwDateUsed);
1715     return ERROR_CALL_NOT_IMPLEMENTED;
1716 }
1717
1718 /***********************************************************************
1719  * MsiGetFeatureUsageA           [MSI.@]
1720  */
1721 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1722                                  LPDWORD pdwUseCount, LPWORD pwDateUsed )
1723 {
1724     LPWSTR prod = NULL, feat = NULL;
1725     UINT ret = ERROR_OUTOFMEMORY;
1726
1727     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1728           pdwUseCount, pwDateUsed);
1729
1730     prod = strdupAtoW( szProduct );
1731     if (szProduct && !prod)
1732         goto end;
1733
1734     feat = strdupAtoW( szFeature );
1735     if (szFeature && !feat)
1736         goto end;
1737
1738     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1739
1740 end:
1741     msi_free( prod );
1742     msi_free( feat );
1743
1744     return ret;
1745 }
1746
1747 /***********************************************************************
1748  * MsiUseFeatureExW           [MSI.@]
1749  */
1750 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1751                                       DWORD dwInstallMode, DWORD dwReserved )
1752 {
1753     INSTALLSTATE state;
1754
1755     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1756           dwInstallMode, dwReserved);
1757
1758     state = MsiQueryFeatureStateW( szProduct, szFeature );
1759
1760     if (dwReserved)
1761         return INSTALLSTATE_INVALIDARG;
1762
1763     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1764     {
1765         FIXME("mark product %s feature %s as used\n",
1766               debugstr_w(szProduct), debugstr_w(szFeature) );
1767     }
1768
1769     return state;
1770 }
1771
1772 /***********************************************************************
1773  * MsiUseFeatureExA           [MSI.@]
1774  */
1775 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1776                                       DWORD dwInstallMode, DWORD dwReserved )
1777 {
1778     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1779     LPWSTR prod = NULL, feat = NULL;
1780
1781     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1782           dwInstallMode, dwReserved);
1783
1784     prod = strdupAtoW( szProduct );
1785     if (szProduct && !prod)
1786         goto end;
1787
1788     feat = strdupAtoW( szFeature );
1789     if (szFeature && !feat)
1790         goto end;
1791
1792     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1793
1794 end:
1795     msi_free( prod );
1796     msi_free( feat );
1797
1798     return ret;
1799 }
1800
1801 /***********************************************************************
1802  * MsiUseFeatureW             [MSI.@]
1803  */
1804 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1805 {
1806     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
1807 }
1808
1809 /***********************************************************************
1810  * MsiUseFeatureA             [MSI.@]
1811  */
1812 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1813 {
1814     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
1815 }
1816
1817 /***********************************************************************
1818  * MSI_ProvideQualifiedComponentEx [internal]
1819  */
1820 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
1821                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
1822                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
1823                 LPDWORD pcchPathBuf)
1824 {
1825     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
1826           feature[MAX_FEATURE_CHARS+1];
1827     LPWSTR info;
1828     HKEY hkey;
1829     DWORD sz;
1830     UINT rc;
1831
1832     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
1833           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1834           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1835
1836     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1837     if (rc != ERROR_SUCCESS)
1838         return ERROR_INDEX_ABSENT;
1839
1840     info = msi_reg_get_val_str( hkey, szQualifier );
1841     RegCloseKey(hkey);
1842
1843     if (!info)
1844         return ERROR_INDEX_ABSENT;
1845
1846     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1847
1848     if (!szProduct)
1849         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
1850     else
1851         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
1852
1853     msi_free( info );
1854
1855     if (rc != INSTALLSTATE_LOCAL)
1856         return ERROR_FILE_NOT_FOUND;
1857
1858     return ERROR_SUCCESS;
1859 }
1860
1861 /***********************************************************************
1862  * MsiProvideQualifiedComponentExW [MSI.@]
1863  */
1864 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1865                 LPCWSTR szQualifier, DWORD dwInstallMode, LPCWSTR szProduct,
1866                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1867                 LPDWORD pcchPathBuf)
1868 {
1869     awstring path;
1870
1871     path.unicode = TRUE;
1872     path.str.w = lpPathBuf;
1873
1874     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
1875             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
1876 }
1877
1878 /***********************************************************************
1879  * MsiProvideQualifiedComponentExA [MSI.@]
1880  */
1881 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
1882                 LPCSTR szQualifier, DWORD dwInstallMode, LPCSTR szProduct,
1883                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
1884                 LPDWORD pcchPathBuf)
1885 {
1886     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
1887     UINT r = ERROR_OUTOFMEMORY;
1888     awstring path;
1889
1890     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
1891           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
1892           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1893
1894     szwComponent = strdupAtoW( szComponent );
1895     if (szComponent && !szwComponent)
1896         goto end;
1897
1898     szwQualifier = strdupAtoW( szQualifier );
1899     if (szQualifier && !szwQualifier)
1900         goto end;
1901
1902     szwProduct = strdupAtoW( szProduct );
1903     if (szProduct && !szwProduct)
1904         goto end;
1905
1906     path.unicode = FALSE;
1907     path.str.a = lpPathBuf;
1908
1909     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
1910                               dwInstallMode, szwProduct, Unused1,
1911                               Unused2, &path, pcchPathBuf);
1912 end:
1913     msi_free(szwProduct);
1914     msi_free(szwComponent);
1915     msi_free(szwQualifier);
1916
1917     return r;
1918 }
1919
1920 /***********************************************************************
1921  * MsiProvideQualifiedComponentW [MSI.@]
1922  */
1923 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1924                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1925                 LPDWORD pcchPathBuf)
1926 {
1927     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1928                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1929 }
1930
1931 /***********************************************************************
1932  * MsiProvideQualifiedComponentA [MSI.@]
1933  */
1934 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1935                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1936                 LPDWORD pcchPathBuf)
1937 {
1938     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
1939                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1940 }
1941
1942 /***********************************************************************
1943  * MSI_GetUserInfo [internal]
1944  */
1945 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
1946                 awstring *lpUserNameBuf, LPDWORD pcchUserNameBuf,
1947                 awstring *lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
1948                 awstring *lpSerialBuf, LPDWORD pcchSerialBuf)
1949 {
1950     HKEY hkey;
1951     LPWSTR user, org, serial;
1952     UINT r;
1953     USERINFOSTATE state;
1954
1955     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1956           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1957           pcchSerialBuf);
1958
1959     if (!szProduct)
1960         return USERINFOSTATE_INVALIDARG;
1961
1962     r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1963     if (r != ERROR_SUCCESS)
1964         return USERINFOSTATE_UNKNOWN;
1965
1966     user = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGOWNERW );
1967     org = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGCOMPANYW );
1968     serial = msi_reg_get_val_str( hkey, INSTALLPROPERTY_PRODUCTIDW );
1969
1970     RegCloseKey(hkey);
1971
1972     state = USERINFOSTATE_PRESENT;
1973
1974     if (user)
1975     {
1976         r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
1977         if (r == ERROR_MORE_DATA)
1978             state = USERINFOSTATE_MOREDATA;
1979     }
1980     else
1981         state = USERINFOSTATE_ABSENT;
1982     if (org)
1983     {
1984         r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
1985         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1986             state = USERINFOSTATE_MOREDATA;
1987     }
1988     /* msdn states: The user information is considered to be present even in the absence of a company name. */
1989     if (serial)
1990     {
1991         r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
1992         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1993             state = USERINFOSTATE_MOREDATA;
1994     }
1995     else
1996         state = USERINFOSTATE_ABSENT;
1997
1998     msi_free( user );
1999     msi_free( org );
2000     msi_free( serial );
2001
2002     return state;
2003 }
2004
2005 /***********************************************************************
2006  * MsiGetUserInfoW [MSI.@]
2007  */
2008 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
2009                 LPWSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2010                 LPWSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2011                 LPWSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2012 {
2013     awstring user, org, serial;
2014
2015     user.unicode = TRUE;
2016     user.str.w = lpUserNameBuf;
2017     org.unicode = TRUE;
2018     org.str.w = lpOrgNameBuf;
2019     serial.unicode = TRUE;
2020     serial.str.w = lpSerialBuf;
2021
2022     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
2023                             &org, pcchOrgNameBuf,
2024                             &serial, pcchSerialBuf );
2025 }
2026
2027 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
2028                 LPSTR lpUserNameBuf, LPDWORD pcchUserNameBuf,
2029                 LPSTR lpOrgNameBuf, LPDWORD pcchOrgNameBuf,
2030                 LPSTR lpSerialBuf, LPDWORD pcchSerialBuf)
2031 {
2032     awstring user, org, serial;
2033     LPWSTR prod;
2034     UINT r;
2035
2036     prod = strdupAtoW( szProduct );
2037     if (szProduct && !prod)
2038         return ERROR_OUTOFMEMORY;
2039
2040     user.unicode = FALSE;
2041     user.str.a = lpUserNameBuf;
2042     org.unicode = FALSE;
2043     org.str.a = lpOrgNameBuf;
2044     serial.unicode = FALSE;
2045     serial.str.a = lpSerialBuf;
2046
2047     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
2048                          &org, pcchOrgNameBuf,
2049                          &serial, pcchSerialBuf );
2050
2051     msi_free( prod );
2052
2053     return r;
2054 }
2055
2056 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
2057 {
2058     MSIHANDLE handle;
2059     UINT rc;
2060     MSIPACKAGE *package;
2061     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2062
2063     TRACE("(%s)\n",debugstr_w(szProduct));
2064
2065     rc = MsiOpenProductW(szProduct,&handle);
2066     if (rc != ERROR_SUCCESS)
2067         return ERROR_INVALID_PARAMETER;
2068
2069     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2070     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2071     msiobj_release( &package->hdr );
2072
2073     MsiCloseHandle(handle);
2074
2075     return rc;
2076 }
2077
2078 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
2079 {
2080     MSIHANDLE handle;
2081     UINT rc;
2082     MSIPACKAGE *package;
2083     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
2084
2085     TRACE("(%s)\n",debugstr_a(szProduct));
2086
2087     rc = MsiOpenProductA(szProduct,&handle);
2088     if (rc != ERROR_SUCCESS)
2089         return ERROR_INVALID_PARAMETER;
2090
2091     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
2092     rc = ACTION_PerformUIAction(package, szFirstRun, -1);
2093     msiobj_release( &package->hdr );
2094
2095     MsiCloseHandle(handle);
2096
2097     return rc;
2098 }
2099
2100 /***********************************************************************
2101  * MsiConfigureFeatureA            [MSI.@]
2102  */
2103 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
2104 {
2105     LPWSTR prod, feat = NULL;
2106     UINT r = ERROR_OUTOFMEMORY;
2107
2108     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
2109
2110     prod = strdupAtoW( szProduct );
2111     if (szProduct && !prod)
2112         goto end;
2113
2114     feat = strdupAtoW( szFeature );
2115     if (szFeature && !feat)
2116         goto end;
2117
2118     r = MsiConfigureFeatureW(prod, feat, eInstallState);
2119
2120 end:
2121     msi_free(feat);
2122     msi_free(prod);
2123
2124     return r;
2125 }
2126
2127 /***********************************************************************
2128  * MsiConfigureFeatureW            [MSI.@]
2129  */
2130 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
2131 {
2132     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
2133     MSIPACKAGE *package = NULL;
2134     UINT r;
2135     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
2136     DWORD sz;
2137
2138     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
2139
2140     if (!szProduct || !szFeature)
2141         return ERROR_INVALID_PARAMETER;
2142
2143     switch (eInstallState)
2144     {
2145     case INSTALLSTATE_DEFAULT:
2146         /* FIXME: how do we figure out the default location? */
2147         eInstallState = INSTALLSTATE_LOCAL;
2148         break;
2149     case INSTALLSTATE_LOCAL:
2150     case INSTALLSTATE_SOURCE:
2151     case INSTALLSTATE_ABSENT:
2152     case INSTALLSTATE_ADVERTISED:
2153         break;
2154     default:
2155         return ERROR_INVALID_PARAMETER;
2156     }
2157
2158     r = MSI_OpenProductW( szProduct, &package );
2159     if (r != ERROR_SUCCESS)
2160         return r;
2161
2162     sz = sizeof(sourcepath);
2163     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2164                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2165
2166     sz = sizeof(filename);
2167     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2168                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2169
2170     lstrcatW( sourcepath, filename );
2171
2172     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
2173
2174     r = ACTION_PerformUIAction( package, szCostInit, -1 );
2175     if (r != ERROR_SUCCESS)
2176         goto end;
2177
2178     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
2179     if (r != ERROR_SUCCESS)
2180         goto end;
2181
2182     r = MSI_InstallPackage( package, sourcepath, NULL );
2183
2184 end:
2185     msiobj_release( &package->hdr );
2186
2187     return r;
2188 }
2189
2190 /***********************************************************************
2191  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
2192  *
2193  * Notes: undocumented
2194  */
2195 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
2196 {
2197     WCHAR path[MAX_PATH];
2198
2199     TRACE("%d\n", dwReserved);
2200
2201     if (dwReserved)
2202     {
2203         FIXME("dwReserved=%d\n", dwReserved);
2204         return ERROR_INVALID_PARAMETER;
2205     }
2206
2207     if (!GetWindowsDirectoryW(path, MAX_PATH))
2208         return ERROR_FUNCTION_FAILED;
2209
2210     lstrcatW(path, installerW);
2211
2212     if (!CreateDirectoryW(path, NULL))
2213         return ERROR_FUNCTION_FAILED;
2214
2215     return ERROR_SUCCESS;
2216 }
2217
2218 /***********************************************************************
2219  * MsiGetShortcutTargetA           [MSI.@]
2220  */
2221 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
2222                                    LPSTR szProductCode, LPSTR szFeatureId,
2223                                    LPSTR szComponentCode )
2224 {
2225     LPWSTR target;
2226     const int len = MAX_FEATURE_CHARS+1;
2227     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
2228     UINT r;
2229
2230     target = strdupAtoW( szShortcutTarget );
2231     if (szShortcutTarget && !target )
2232         return ERROR_OUTOFMEMORY;
2233     product[0] = 0;
2234     feature[0] = 0;
2235     component[0] = 0;
2236     r = MsiGetShortcutTargetW( target, product, feature, component );
2237     msi_free( target );
2238     if (r == ERROR_SUCCESS)
2239     {
2240         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
2241         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
2242         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
2243     }
2244     return r;
2245 }
2246
2247 /***********************************************************************
2248  * MsiGetShortcutTargetW           [MSI.@]
2249  */
2250 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
2251                                    LPWSTR szProductCode, LPWSTR szFeatureId,
2252                                    LPWSTR szComponentCode )
2253 {
2254     IShellLinkDataList *dl = NULL;
2255     IPersistFile *pf = NULL;
2256     LPEXP_DARWIN_LINK darwin = NULL;
2257     HRESULT r, init;
2258
2259     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
2260           szProductCode, szFeatureId, szComponentCode );
2261
2262     init = CoInitialize(NULL);
2263
2264     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2265                           &IID_IPersistFile, (LPVOID*) &pf );
2266     if( SUCCEEDED( r ) )
2267     {
2268         r = IPersistFile_Load( pf, szShortcutTarget,
2269                                STGM_READ | STGM_SHARE_DENY_WRITE );
2270         if( SUCCEEDED( r ) )
2271         {
2272             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
2273                                              (LPVOID*) &dl );
2274             if( SUCCEEDED( r ) )
2275             {
2276                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
2277                                                   (LPVOID) &darwin );
2278                 IShellLinkDataList_Release( dl );
2279             }
2280         }
2281         IPersistFile_Release( pf );
2282     }
2283
2284     if (SUCCEEDED(init))
2285         CoUninitialize();
2286
2287     TRACE("darwin = %p\n", darwin);
2288
2289     if (darwin)
2290     {
2291         DWORD sz;
2292         UINT ret;
2293
2294         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
2295                   szProductCode, szFeatureId, szComponentCode, &sz );
2296         LocalFree( darwin );
2297         return ret;
2298     }
2299
2300     return ERROR_FUNCTION_FAILED;
2301 }
2302
2303 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
2304                                   DWORD dwReinstallMode )
2305 {
2306     MSIPACKAGE* package = NULL;
2307     UINT r;
2308     WCHAR sourcepath[MAX_PATH];
2309     WCHAR filename[MAX_PATH];
2310     static const WCHAR szLogVerbose[] = {
2311         ' ','L','O','G','V','E','R','B','O','S','E',0 };
2312     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
2313     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
2314     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
2315     static const WCHAR szOne[] = {'1',0};
2316     WCHAR reinstallmode[11];
2317     LPWSTR ptr;
2318     DWORD sz;
2319
2320     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
2321                            dwReinstallMode);
2322
2323     ptr = reinstallmode;
2324
2325     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
2326         *ptr++ = 'p';
2327     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
2328         *ptr++ = 'o';
2329     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
2330         *ptr++ = 'w';
2331     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
2332         *ptr++ = 'd';
2333     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
2334         *ptr++ = 'c';
2335     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
2336         *ptr++ = 'a';
2337     if (dwReinstallMode & REINSTALLMODE_USERDATA)
2338         *ptr++ = 'u';
2339     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
2340         *ptr++ = 'm';
2341     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
2342         *ptr++ = 's';
2343     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2344         *ptr++ = 'v';
2345     *ptr = 0;
2346     
2347     sz = sizeof(sourcepath);
2348     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2349             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
2350
2351     sz = sizeof(filename);
2352     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
2353             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
2354
2355     lstrcatW( sourcepath, filename );
2356
2357     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
2358         r = MSI_OpenPackageW( sourcepath, &package );
2359     else
2360         r = MSI_OpenProductW( szProduct, &package );
2361
2362     if (r != ERROR_SUCCESS)
2363         return r;
2364
2365     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
2366     MSI_SetPropertyW( package, szInstalled, szOne );
2367     MSI_SetPropertyW( package, szLogVerbose, szOne );
2368     MSI_SetPropertyW( package, szReinstall, szFeature );
2369
2370     r = MSI_InstallPackage( package, sourcepath, NULL );
2371
2372     msiobj_release( &package->hdr );
2373
2374     return r;
2375 }
2376
2377 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
2378                                   DWORD dwReinstallMode )
2379 {
2380     LPWSTR wszProduct;
2381     LPWSTR wszFeature;
2382     UINT rc;
2383
2384     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
2385                            dwReinstallMode);
2386
2387     wszProduct = strdupAtoW(szProduct);
2388     wszFeature = strdupAtoW(szFeature);
2389
2390     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
2391
2392     msi_free(wszProduct);
2393     msi_free(wszFeature);
2394     return rc;
2395 }
2396
2397 typedef struct
2398 {
2399     unsigned int i[2];
2400     unsigned int buf[4];
2401     unsigned char in[64];
2402     unsigned char digest[16];
2403 } MD5_CTX;
2404
2405 extern VOID WINAPI MD5Init( MD5_CTX *);
2406 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2407 extern VOID WINAPI MD5Final( MD5_CTX *);
2408
2409 /***********************************************************************
2410  * MsiGetFileHashW            [MSI.@]
2411  */
2412 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2413                              PMSIFILEHASHINFO pHash )
2414 {
2415     HANDLE handle, mapping;
2416     void *p;
2417     DWORD length;
2418     UINT r = ERROR_FUNCTION_FAILED;
2419
2420     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2421
2422     if (!szFilePath)
2423         return ERROR_INVALID_PARAMETER;
2424
2425     if (!*szFilePath)
2426         return ERROR_PATH_NOT_FOUND;
2427
2428     if (dwOptions)
2429         return ERROR_INVALID_PARAMETER;
2430     if (!pHash)
2431         return ERROR_INVALID_PARAMETER;
2432     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2433         return ERROR_INVALID_PARAMETER;
2434
2435     handle = CreateFileW( szFilePath, GENERIC_READ,
2436                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2437     if (handle == INVALID_HANDLE_VALUE)
2438         return ERROR_FILE_NOT_FOUND;
2439
2440     length = GetFileSize( handle, NULL );
2441
2442     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2443     if (mapping)
2444     {
2445         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2446         if (p)
2447         {
2448             MD5_CTX ctx;
2449
2450             MD5Init( &ctx );
2451             MD5Update( &ctx, p, length );
2452             MD5Final( &ctx );
2453             UnmapViewOfFile( p );
2454
2455             memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
2456             r = ERROR_SUCCESS;
2457         }
2458         CloseHandle( mapping );
2459     }
2460     CloseHandle( handle );
2461
2462     return r;
2463 }
2464
2465 /***********************************************************************
2466  * MsiGetFileHashA            [MSI.@]
2467  */
2468 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2469                              PMSIFILEHASHINFO pHash )
2470 {
2471     LPWSTR file;
2472     UINT r;
2473
2474     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2475
2476     file = strdupAtoW( szFilePath );
2477     if (szFilePath && !file)
2478         return ERROR_OUTOFMEMORY;
2479
2480     r = MsiGetFileHashW( file, dwOptions, pHash );
2481     msi_free( file );
2482     return r;
2483 }
2484
2485 /***********************************************************************
2486  * MsiAdvertiseScriptW        [MSI.@]
2487  */
2488 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2489                                  PHKEY phRegData, BOOL fRemoveItems )
2490 {
2491     FIXME("%s %08x %p %d\n",
2492           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2493     return ERROR_CALL_NOT_IMPLEMENTED;
2494 }
2495
2496 /***********************************************************************
2497  * MsiAdvertiseScriptA        [MSI.@]
2498  */
2499 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2500                                  PHKEY phRegData, BOOL fRemoveItems )
2501 {
2502     FIXME("%s %08x %p %d\n",
2503           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2504     return ERROR_CALL_NOT_IMPLEMENTED;
2505 }