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