msi: Return appropriate values for empty MsiProductInfo parameters.
[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 || !szProduct[0] || !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 if (!szAttribute[0])
509     {
510         return ERROR_UNKNOWN_PROPERTY;
511     }
512     else
513     {
514         static const WCHAR szDisplayVersion[] = {
515             'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0 };
516
517         FIXME("%s\n", debugstr_w(szAttribute));
518         /* FIXME: some attribute values not tested... */
519
520         if (!lstrcmpW( szAttribute, INSTALLPROPERTY_VERSIONSTRINGW ))
521             szAttribute = szDisplayVersion;
522
523         r = MSIREG_OpenUninstallKey( szProduct, &hkey, FALSE );
524         if (r != ERROR_SUCCESS)
525             return ERROR_UNKNOWN_PRODUCT;
526
527         val = msi_reg_get_val_str( hkey, szAttribute );
528
529         RegCloseKey(hkey);
530     }
531
532     TRACE("returning %s\n", debugstr_w(val));
533
534     if (!val)
535         return ERROR_UNKNOWN_PROPERTY;
536
537     r = msi_strcpy_to_awstring( val, szValue, pcchValueBuf );
538
539     msi_free(val);
540
541     return r;
542 }
543
544 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
545                                LPSTR szBuffer, DWORD *pcchValueBuf)
546 {
547     LPWSTR szwProduct, szwAttribute = NULL;
548     UINT r = ERROR_OUTOFMEMORY;
549     awstring buffer;
550
551     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
552           szBuffer, pcchValueBuf);
553
554     szwProduct = strdupAtoW( szProduct );
555     if( szProduct && !szwProduct )
556         goto end;
557
558     szwAttribute = strdupAtoW( szAttribute );
559     if( szAttribute && !szwAttribute )
560         goto end;
561
562     buffer.unicode = FALSE;
563     buffer.str.a = szBuffer;
564
565     r = MSI_GetProductInfo( szwProduct, szwAttribute,
566                             &buffer, pcchValueBuf );
567
568 end:
569     msi_free( szwProduct );
570     msi_free( szwAttribute );
571
572     return r;
573 }
574
575 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
576                                LPWSTR szBuffer, DWORD *pcchValueBuf)
577 {
578     awstring buffer;
579
580     TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szAttribute),
581           szBuffer, pcchValueBuf);
582
583     buffer.unicode = TRUE;
584     buffer.str.w = szBuffer;
585
586     return MSI_GetProductInfo( szProduct, szAttribute,
587                                &buffer, pcchValueBuf );
588 }
589
590 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
591 {
592     LPWSTR szwLogFile = NULL;
593     UINT r;
594
595     TRACE("%08x %s %08x\n", dwLogMode, debugstr_a(szLogFile), attributes);
596
597     if( szLogFile )
598     {
599         szwLogFile = strdupAtoW( szLogFile );
600         if( !szwLogFile )
601             return ERROR_OUTOFMEMORY;
602     }
603     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
604     msi_free( szwLogFile );
605     return r;
606 }
607
608 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
609 {
610     HANDLE file = INVALID_HANDLE_VALUE;
611
612     TRACE("%08x %s %08x\n", dwLogMode, debugstr_w(szLogFile), attributes);
613
614     if (szLogFile)
615     {
616         lstrcpyW(gszLogFile,szLogFile);
617         if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
618             DeleteFileW(szLogFile);
619         file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
620                                FILE_ATTRIBUTE_NORMAL, NULL);
621         if (file != INVALID_HANDLE_VALUE)
622             CloseHandle(file);
623         else
624             ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
625     }
626     else
627         gszLogFile[0] = '\0';
628
629     return ERROR_SUCCESS;
630 }
631
632 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
633 {
634     LPWSTR szwProduct = NULL;
635     INSTALLSTATE r;
636
637     if( szProduct )
638     {
639          szwProduct = strdupAtoW( szProduct );
640          if( !szwProduct )
641              return ERROR_OUTOFMEMORY;
642     }
643     r = MsiQueryProductStateW( szwProduct );
644     msi_free( szwProduct );
645     return r;
646 }
647
648 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
649 {
650     UINT rc;
651     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
652     HKEY hkey = 0;
653     static const WCHAR szWindowsInstaller[] = {
654          'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 };
655     DWORD sz;
656
657     TRACE("%s\n", debugstr_w(szProduct));
658
659     if (!szProduct)
660         return INSTALLSTATE_INVALIDARG;
661
662     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
663     if (rc != ERROR_SUCCESS)
664         goto end;
665
666     RegCloseKey(hkey);
667
668     rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE);
669     if (rc != ERROR_SUCCESS)
670         goto end;
671
672     sz = sizeof(rrc);
673     rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz);
674     if (rc != ERROR_SUCCESS)
675         goto end;
676
677     switch (rrc)
678     {
679     case 1:
680         /* default */
681         rrc = INSTALLSTATE_DEFAULT;
682         break;
683     default:
684         FIXME("Unknown install state read from registry (%i)\n",rrc);
685         rrc = INSTALLSTATE_UNKNOWN;
686         break;
687     }
688 end:
689     RegCloseKey(hkey);
690     return rrc;
691 }
692
693 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
694 {
695     INSTALLUILEVEL old = gUILevel;
696     HWND oldwnd = gUIhwnd;
697
698     TRACE("%08x %p\n", dwUILevel, phWnd);
699
700     gUILevel = dwUILevel;
701     if (phWnd)
702     {
703         gUIhwnd = *phWnd;
704         *phWnd = oldwnd;
705     }
706     return old;
707 }
708
709 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
710                                   DWORD dwMessageFilter, LPVOID pvContext)
711 {
712     INSTALLUI_HANDLERA prev = gUIHandlerA;
713
714     TRACE("%p %x %p\n",puiHandler, dwMessageFilter,pvContext);
715     gUIHandlerA = puiHandler;
716     gUIFilter = dwMessageFilter;
717     gUIContext = pvContext;
718
719     return prev;
720 }
721
722 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
723                                   DWORD dwMessageFilter, LPVOID pvContext)
724 {
725     INSTALLUI_HANDLERW prev = gUIHandlerW;
726
727     TRACE("%p %x %p\n",puiHandler,dwMessageFilter,pvContext);
728     gUIHandlerW = puiHandler;
729     gUIFilter = dwMessageFilter;
730     gUIContext = pvContext;
731
732     return prev;
733 }
734
735 /******************************************************************
736  *  MsiLoadStringW            [MSI.@]
737  *
738  * Loads a string from MSI's string resources.
739  *
740  * PARAMS
741  *
742  *   handle        [I]  only -1 is handled currently
743  *   id            [I]  id of the string to be loaded
744  *   lpBuffer      [O]  buffer for the string to be written to
745  *   nBufferMax    [I]  maximum size of the buffer in characters
746  *   lang          [I]  the preferred language for the string
747  *
748  * RETURNS
749  *
750  *   If successful, this function returns the language id of the string loaded
751  *   If the function fails, the function returns zero.
752  *
753  * NOTES
754  *
755  *   The type of the first parameter is unknown.  LoadString's prototype
756  *  suggests that it might be a module handle.  I have made it an MSI handle
757  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
758  *  handle.  Maybe strings can be stored in an MSI database somehow.
759  */
760 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
761                 int nBufferMax, LANGID lang )
762 {
763     HRSRC hres;
764     HGLOBAL hResData;
765     LPWSTR p;
766     DWORD i, len;
767
768     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
769
770     if( handle != -1 )
771         FIXME("don't know how to deal with handle = %08lx\n", handle);
772
773     if( !lang )
774         lang = GetUserDefaultLangID();
775
776     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
777                             (LPWSTR)1, lang );
778     if( !hres )
779         return 0;
780     hResData = LoadResource( msi_hInstance, hres );
781     if( !hResData )
782         return 0;
783     p = LockResource( hResData );
784     if( !p )
785         return 0;
786
787     for (i = 0; i < (id&0xf); i++)
788         p += *p + 1;
789     len = *p;
790
791     if( nBufferMax <= len )
792         return 0;
793
794     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
795     lpBuffer[ len ] = 0;
796
797     TRACE("found -> %s\n", debugstr_w(lpBuffer));
798
799     return lang;
800 }
801
802 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
803                 int nBufferMax, LANGID lang )
804 {
805     LPWSTR bufW;
806     LANGID r;
807     DWORD len;
808
809     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
810     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
811     if( r )
812     {
813         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
814         if( len <= nBufferMax )
815             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
816                                  lpBuffer, nBufferMax, NULL, NULL );
817         else
818             r = 0;
819     }
820     msi_free(bufW);
821     return r;
822 }
823
824 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
825                 DWORD *pcchBuf)
826 {
827     char szProduct[GUID_SIZE];
828
829     TRACE("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
830
831     if (MsiGetProductCodeA( szComponent, szProduct ) != ERROR_SUCCESS)
832         return INSTALLSTATE_UNKNOWN;
833
834     return MsiGetComponentPathA( szProduct, szComponent, lpPathBuf, pcchBuf );
835 }
836
837 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
838                 DWORD *pcchBuf)
839 {
840     WCHAR szProduct[GUID_SIZE];
841
842     TRACE("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
843
844     if (MsiGetProductCodeW( szComponent, szProduct ) != ERROR_SUCCESS)
845         return INSTALLSTATE_UNKNOWN;
846
847     return MsiGetComponentPathW( szProduct, szComponent, lpPathBuf, pcchBuf );
848 }
849
850 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
851                 WORD wLanguageId, DWORD f)
852 {
853     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_a(lpText), debugstr_a(lpCaption),
854           uType, wLanguageId, f);
855     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
856 }
857
858 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
859                 WORD wLanguageId, DWORD f)
860 {
861     FIXME("%p %s %s %u %08x %08x\n", hWnd, debugstr_w(lpText), debugstr_w(lpCaption),
862           uType, wLanguageId, f);
863     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
864 }
865
866 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
867                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
868                 DWORD* pcchPathBuf )
869 {
870     FIXME("%s %s %08x %08x %p %p\n", debugstr_a(szAssemblyName),
871           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
872           pcchPathBuf);
873     return ERROR_CALL_NOT_IMPLEMENTED;
874 }
875
876 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
877                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
878                 DWORD* pcchPathBuf )
879 {
880     FIXME("%s %s %08x %08x %p %p\n", debugstr_w(szAssemblyName),
881           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
882           pcchPathBuf);
883     return ERROR_CALL_NOT_IMPLEMENTED;
884 }
885
886 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
887                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
888 {
889     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
890     return ERROR_CALL_NOT_IMPLEMENTED;
891 }
892
893 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
894                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
895 {
896     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
897     return ERROR_CALL_NOT_IMPLEMENTED;
898 }
899
900 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
901                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
902                 DWORD* pcbHashData)
903 {
904     FIXME("%s %08x %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
905           ppcCertContext, pbHashData, pcbHashData);
906     return ERROR_CALL_NOT_IMPLEMENTED;
907 }
908
909 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
910                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
911                 DWORD* pcbHashData)
912 {
913     FIXME("%s %08x %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
914           ppcCertContext, pbHashData, pcbHashData);
915     return ERROR_CALL_NOT_IMPLEMENTED;
916 }
917
918 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
919                                     LPSTR szValue, DWORD *pccbValue )
920 {
921     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
922     return ERROR_CALL_NOT_IMPLEMENTED;
923 }
924
925 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
926                                     LPWSTR szValue, DWORD *pccbValue )
927 {
928     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
929     return ERROR_CALL_NOT_IMPLEMENTED;
930 }
931
932 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
933 {
934     UINT r;
935     LPWSTR szPack = NULL;
936
937     TRACE("%s\n", debugstr_a(szPackage) );
938
939     if( szPackage )
940     {
941         szPack = strdupAtoW( szPackage );
942         if( !szPack )
943             return ERROR_OUTOFMEMORY;
944     }
945
946     r = MsiVerifyPackageW( szPack );
947
948     msi_free( szPack );
949
950     return r;
951 }
952
953 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
954 {
955     MSIHANDLE handle;
956     UINT r;
957
958     TRACE("%s\n", debugstr_w(szPackage) );
959
960     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
961     MsiCloseHandle( handle );
962
963     return r;
964 }
965
966 static INSTALLSTATE WINAPI MSI_GetComponentPath(LPCWSTR szProduct, LPCWSTR szComponent,
967                                                 awstring* lpPathBuf, DWORD* pcchBuf)
968 {
969     WCHAR squished_pc[GUID_SIZE], squished_comp[GUID_SIZE];
970     UINT rc;
971     HKEY hkey = 0;
972     LPWSTR path = NULL;
973     INSTALLSTATE r;
974
975     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
976            debugstr_w(szComponent), lpPathBuf->str.w, pcchBuf);
977
978     if( !szProduct || !szComponent )
979         return INSTALLSTATE_INVALIDARG;
980     if( lpPathBuf->str.w && !pcchBuf )
981         return INSTALLSTATE_INVALIDARG;
982
983     if (!squash_guid( szProduct, squished_pc ) ||
984         !squash_guid( szComponent, squished_comp ))
985         return INSTALLSTATE_INVALIDARG;
986
987     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
988     if( rc != ERROR_SUCCESS )
989         return INSTALLSTATE_UNKNOWN;
990
991     RegCloseKey(hkey);
992
993     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
994     if( rc != ERROR_SUCCESS )
995         return INSTALLSTATE_UNKNOWN;
996
997     path = msi_reg_get_val_str( hkey, squished_pc );
998     RegCloseKey(hkey);
999
1000     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1001            debugstr_w(szProduct), debugstr_w(path));
1002
1003     if (!path)
1004         return INSTALLSTATE_UNKNOWN;
1005
1006     if (path[0])
1007         r = INSTALLSTATE_LOCAL;
1008     else
1009         r = INSTALLSTATE_NOTUSED;
1010
1011     msi_strcpy_to_awstring( path, lpPathBuf, pcchBuf );
1012
1013     msi_free( path );
1014     return r;
1015 }
1016
1017 /******************************************************************
1018  * MsiGetComponentPathW      [MSI.@]
1019  */
1020 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1021                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1022 {
1023     awstring path;
1024
1025     path.unicode = TRUE;
1026     path.str.w = lpPathBuf;
1027
1028     return MSI_GetComponentPath( szProduct, szComponent, &path, pcchBuf );
1029 }
1030
1031 /******************************************************************
1032  * MsiGetComponentPathA      [MSI.@]
1033  */
1034 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
1035                                          LPSTR lpPathBuf, DWORD* pcchBuf)
1036 {
1037     LPWSTR szwProduct, szwComponent = NULL;
1038     INSTALLSTATE r = INSTALLSTATE_UNKNOWN;
1039     awstring path;
1040
1041     szwProduct = strdupAtoW( szProduct );
1042     if( szProduct && !szwProduct)
1043         goto end;
1044
1045     szwComponent = strdupAtoW( szComponent );
1046     if( szComponent && !szwComponent )
1047         goto end;
1048
1049     path.unicode = FALSE;
1050     path.str.a = lpPathBuf;
1051
1052     r = MSI_GetComponentPath( szwProduct, szwComponent, &path, pcchBuf );
1053
1054 end:
1055     msi_free( szwProduct );
1056     msi_free( szwComponent );
1057
1058     return r;
1059 }
1060
1061 /******************************************************************
1062  * MsiQueryFeatureStateA      [MSI.@]
1063  */
1064 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1065 {
1066     LPWSTR szwProduct = NULL, szwFeature= NULL;
1067     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1068
1069     szwProduct = strdupAtoW( szProduct );
1070     if ( szProduct && !szwProduct )
1071         goto end;
1072
1073     szwFeature = strdupAtoW( szFeature );
1074     if ( szFeature && !szwFeature )
1075         goto end;
1076
1077     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1078
1079 end:
1080     msi_free( szwProduct);
1081     msi_free( szwFeature);
1082
1083     return rc;
1084 }
1085
1086 /******************************************************************
1087  * MsiQueryFeatureStateW      [MSI.@]
1088  *
1089  * Checks the state of a feature
1090  *
1091  * PARAMS
1092  *   szProduct     [I]  Product's GUID string
1093  *   szFeature     [I]  Feature's GUID string
1094  *
1095  * RETURNS
1096  *   INSTALLSTATE_LOCAL        Feature is installed and useable
1097  *   INSTALLSTATE_ABSENT       Feature is absent
1098  *   INSTALLSTATE_ADVERTISED   Feature should be installed on demand
1099  *   INSTALLSTATE_UNKNOWN      An error occurred
1100  *   INSTALLSTATE_INVALIDARG   One of the GUIDs was invalid
1101  *
1102  */
1103 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1104 {
1105     WCHAR squishProduct[33], comp[GUID_SIZE];
1106     GUID guid;
1107     LPWSTR components, p, parent_feature;
1108     UINT rc;
1109     HKEY hkey;
1110     INSTALLSTATE r;
1111     BOOL missing = FALSE;
1112
1113     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1114
1115     if (!szProduct || !szFeature)
1116         return INSTALLSTATE_INVALIDARG;
1117
1118     if (!squash_guid( szProduct, squishProduct ))
1119         return INSTALLSTATE_INVALIDARG;
1120
1121     /* check that it's installed at all */
1122     rc = MSIREG_OpenUserFeaturesKey(szProduct, &hkey, FALSE);
1123     if (rc != ERROR_SUCCESS)
1124         return INSTALLSTATE_UNKNOWN;
1125
1126     parent_feature = msi_reg_get_val_str( hkey, szFeature );
1127     RegCloseKey(hkey);
1128
1129     if (!parent_feature)
1130         return INSTALLSTATE_UNKNOWN;
1131
1132     r = (parent_feature[0] == 6) ? INSTALLSTATE_ABSENT : INSTALLSTATE_LOCAL;
1133     msi_free(parent_feature);
1134     if (r == INSTALLSTATE_ABSENT)
1135         return r;
1136
1137     /* now check if it's complete or advertised */
1138     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
1139     if (rc != ERROR_SUCCESS)
1140         return INSTALLSTATE_UNKNOWN;
1141
1142     components = msi_reg_get_val_str( hkey, szFeature );
1143     RegCloseKey(hkey);
1144
1145     TRACE("rc = %d buffer = %s\n", rc, debugstr_w(components));
1146
1147     if (!components)
1148     {
1149         ERR("components missing %s %s\n",
1150             debugstr_w(szProduct), debugstr_w(szFeature));
1151         return INSTALLSTATE_UNKNOWN;
1152     }
1153
1154     for( p = components; *p != 2 ; p += 20)
1155     {
1156         if (!decode_base85_guid( p, &guid ))
1157         {
1158             ERR("%s\n", debugstr_w(p));
1159             break;
1160         }
1161         StringFromGUID2(&guid, comp, GUID_SIZE);
1162         r = MsiGetComponentPathW(szProduct, comp, NULL, 0);
1163         TRACE("component %s state %d\n", debugstr_guid(&guid), r);
1164         switch (r)
1165         {
1166         case INSTALLSTATE_NOTUSED:
1167         case INSTALLSTATE_LOCAL:
1168         case INSTALLSTATE_SOURCE:
1169             break;
1170         default:
1171             missing = TRUE;
1172         }
1173     }
1174
1175     TRACE("%s %s -> %d\n", debugstr_w(szProduct), debugstr_w(szFeature), r);
1176     msi_free(components);
1177
1178     if (missing)
1179         return INSTALLSTATE_ADVERTISED;
1180
1181     return INSTALLSTATE_LOCAL;
1182 }
1183
1184 /******************************************************************
1185  * MsiGetFileVersionA         [MSI.@]
1186  */
1187 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1188                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1189 {
1190     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1191     UINT ret = ERROR_OUTOFMEMORY;
1192
1193     if( szFilePath )
1194     {
1195         szwFilePath = strdupAtoW( szFilePath );
1196         if( !szwFilePath )
1197             goto end;
1198     }
1199
1200     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1201     {
1202         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1203         if( !lpwVersionBuff )
1204             goto end;
1205     }
1206
1207     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1208     {
1209         lpwLangBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1210         if( !lpwLangBuff )
1211             goto end;
1212     }
1213
1214     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1215                              lpwLangBuff, pcchLangBuf);
1216
1217     if( lpwVersionBuff )
1218         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1219                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1220     if( lpwLangBuff )
1221         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1222                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1223
1224 end:
1225     msi_free(szwFilePath);
1226     msi_free(lpwVersionBuff);
1227     msi_free(lpwLangBuff);
1228
1229     return ret;
1230 }
1231
1232 /******************************************************************
1233  * MsiGetFileVersionW         [MSI.@]
1234  */
1235 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1236                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1237 {
1238     static const WCHAR szVersionResource[] = {'\\',0};
1239     static const WCHAR szVersionFormat[] = {
1240         '%','d','.','%','d','.','%','d','.','%','d',0};
1241     static const WCHAR szLangFormat[] = {'%','d',0};
1242     UINT ret = 0;
1243     DWORD dwVerLen;
1244     LPVOID lpVer = NULL;
1245     VS_FIXEDFILEINFO *ffi;
1246     UINT puLen;
1247     WCHAR tmp[32];
1248
1249     TRACE("%s %p %d %p %d\n", debugstr_w(szFilePath),
1250           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1251           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1252
1253     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1254     if( !dwVerLen )
1255         return GetLastError();
1256
1257     lpVer = msi_alloc(dwVerLen);
1258     if( !lpVer )
1259     {
1260         ret = ERROR_OUTOFMEMORY;
1261         goto end;
1262     }
1263
1264     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1265     {
1266         ret = GetLastError();
1267         goto end;
1268     }
1269     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1270     {
1271         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1272             (puLen > 0) )
1273         {
1274             wsprintfW(tmp, szVersionFormat,
1275                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1276                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1277             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1278             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1279         }
1280         else
1281         {
1282             *lpVersionBuf = 0;
1283             *pcchVersionBuf = 0;
1284         }
1285     }
1286
1287     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1288     {
1289         DWORD lang = GetUserDefaultLangID();
1290
1291         FIXME("Retrieve language from file\n");
1292         wsprintfW(tmp, szLangFormat, lang);
1293         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1294         *pcchLangBuf = lstrlenW(lpLangBuf);
1295     }
1296
1297 end:
1298     msi_free(lpVer);
1299     return ret;
1300 }
1301
1302 /***********************************************************************
1303  * MsiGetFeatureUsageW           [MSI.@]
1304  */
1305 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1306                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1307 {
1308     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1309           pdwUseCount, pwDateUsed);
1310     return ERROR_CALL_NOT_IMPLEMENTED;
1311 }
1312
1313 /***********************************************************************
1314  * MsiGetFeatureUsageA           [MSI.@]
1315  */
1316 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1317                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1318 {
1319     LPWSTR prod = NULL, feat = NULL;
1320     UINT ret = ERROR_OUTOFMEMORY;
1321
1322     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1323           pdwUseCount, pwDateUsed);
1324
1325     prod = strdupAtoW( szProduct );
1326     if (szProduct && !prod)
1327         goto end;
1328
1329     feat = strdupAtoW( szFeature );
1330     if (szFeature && !feat)
1331         goto end;
1332
1333     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1334
1335 end:
1336     msi_free( prod );
1337     msi_free( feat );
1338
1339     return ret;
1340 }
1341
1342 /***********************************************************************
1343  * MsiUseFeatureExW           [MSI.@]
1344  */
1345 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1346                                       DWORD dwInstallMode, DWORD dwReserved )
1347 {
1348     INSTALLSTATE state;
1349
1350     TRACE("%s %s %i %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1351           dwInstallMode, dwReserved);
1352
1353     state = MsiQueryFeatureStateW( szProduct, szFeature );
1354
1355     if (dwReserved)
1356         return INSTALLSTATE_INVALIDARG;
1357
1358     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1359     {
1360         FIXME("mark product %s feature %s as used\n",
1361               debugstr_w(szProduct), debugstr_w(szFeature) );
1362     }
1363
1364     return state;
1365 }
1366
1367 /***********************************************************************
1368  * MsiUseFeatureExA           [MSI.@]
1369  */
1370 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1371                                       DWORD dwInstallMode, DWORD dwReserved )
1372 {
1373     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1374     LPWSTR prod = NULL, feat = NULL;
1375
1376     TRACE("%s %s %i %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1377           dwInstallMode, dwReserved);
1378
1379     prod = strdupAtoW( szProduct );
1380     if (szProduct && !prod)
1381         goto end;
1382
1383     feat = strdupAtoW( szFeature );
1384     if (szFeature && !feat)
1385         goto end;
1386
1387     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1388
1389 end:
1390     msi_free( prod );
1391     msi_free( feat );
1392
1393     return ret;
1394 }
1395
1396 /***********************************************************************
1397  * MsiUseFeatureW             [MSI.@]
1398  */
1399 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1400 {
1401     return MsiUseFeatureExW(szProduct, szFeature, 0, 0);
1402 }
1403
1404 /***********************************************************************
1405  * MsiUseFeatureA             [MSI.@]
1406  */
1407 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1408 {
1409     return MsiUseFeatureExA(szProduct, szFeature, 0, 0);
1410 }
1411
1412 /***********************************************************************
1413  * MSI_ProvideQualifiedComponentEx [internal]
1414  */
1415 static UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
1416                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1417                 DWORD Unused1, DWORD Unused2, awstring *lpPathBuf,
1418                 DWORD* pcchPathBuf)
1419 {
1420     WCHAR product[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1],
1421           feature[MAX_FEATURE_CHARS+1];
1422     LPWSTR info;
1423     HKEY hkey;
1424     DWORD sz;
1425     UINT rc;
1426
1427     TRACE("%s %s %i %s %i %i %p %p\n", debugstr_w(szComponent),
1428           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1429           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1430
1431     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1432     if (rc != ERROR_SUCCESS)
1433         return ERROR_INDEX_ABSENT;
1434
1435     info = msi_reg_get_val_str( hkey, szQualifier );
1436     RegCloseKey(hkey);
1437
1438     if (!info)
1439         return ERROR_INDEX_ABSENT;
1440
1441     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1442
1443     if (!szProduct)
1444         rc = MSI_GetComponentPath(product, component, lpPathBuf, pcchPathBuf);
1445     else
1446         rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
1447
1448     msi_free( info );
1449
1450     if (rc != INSTALLSTATE_LOCAL)
1451         return ERROR_FILE_NOT_FOUND;
1452
1453     return ERROR_SUCCESS;
1454 }
1455
1456 /***********************************************************************
1457  * MsiProvideQualifiedComponentExW [MSI.@]
1458  */
1459 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1460                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1461                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1462                 DWORD* pcchPathBuf)
1463 {
1464     awstring path;
1465
1466     path.unicode = TRUE;
1467     path.str.w = lpPathBuf;
1468
1469     return MSI_ProvideQualifiedComponentEx(szComponent, szQualifier,
1470             dwInstallMode, szProduct, Unused1, Unused2, &path, pcchPathBuf);
1471 }
1472
1473 /***********************************************************************
1474  * MsiProvideQualifiedComponentExA [MSI.@]
1475  */
1476 UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR szComponent,
1477                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR szProduct,
1478                 DWORD Unused1, DWORD Unused2, LPSTR lpPathBuf,
1479                 DWORD* pcchPathBuf)
1480 {
1481     LPWSTR szwComponent, szwQualifier = NULL, szwProduct = NULL;
1482     UINT r = ERROR_OUTOFMEMORY;
1483     awstring path;
1484
1485     TRACE("%s %s %u %s %u %u %p %p\n", debugstr_a(szComponent),
1486           debugstr_a(szQualifier), dwInstallMode, debugstr_a(szProduct),
1487           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1488
1489     szwComponent = strdupAtoW( szComponent );
1490     if (szComponent && !szwComponent)
1491         goto end;
1492
1493     szwQualifier = strdupAtoW( szQualifier );
1494     if (szQualifier && !szwQualifier)
1495         goto end;
1496
1497     szwProduct = strdupAtoW( szProduct );
1498     if (szProduct && !szwProduct)
1499         goto end;
1500
1501     path.unicode = FALSE;
1502     path.str.a = lpPathBuf;
1503
1504     r = MSI_ProvideQualifiedComponentEx(szwComponent, szwQualifier,
1505                               dwInstallMode, szwProduct, Unused1,
1506                               Unused2, &path, pcchPathBuf);
1507 end:
1508     msi_free(szwProduct);
1509     msi_free(szwComponent);
1510     msi_free(szwQualifier);
1511
1512     return r;
1513 }
1514
1515 /***********************************************************************
1516  * MsiProvideQualifiedComponentW [MSI.@]
1517  */
1518 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1519                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1520                 DWORD* pcchPathBuf)
1521 {
1522     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1523                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1524 }
1525
1526 /***********************************************************************
1527  * MsiProvideQualifiedComponentA [MSI.@]
1528  */
1529 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1530                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1531                 DWORD* pcchPathBuf)
1532 {
1533     return MsiProvideQualifiedComponentExA(szComponent, szQualifier,
1534                               dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1535 }
1536
1537 /***********************************************************************
1538  * MSI_GetUserInfo [internal]
1539  */
1540 static USERINFOSTATE WINAPI MSI_GetUserInfo(LPCWSTR szProduct,
1541                 awstring *lpUserNameBuf, DWORD* pcchUserNameBuf,
1542                 awstring *lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1543                 awstring *lpSerialBuf, DWORD* pcchSerialBuf)
1544 {
1545     HKEY hkey;
1546     LPWSTR user, org, serial;
1547     UINT r;
1548     USERINFOSTATE state;
1549
1550     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1551           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1552           pcchSerialBuf);
1553
1554     if (!szProduct)
1555         return USERINFOSTATE_INVALIDARG;
1556
1557     r = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1558     if (r != ERROR_SUCCESS)
1559         return USERINFOSTATE_UNKNOWN;
1560
1561     user = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGOWNERW );
1562     org = msi_reg_get_val_str( hkey, INSTALLPROPERTY_REGCOMPANYW );
1563     serial = msi_reg_get_val_str( hkey, INSTALLPROPERTY_PRODUCTIDW );
1564
1565     RegCloseKey(hkey);
1566
1567     state = USERINFOSTATE_PRESENT;
1568
1569     if (user)
1570     {
1571         r = msi_strcpy_to_awstring( user, lpUserNameBuf, pcchUserNameBuf );
1572         if (r == ERROR_MORE_DATA)
1573             state = USERINFOSTATE_MOREDATA;
1574     }
1575     else
1576         state = USERINFOSTATE_ABSENT;
1577     if (org)
1578     {
1579         r = msi_strcpy_to_awstring( org, lpOrgNameBuf, pcchOrgNameBuf );
1580         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1581             state = USERINFOSTATE_MOREDATA;
1582     }
1583     /* msdn states: The user information is considered to be present even in the absence of a company name. */
1584     if (serial)
1585     {
1586         r = msi_strcpy_to_awstring( serial, lpSerialBuf, pcchSerialBuf );
1587         if (r == ERROR_MORE_DATA && state == USERINFOSTATE_PRESENT)
1588             state = USERINFOSTATE_MOREDATA;
1589     }
1590     else
1591         state = USERINFOSTATE_ABSENT;
1592
1593     msi_free( user );
1594     msi_free( org );
1595     msi_free( serial );
1596
1597     return state;
1598 }
1599
1600 /***********************************************************************
1601  * MsiGetUserInfoW [MSI.@]
1602  */
1603 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct,
1604                 LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1605                 LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1606                 LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1607 {
1608     awstring user, org, serial;
1609
1610     user.unicode = TRUE;
1611     user.str.w = lpUserNameBuf;
1612     org.unicode = TRUE;
1613     org.str.w = lpOrgNameBuf;
1614     serial.unicode = TRUE;
1615     serial.str.w = lpSerialBuf;
1616
1617     return MSI_GetUserInfo( szProduct, &user, pcchUserNameBuf,
1618                             &org, pcchOrgNameBuf,
1619                             &serial, pcchSerialBuf );
1620 }
1621
1622 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct,
1623                 LPSTR lpUserNameBuf, DWORD* pcchUserNameBuf,
1624                 LPSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf,
1625                 LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1626 {
1627     awstring user, org, serial;
1628     LPWSTR prod;
1629     UINT r;
1630
1631     prod = strdupAtoW( szProduct );
1632     if (szProduct && !prod)
1633         return ERROR_OUTOFMEMORY;
1634
1635     user.unicode = FALSE;
1636     user.str.a = lpUserNameBuf;
1637     org.unicode = FALSE;
1638     org.str.a = lpOrgNameBuf;
1639     serial.unicode = FALSE;
1640     serial.str.a = lpSerialBuf;
1641
1642     r = MSI_GetUserInfo( prod, &user, pcchUserNameBuf,
1643                          &org, pcchOrgNameBuf,
1644                          &serial, pcchSerialBuf );
1645
1646     msi_free( prod );
1647
1648     return r;
1649 }
1650
1651 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1652 {
1653     MSIHANDLE handle;
1654     UINT rc;
1655     MSIPACKAGE *package;
1656     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1657
1658     TRACE("(%s)\n",debugstr_w(szProduct));
1659
1660     rc = MsiOpenProductW(szProduct,&handle);
1661     if (rc != ERROR_SUCCESS)
1662         return ERROR_INVALID_PARAMETER;
1663
1664     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1665     rc = ACTION_PerformUIAction(package, szFirstRun);
1666     msiobj_release( &package->hdr );
1667
1668     MsiCloseHandle(handle);
1669
1670     return rc;
1671 }
1672
1673 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1674 {
1675     MSIHANDLE handle;
1676     UINT rc;
1677     MSIPACKAGE *package;
1678     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1679
1680     TRACE("(%s)\n",debugstr_a(szProduct));
1681
1682     rc = MsiOpenProductA(szProduct,&handle);
1683     if (rc != ERROR_SUCCESS)
1684         return ERROR_INVALID_PARAMETER;
1685
1686     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1687     rc = ACTION_PerformUIAction(package, szFirstRun);
1688     msiobj_release( &package->hdr );
1689
1690     MsiCloseHandle(handle);
1691
1692     return rc;
1693 }
1694
1695 /***********************************************************************
1696  * MsiConfigureFeatureA            [MSI.@]
1697  */
1698 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1699 {
1700     LPWSTR prod, feat = NULL;
1701     UINT r = ERROR_OUTOFMEMORY;
1702
1703     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1704
1705     prod = strdupAtoW( szProduct );
1706     if (szProduct && !prod)
1707         goto end;
1708
1709     feat = strdupAtoW( szFeature );
1710     if (szFeature && !feat)
1711         goto end;
1712
1713     r = MsiConfigureFeatureW(prod, feat, eInstallState);
1714
1715 end:
1716     msi_free(feat);
1717     msi_free(prod);
1718
1719     return r;
1720 }
1721
1722 /***********************************************************************
1723  * MsiConfigureFeatureW            [MSI.@]
1724  */
1725 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1726 {
1727     static const WCHAR szCostInit[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1728     MSIPACKAGE *package = NULL;
1729     UINT r;
1730     WCHAR sourcepath[MAX_PATH], filename[MAX_PATH];
1731     DWORD sz;
1732
1733     TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1734
1735     if (!szProduct || !szFeature)
1736         return ERROR_INVALID_PARAMETER;
1737
1738     switch (eInstallState)
1739     {
1740     case INSTALLSTATE_DEFAULT:
1741         /* FIXME: how do we figure out the default location? */
1742         eInstallState = INSTALLSTATE_LOCAL;
1743         break;
1744     case INSTALLSTATE_LOCAL:
1745     case INSTALLSTATE_SOURCE:
1746     case INSTALLSTATE_ABSENT:
1747     case INSTALLSTATE_ADVERTISED:
1748         break;
1749     default:
1750         return ERROR_INVALID_PARAMETER;
1751     }
1752
1753     r = MSI_OpenProductW( szProduct, &package );
1754     if (r != ERROR_SUCCESS)
1755         return r;
1756
1757     sz = sizeof(sourcepath);
1758     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1759                 MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1760
1761     sz = sizeof(filename);
1762     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
1763                 MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1764
1765     lstrcatW( sourcepath, filename );
1766
1767     MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL );
1768
1769     r = ACTION_PerformUIAction( package, szCostInit );
1770     if (r != ERROR_SUCCESS)
1771         goto end;
1772
1773     r = MSI_SetFeatureStateW( package, szFeature, eInstallState);
1774     if (r != ERROR_SUCCESS)
1775         goto end;
1776
1777     r = MSI_InstallPackage( package, sourcepath, NULL );
1778
1779 end:
1780     msiobj_release( &package->hdr );
1781
1782     return r;
1783 }
1784
1785 /***********************************************************************
1786  * MsiCreateAndVerifyInstallerDirectory [MSI.@]
1787  *
1788  * Notes: undocumented
1789  */
1790 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1791 {
1792     WCHAR path[MAX_PATH];
1793
1794     TRACE("%d\n", dwReserved);
1795
1796     if (dwReserved)
1797     {
1798         FIXME("dwReserved=%d\n", dwReserved);
1799         return ERROR_INVALID_PARAMETER;
1800     }
1801
1802     if (!GetWindowsDirectoryW(path, MAX_PATH))
1803         return ERROR_FUNCTION_FAILED;
1804
1805     lstrcatW(path, installerW);
1806
1807     if (!CreateDirectoryW(path, NULL))
1808         return ERROR_FUNCTION_FAILED;
1809
1810     return ERROR_SUCCESS;
1811 }
1812
1813 /***********************************************************************
1814  * MsiGetShortcutTargetA           [MSI.@]
1815  */
1816 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1817                                    LPSTR szProductCode, LPSTR szFeatureId,
1818                                    LPSTR szComponentCode )
1819 {
1820     LPWSTR target;
1821     const int len = MAX_FEATURE_CHARS+1;
1822     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1823     UINT r;
1824
1825     target = strdupAtoW( szShortcutTarget );
1826     if (szShortcutTarget && !target )
1827         return ERROR_OUTOFMEMORY;
1828     product[0] = 0;
1829     feature[0] = 0;
1830     component[0] = 0;
1831     r = MsiGetShortcutTargetW( target, product, feature, component );
1832     msi_free( target );
1833     if (r == ERROR_SUCCESS)
1834     {
1835         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1836         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1837         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1838     }
1839     return r;
1840 }
1841
1842 /***********************************************************************
1843  * MsiGetShortcutTargetW           [MSI.@]
1844  */
1845 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1846                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1847                                    LPWSTR szComponentCode )
1848 {
1849     IShellLinkDataList *dl = NULL;
1850     IPersistFile *pf = NULL;
1851     LPEXP_DARWIN_LINK darwin = NULL;
1852     HRESULT r, init;
1853
1854     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1855           szProductCode, szFeatureId, szComponentCode );
1856
1857     init = CoInitialize(NULL);
1858
1859     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1860                           &IID_IPersistFile, (LPVOID*) &pf );
1861     if( SUCCEEDED( r ) )
1862     {
1863         r = IPersistFile_Load( pf, szShortcutTarget,
1864                                STGM_READ | STGM_SHARE_DENY_WRITE );
1865         if( SUCCEEDED( r ) )
1866         {
1867             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1868                                              (LPVOID*) &dl );
1869             if( SUCCEEDED( r ) )
1870             {
1871                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1872                                                   (LPVOID) &darwin );
1873                 IShellLinkDataList_Release( dl );
1874             }
1875         }
1876         IPersistFile_Release( pf );
1877     }
1878
1879     if (SUCCEEDED(init))
1880         CoUninitialize();
1881
1882     TRACE("darwin = %p\n", darwin);
1883
1884     if (darwin)
1885     {
1886         DWORD sz;
1887         UINT ret;
1888
1889         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1890                   szProductCode, szFeatureId, szComponentCode, &sz );
1891         LocalFree( darwin );
1892         return ret;
1893     }
1894
1895     return ERROR_FUNCTION_FAILED;
1896 }
1897
1898 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1899                                   DWORD dwReinstallMode )
1900 {
1901     MSIPACKAGE* package = NULL;
1902     UINT r;
1903     WCHAR sourcepath[MAX_PATH];
1904     WCHAR filename[MAX_PATH];
1905     static const WCHAR szLogVerbose[] = {
1906         ' ','L','O','G','V','E','R','B','O','S','E',0 };
1907     static const WCHAR szInstalled[] = { 'I','n','s','t','a','l','l','e','d',0};
1908     static const WCHAR szReinstall[] = {'R','E','I','N','S','T','A','L','L',0};
1909     static const WCHAR szReinstallMode[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
1910     static const WCHAR szOne[] = {'1',0};
1911     WCHAR reinstallmode[11];
1912     LPWSTR ptr;
1913     DWORD sz;
1914
1915     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature),
1916                            dwReinstallMode);
1917
1918     ptr = reinstallmode;
1919
1920     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
1921         *ptr++ = 'p';
1922     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
1923         *ptr++ = 'o';
1924     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
1925         *ptr++ = 'w';
1926     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
1927         *ptr++ = 'd';
1928     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
1929         *ptr++ = 'c';
1930     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
1931         *ptr++ = 'a';
1932     if (dwReinstallMode & REINSTALLMODE_USERDATA)
1933         *ptr++ = 'u';
1934     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
1935         *ptr++ = 'm';
1936     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
1937         *ptr++ = 's';
1938     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1939         *ptr++ = 'v';
1940     *ptr = 0;
1941     
1942     sz = sizeof(sourcepath);
1943     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1944             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz);
1945
1946     sz = sizeof(filename);
1947     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1948             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1949
1950     lstrcatW( sourcepath, filename );
1951
1952     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1953         r = MSI_OpenPackageW( sourcepath, &package );
1954     else
1955         r = MSI_OpenProductW( szProduct, &package );
1956
1957     if (r != ERROR_SUCCESS)
1958         return r;
1959
1960     MSI_SetPropertyW( package, szReinstallMode, reinstallmode );
1961     MSI_SetPropertyW( package, szInstalled, szOne );
1962     MSI_SetPropertyW( package, szLogVerbose, szOne );
1963     MSI_SetPropertyW( package, szReinstall, szFeature );
1964
1965     r = MSI_InstallPackage( package, sourcepath, NULL );
1966
1967     msiobj_release( &package->hdr );
1968
1969     return r;
1970 }
1971
1972 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1973                                   DWORD dwReinstallMode )
1974 {
1975     LPWSTR wszProduct;
1976     LPWSTR wszFeature;
1977     UINT rc;
1978
1979     TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature),
1980                            dwReinstallMode);
1981
1982     wszProduct = strdupAtoW(szProduct);
1983     wszFeature = strdupAtoW(szFeature);
1984
1985     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
1986
1987     msi_free(wszProduct);
1988     msi_free(wszFeature);
1989     return rc;
1990 }
1991
1992 typedef struct
1993 {
1994     unsigned int i[2];
1995     unsigned int buf[4];
1996     unsigned char in[64];
1997     unsigned char digest[16];
1998 } MD5_CTX;
1999
2000 extern VOID WINAPI MD5Init( MD5_CTX *);
2001 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
2002 extern VOID WINAPI MD5Final( MD5_CTX *);
2003
2004 /***********************************************************************
2005  * MsiGetFileHashW            [MSI.@]
2006  */
2007 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2008                              PMSIFILEHASHINFO pHash )
2009 {
2010     HANDLE handle, mapping;
2011     void *p;
2012     DWORD length;
2013     UINT r = ERROR_FUNCTION_FAILED;
2014
2015     TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2016
2017     if (dwOptions)
2018         return ERROR_INVALID_PARAMETER;
2019     if (!pHash)
2020         return ERROR_INVALID_PARAMETER;
2021     if (pHash->dwFileHashInfoSize < sizeof *pHash)
2022         return ERROR_INVALID_PARAMETER;
2023
2024     handle = CreateFileW( szFilePath, GENERIC_READ,
2025                           FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
2026     if (handle == INVALID_HANDLE_VALUE)
2027         return ERROR_FILE_NOT_FOUND;
2028
2029     length = GetFileSize( handle, NULL );
2030
2031     mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
2032     if (mapping)
2033     {
2034         p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
2035         if (p)
2036         {
2037             MD5_CTX ctx;
2038
2039             MD5Init( &ctx );
2040             MD5Update( &ctx, p, length );
2041             MD5Final( &ctx );
2042             UnmapViewOfFile( p );
2043
2044             memcpy( pHash->dwData, &ctx.digest, sizeof pHash->dwData );
2045             r = ERROR_SUCCESS;
2046         }
2047         CloseHandle( mapping );
2048     }
2049     CloseHandle( handle );
2050
2051     return r;
2052 }
2053
2054 /***********************************************************************
2055  * MsiGetFileHashA            [MSI.@]
2056  */
2057 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2058                              PMSIFILEHASHINFO pHash )
2059 {
2060     LPWSTR file;
2061     UINT r;
2062
2063     TRACE("%s %08x %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2064
2065     file = strdupAtoW( szFilePath );
2066     if (szFilePath && !file)
2067         return ERROR_OUTOFMEMORY;
2068
2069     r = MsiGetFileHashW( file, dwOptions, pHash );
2070     msi_free( file );
2071     return r;
2072 }
2073
2074 /***********************************************************************
2075  * MsiAdvertiseScriptW        [MSI.@]
2076  */
2077 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2078                                  PHKEY phRegData, BOOL fRemoveItems )
2079 {
2080     FIXME("%s %08x %p %d\n",
2081           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2082     return ERROR_CALL_NOT_IMPLEMENTED;
2083 }
2084
2085 /***********************************************************************
2086  * MsiAdvertiseScriptA        [MSI.@]
2087  */
2088 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2089                                  PHKEY phRegData, BOOL fRemoveItems )
2090 {
2091     FIXME("%s %08x %p %d\n",
2092           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2093     return ERROR_CALL_NOT_IMPLEMENTED;
2094 }