mcicda: Exclude unused headers.
[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 const 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     if (user)
1566     {
1567         r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
1568         if (r == ERROR_MORE_DATA)
1569             state = USERINFOSTATE_MOREDATA;
1570     }
1571     else
1572         state = USERINFOSTATE_ABSENT;
1573     if (org)
1574     {
1575         r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
1576         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1577             state = USERINFOSTATE_MOREDATA;
1578     }
1579     /* msdn states: The user information is considered to be present even in the absence of a company name. */
1580     if (serial)
1581     {
1582         r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
1583         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1584             state = USERINFOSTATE_MOREDATA;
1585     }
1586     else
1587         state = USERINFOSTATE_ABSENT;
1588
1589     msi_free( user );
1590     msi_free( org );
1591     msi_free( serial );
1592
1593     return state;
1594 }
1595
1596 /***********************************************************************
1597  * MsiGetUserInfoW [MSI.@]
1598  */
1599 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
1600                 LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1601                 LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1602                 LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1603 {
1604     awstring user, org, serial;
1605
1606     user.unicode = TRUE;
1607     user.str.w = lpUserNameBuf;
1608     org.unicode = TRUE;
1609     org.str.w = lpOrgNameBuf;
1610     serial.unicode = TRUE;
1611     serial.str.w = lpSerialBuf;
1612
1613     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
1614                             &org, pcchOrgNameBuf,
1615                             &serial, pcchSerialBuf );
1616 }
1617
1618 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
1619                 LPSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1620                 LPSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1621                 LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1622 {
1623     awstring user, org, serial;
1624     LPWSTR prod;
1625     UINT r;
1626
1627     prod = strdupAtoW( szProduct );
1628     if (szProduct && !prod)
1629         return ERROR_OUTOFMEMORY;
1630
1631     user.unicode = FALSE;
1632     user.str.a = lpUserNameBuf;
1633     org.unicode = FALSE;
1634     org.str.a = lpOrgNameBuf;
1635     serial.unicode = FALSE;
1636     serial.str.a = lpSerialBuf;
1637
1638     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
1639                          &org, pcchOrgNameBuf,
1640                          &serial, pcchSerialBuf );
1641
1642     msi_free( prod );
1643
1644     return r;
1645 }
1646
1647 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1648 {
1649     MSIHANDLE handle;
1650     UINT rc;
1651     MSIPACKAGE *package;
1652     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1653
1654     TRACE("(%s)\n",debugstr_w(szProduct));
1655
1656     rc = MsiOpenProductW(szProduct,&handle);
1657     if (rc != ERROR_SUCCESS)
1658         return ERROR_INVALID_PARAMETER;
1659
1660     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1661     rc = ACTION_PerformUIAction(package, szFirstRun);
1662     msiobj_release( &package->hdr );
1663
1664     MsiCloseHandle(handle);
1665
1666     return rc;
1667 }
1668
1669 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1670 {
1671     MSIHANDLE handle;
1672     UINT rc;
1673     MSIPACKAGE *package;
1674     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1675
1676     TRACE("(%s)\n",debugstr_a(szProduct));
1677
1678     rc = MsiOpenProductA(szProduct,&handle);
1679     if (rc != ERROR_SUCCESS)
1680         return ERROR_INVALID_PARAMETER;
1681
1682     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1683     rc = ACTION_PerformUIAction(package, szFirstRun);
1684     msiobj_release( &package->hdr );
1685
1686     MsiCloseHandle(handle);
1687
1688     return rc;
1689 }
1690
1691 /***********************************************************************
1692  * MsiConfigureFeatureA            [MSI.@]
1693  */
1694 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1695 {
1696     LPWSTR prod, feat = NULL;
1697     UINT r = ERROR_OUTOFMEMORY;
1698
1699     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1700
1701     prod = strdupAtoW( szProduct );
1702     if (szProduct && !prod)
1703         goto end;
1704
1705     feat = strdupAtoW( szFeature );
1706     if (szFeature && !feat)
1707         goto end;
1708
1709     r = MsiConfigureFeatureW(prod, feat, eInstallState);
1710
1711 end:
1712     msi_free(feat);
1713     msi_free(prod);
1714
1715     return r;
1716 }
1717
1718 /***********************************************************************
1719  * MsiConfigureFeatureW            [MSI.@]
1720  */
1721 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1722 {
1723     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1724     MSIPACKAGE *package = NULL;
1725     UINT r;
1726     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
1727     DWORD sz;
1728
1729     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1730
1731     if (!szProduct || !szFeature)
1732         return ERROR_INVALID_PARAMETER;
1733
1734     switch (eInstallState)
1735     {
1736     case INSTALLSTATE_DEFAULT:
1737         /* FIXME: how do we figure out the default location? */
1738         eInstallState = INSTALLSTATE_LOCAL;
1739         break;
1740     case INSTALLSTATE_LOCAL:
1741     case INSTALLSTATE_SOURCE:
1742     case INSTALLSTATE_ABSENT:
1743     case INSTALLSTATE_ADVERTISED:
1744         break;
1745     default:
1746         return ERROR_INVALID_PARAMETER;
1747     }
1748
1749     r = MSI_OpenProductW( szProduct, &package );
1750     if (r != ERROR_SUCCESS)
1751         return r;
1752
1753     sz = sizeof(sourcepath);
1754     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1755                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1756
1757     sz = sizeof(filename);
1758     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1759                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1760
1761     lstrcatW( sourcepath, filename );
1762
1763     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
1764
1765     r = ACTION_PerformUIAction( package, szCostInit );
1766     if (r != ERROR_SUCCESS)
1767         goto end;
1768
1769     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
1770     if (r != ERROR_SUCCESS)
1771         goto end;
1772
1773     r = MSI_InstallPackage( package, sourcepath, NULL );
1774
1775 end:
1776     msiobj_release( &package->hdr );
1777
1778     return r;
1779 }
1780
1781 /***********************************************************************
1782  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
1783  *
1784  * Notes: undocumented
1785  */
1786 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1787 {
1788     WCHAR path[MAX_PATH];
1789
1790     TRACE("%d\n", dwReserved);
1791
1792     if (dwReserved)
1793     {
1794         FIXME("dwReserved=%d\n", dwReserved);
1795         return ERROR_INVALID_PARAMETER;
1796     }
1797
1798     if (!GetWindowsDirectoryW(path, MAX_PATH))
1799         return ERROR_FUNCTION_FAILED;
1800
1801     lstrcatW(path, installerW);
1802
1803     if (!CreateDirectoryW(path, NULL))
1804         return ERROR_FUNCTION_FAILED;
1805
1806     return ERROR_SUCCESS;
1807 }
1808
1809 /***********************************************************************
1810  * MsiGetShortcutTargetA           [MSI.@]
1811  */
1812 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1813                                    LPSTR szProductCode, LPSTR szFeatureId,
1814                                    LPSTR szComponentCode )
1815 {
1816     LPWSTR target;
1817     const int len = MAX_FEATURE_CHARS+1;
1818     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1819     UINT r;
1820
1821     target = strdupAtoW( szShortcutTarget );
1822     if (szShortcutTarget && !target )
1823         return ERROR_OUTOFMEMORY;
1824     product[0] = 0;
1825     feature[0] = 0;
1826     component[0] = 0;
1827     r = MsiGetShortcutTargetW( target, product, feature, component );
1828     msi_free( target );
1829     if (r == ERROR_SUCCESS)
1830     {
1831         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1832         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1833         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1834     }
1835     return r;
1836 }
1837
1838 /***********************************************************************
1839  * MsiGetShortcutTargetW           [MSI.@]
1840  */
1841 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1842                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1843                                    LPWSTR szComponentCode )
1844 {
1845     IShellLinkDataList *dl = NULL;
1846     IPersistFile *pf = NULL;
1847     LPEXP_DARWIN_LINK darwin = NULL;
1848     HRESULT r, init;
1849
1850     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1851           szProductCode, szFeatureId, szComponentCode );
1852
1853     init = CoInitialize(NULL);
1854
1855     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1856                           &IID_IPersistFile, (LPVOID*) &pf );
1857     if( SUCCEEDED( r ) )
1858     {
1859         r = IPersistFile_Load( pf, szShortcutTarget,
1860                                STGM_READ | STGM_SHARE_DENY_WRITE );
1861         if( SUCCEEDED( r ) )
1862         {
1863             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1864                                              (LPVOID*) &dl );
1865             if( SUCCEEDED( r ) )
1866             {
1867                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1868                                                   (LPVOID) &darwin );
1869                 IShellLinkDataList_Release( dl );
1870             }
1871         }
1872         IPersistFile_Release( pf );
1873     }
1874
1875     if (SUCCEEDED(init))
1876         CoUninitialize();
1877
1878     TRACE("darwin = %p\n", darwin);
1879
1880     if (darwin)
1881     {
1882         DWORD sz;
1883         UINT ret;
1884
1885         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1886                   szProductCode, szFeatureId, szComponentCode, &sz );
1887         LocalFree( darwin );
1888         return ret;
1889     }
1890
1891     return ERROR_FUNCTION_FAILED;
1892 }
1893
1894 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1895                                   DWORD dwReinstallMode )
1896 {
1897     MSIPACKAGE* package = NULL;
1898     UINT r;
1899     WCHAR sourcepath[MAX_PATH];
1900     WCHAR filename[MAX_PATH];
1901     static const WCHAR szLogVerbose[] = {
1902         ' ','L','O','G','V','E','R','B','O','S','E',0 };
1903     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
1904     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
1905     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
1906     static const WCHAR szOne[] = {'1',0};
1907     WCHAR reinstallmode[11];
1908     LPWSTR ptr;
1909     DWORD sz;
1910
1911     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1912                            dwReinstallMode);
1913
1914     ptr = reinstallmode;
1915
1916     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
1917         *ptr++ = 'p';
1918     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
1919         *ptr++ = 'o';
1920     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
1921         *ptr++ = 'w';
1922     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
1923         *ptr++ = 'd';
1924     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
1925         *ptr++ = 'c';
1926     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
1927         *ptr++ = 'a';
1928     if (dwReinstallMode & REINSTALLMODE_USERDATA)
1929         *ptr++ = 'u';
1930     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
1931         *ptr++ = 'm';
1932     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
1933         *ptr++ = 's';
1934     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1935         *ptr++ = 'v';
1936     *ptr = 0;
1937     
1938     sz = sizeof(sourcepath);
1939     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1940             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1941
1942     sz = sizeof(filename);
1943     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1944             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1945
1946     lstrcatW( sourcepath, filename );
1947
1948     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1949         r = MSI_OpenPackageW( sourcepath, &package );
1950     else
1951         r = MSI_OpenProductW( szProduct, &package );
1952
1953     if (r != ERROR_SUCCESS)
1954         return r;
1955
1956     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
1957     MSI_SetPropertyW( package, szInstalled, szOne );
1958     MSI_SetPropertyW( package, szLogVerbose, szOne );
1959     MSI_SetPropertyW( package, szReinstall, szFeature );
1960
1961     r = MSI_InstallPackage( package, sourcepath, NULL );
1962
1963     msiobj_release( &package->hdr );
1964
1965     return r;
1966 }
1967
1968 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1969                                   DWORD dwReinstallMode )
1970 {
1971     LPWSTR wszProduct;
1972     LPWSTR wszFeature;
1973     UINT rc;
1974
1975     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1976                            dwReinstallMode);
1977
1978     wszProduct = strdupAtoW(szProduct);
1979     wszFeature = strdupAtoW(szFeature);
1980
1981     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
1982
1983     msi_free(wszProduct);
1984     msi_free(wszFeature);
1985     return rc;
1986 }
1987
1988 typedef struct
1989 {
1990     unsigned int i[2];
1991     unsigned int buf[4];
1992     unsigned char in[64];
1993     unsigned char digest[16];
1994 } MD5_CTX;
1995
1996 extern VOID WINAPI MD5Init( MD5_CTX *);
1997 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
1998 extern VOID WINAPI MD5Final( MD5_CTX *);
1999
2000 /***********************************************************************
2001  * MsiGetFileHashW            [MSI.@]
2002  */
2003 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2004                              PMSIFILEHASHINFO pHash )
2005 {
2006     HANDLE handle, mapping;
2007     void *p;
2008     DWORD length;
2009     UINT r = ERROR_FUNCTION_FAILED;
2010
2011     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2012
2013     if (dwOptions)
2014         return ERROR_INVALID_PARAMETER;
2015     if (!pHash)
2016         return ERROR_INVALID_PARAMETER;
2017     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2018         return ERROR_INVALID_PARAMETER;
2019
2020     handle = CreateFileW( szFilePath, GENERIC_READ,
2021                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2022     if (handle == INVALID_HANDLE_VALUE)
2023         return ERROR_FILE_NOT_FOUND;
2024
2025     length = GetFileSize( handle, NULL );
2026
2027     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2028     if (mapping)
2029     {
2030         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2031         if (p)
2032         {
2033             MD5_CTX ctx;
2034
2035             MD5Init( &ctx );
2036             MD5Update( &ctx, p, length );
2037             MD5Final( &ctx );
2038             UnmapViewOfFile( p );
2039
2040             memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
2041             r = ERROR_SUCCESS;
2042         }
2043         CloseHandle( mapping );
2044     }
2045     CloseHandle( handle );
2046
2047     return r;
2048 }
2049
2050 /***********************************************************************
2051  * MsiGetFileHashA            [MSI.@]
2052  */
2053 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2054                              PMSIFILEHASHINFO pHash )
2055 {
2056     LPWSTR file;
2057     UINT r;
2058
2059     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2060
2061     file = strdupAtoW( szFilePath );
2062     if (szFilePath && !file)
2063         return ERROR_OUTOFMEMORY;
2064
2065     r = MsiGetFileHashW( file, dwOptions, pHash );
2066     msi_free( file );
2067     return r;
2068 }
2069
2070 /***********************************************************************
2071  * MsiAdvertiseScriptW        [MSI.@]
2072  */
2073 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2074                                  PHKEY phRegData, BOOL fRemoveItems )
2075 {
2076     FIXME("%s %08x %p %d\n",
2077           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2078     return ERROR_CALL_NOT_IMPLEMENTED;
2079 }
2080
2081 /***********************************************************************
2082  * MsiAdvertiseScriptA        [MSI.@]
2083  */
2084 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2085                                  PHKEY phRegData, BOOL fRemoveItems )
2086 {
2087     FIXME("%s %08x %p %d\n",
2088           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2089     return ERROR_CALL_NOT_IMPLEMENTED;
2090 }