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