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