Implement MsiGetFeatureUsageA and MsiUseFeature(Ex)A using their W
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 /*
47  * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
48  *  which is a problem because LPCTSTR isn't defined when compiling wine.
49  * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
50  *  and make sure to only use it in W functions.
51  */
52 #define LPCTSTR LPCWSTR
53
54 /* the UI level */
55 INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
56 HWND           gUIhwnd = 0;
57 INSTALLUI_HANDLERA gUIHandlerA = NULL;
58 INSTALLUI_HANDLERW gUIHandlerW = NULL;
59 DWORD gUIFilter = 0;
60 LPVOID gUIContext = NULL;
61 WCHAR gszLogFile[MAX_PATH];
62 HINSTANCE msi_hInstance;
63
64 static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
65
66 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
67 {
68     UINT r;
69     LPWSTR szwProd = NULL;
70
71     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
72
73     if( szProduct )
74     {
75         szwProd = strdupAtoW( szProduct );
76         if( !szwProd )
77             return ERROR_OUTOFMEMORY;
78     }
79
80     r = MsiOpenProductW( szwProd, phProduct );
81
82     msi_free( szwProd );
83
84     return r;
85 }
86
87 static UINT MSI_OpenProductW( LPCWSTR szProduct, MSIPACKAGE **ppackage )
88 {
89     LPWSTR path = NULL;
90     UINT r;
91     HKEY hKeyProduct = NULL;
92     DWORD count, type;
93
94     TRACE("%s %p\n", debugstr_w(szProduct), ppackage );
95
96     r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE);
97     if( r != ERROR_SUCCESS )
98     {
99         r = ERROR_UNKNOWN_PRODUCT;
100         goto end;
101     }
102
103     /* find the size of the path */
104     type = count = 0;
105     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
106                           NULL, &type, NULL, &count );
107     if( r != ERROR_SUCCESS )
108     {
109         r = ERROR_UNKNOWN_PRODUCT;
110         goto end;
111     }
112
113     /* now alloc and fetch the path of the database to open */
114     path = msi_alloc( count );
115     if( !path )
116         goto end;
117
118     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
119                           NULL, &type, (LPBYTE) path, &count );
120     if( r != ERROR_SUCCESS )
121     {
122         r = ERROR_UNKNOWN_PRODUCT;
123         goto end;
124     }
125
126     r = MSI_OpenPackageW( path, ppackage );
127
128 end:
129     msi_free( path );
130     if( hKeyProduct )
131         RegCloseKey( hKeyProduct );
132
133     return r;
134 }
135
136 UINT WINAPI MsiOpenProductW( LPCWSTR szProduct, MSIHANDLE *phProduct )
137 {
138    MSIPACKAGE *package = NULL;
139    UINT r;
140
141    r = MSI_OpenProductW( szProduct, &package );
142    if( r == ERROR_SUCCESS )
143    {
144        *phProduct = alloc_msihandle( &package->hdr );
145        msiobj_release( &package->hdr );
146    }
147    return r;
148 }
149
150 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
151                 LPCSTR szTransforms, LANGID lgidLanguage)
152 {
153     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
154           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
155     return ERROR_CALL_NOT_IMPLEMENTED;
156 }
157
158 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
159                 LPCWSTR szTransforms, LANGID lgidLanguage)
160 {
161     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
162           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
163     return ERROR_CALL_NOT_IMPLEMENTED;
164 }
165
166 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
167       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
168 {
169     FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath),
170           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
171           lgidLanguage, dwPlatform, dwOptions);
172     return ERROR_CALL_NOT_IMPLEMENTED;
173 }
174
175 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
176       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
177 {
178     FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath),
179           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
180           lgidLanguage, dwPlatform, dwOptions);
181     return ERROR_CALL_NOT_IMPLEMENTED;
182 }
183
184 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
185 {
186     LPWSTR szwPath = NULL, szwCommand = NULL;
187     UINT r = ERROR_OUTOFMEMORY;
188
189     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
190
191     if( szPackagePath )
192     {
193         szwPath = strdupAtoW( szPackagePath );
194         if( !szwPath )
195             goto end;
196     }
197
198     if( szCommandLine )
199     {
200         szwCommand = strdupAtoW( szCommandLine );
201         if( !szwCommand )
202             goto end;
203     }
204
205     r = MsiInstallProductW( szwPath, szwCommand );
206
207 end:
208     msi_free( szwPath );
209     msi_free( szwCommand );
210
211     return r;
212 }
213
214 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
215 {
216     MSIPACKAGE *package = NULL;
217     UINT r;
218
219     FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
220
221     r = MSI_OpenPackageW( szPackagePath, &package );
222     if (r == ERROR_SUCCESS)
223     {
224         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
225         msiobj_release( &package->hdr );
226     }
227
228     return r;
229 }
230
231 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
232 {
233     FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode);
234     return ERROR_CALL_NOT_IMPLEMENTED;
235 }
236
237 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
238 {
239     FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode);
240     return ERROR_CALL_NOT_IMPLEMENTED;
241 }
242
243 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
244         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
245 {
246     FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
247           eInstallType, debugstr_a(szCommandLine));
248     return ERROR_CALL_NOT_IMPLEMENTED;
249 }
250
251 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
252          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
253 {
254     FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
255           eInstallType, debugstr_w(szCommandLine));
256     return ERROR_CALL_NOT_IMPLEMENTED;
257 }
258
259 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
260                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
261 {
262     MSIPACKAGE* package = NULL;
263     UINT r;
264     DWORD sz;
265     WCHAR sourcepath[MAX_PATH];
266     WCHAR filename[MAX_PATH];
267     static const WCHAR szInstalled[] = {
268         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
269     LPWSTR commandline;
270
271     FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
272           debugstr_w(szCommandLine));
273
274     if (eInstallState != INSTALLSTATE_LOCAL &&
275         eInstallState != INSTALLSTATE_DEFAULT)
276     {
277         FIXME("Not implemented for anything other than local installs\n");
278         return ERROR_CALL_NOT_IMPLEMENTED;
279     }
280
281     sz = sizeof(sourcepath);
282     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
283             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
284             &sz);
285
286     sz = sizeof(filename);
287     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
288             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
289
290     lstrcatW(sourcepath,filename);
291
292     /*
293      * ok 1, we need to find the msi file for this product.
294      *    2, find the source dir for the files
295      *    3, do the configure/install.
296      *    4, cleanupany runonce entry.
297      */
298
299     r = MSI_OpenProductW( szProduct, &package );
300     if (r != ERROR_SUCCESS)
301         return r;
302
303     sz = lstrlenW(szInstalled) + 1;
304
305     if (szCommandLine)
306         sz += lstrlenW(szCommandLine);
307
308     commandline = msi_alloc(sz * sizeof(WCHAR));
309     if (!commandline )
310     {
311         r = ERROR_OUTOFMEMORY;
312         goto end;
313     }
314
315     commandline[0] = 0;
316     if (szCommandLine)
317         lstrcpyW(commandline,szCommandLine);
318
319     if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN)
320         lstrcatW(commandline,szInstalled);
321
322     r = MSI_InstallPackage( package, sourcepath, commandline );
323
324     msi_free(commandline);
325
326 end:
327     msiobj_release( &package->hdr );
328
329     return r;
330 }
331
332 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
333                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
334 {
335     LPWSTR szwProduct = NULL;
336     LPWSTR szwCommandLine = NULL;
337     UINT r = ERROR_OUTOFMEMORY;
338
339     if( szProduct )
340     {
341         szwProduct = strdupAtoW( szProduct );
342         if( !szwProduct )
343             goto end;
344     }
345
346     if( szCommandLine)
347     {
348         szwCommandLine = strdupAtoW( szCommandLine );
349         if( !szwCommandLine)
350             goto end;
351     }
352
353     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
354                                 szwCommandLine );
355 end:
356     msi_free( szwProduct );
357     msi_free( szwCommandLine);
358
359     return r;
360 }
361
362 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
363                                  INSTALLSTATE eInstallState)
364 {
365     LPWSTR szwProduct = NULL;
366     UINT r;
367
368     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
369
370     if( szProduct )
371     {
372         szwProduct = strdupAtoW( szProduct );
373         if( !szwProduct )
374             return ERROR_OUTOFMEMORY;
375     }
376
377     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
378     msi_free( szwProduct );
379
380     return r;
381 }
382
383 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
384                                  INSTALLSTATE eInstallState)
385 {
386     FIXME("%s %d %d\n", debugstr_w(szProduct), iInstallLevel, eInstallState);
387
388     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
389 }
390
391 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
392 {
393     LPWSTR szwComponent = NULL;
394     UINT r;
395     WCHAR szwBuffer[GUID_SIZE];
396
397     TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
398
399     if( szComponent )
400     {
401         szwComponent = strdupAtoW( szComponent );
402         if( !szwComponent )
403             return ERROR_OUTOFMEMORY;
404     }
405
406     r = MsiGetProductCodeW( szwComponent, szwBuffer );
407
408     if( ERROR_SUCCESS == r )
409         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
410
411     msi_free( szwComponent );
412
413     return r;
414 }
415
416 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
417 {
418     UINT rc;
419     HKEY hkey;
420     WCHAR szSquished[GUID_SIZE];
421     DWORD sz = GUID_SIZE;
422     static const WCHAR szPermKey[] =
423         { '0','0','0','0','0','0','0','0','0','0','0','0',
424           '0','0','0','0','0','0','0','0','0','0','0','0',
425           '0','0','0','0','0','0','0','0',0};
426
427     TRACE("%s %p\n",debugstr_w(szComponent), szBuffer);
428
429     if (NULL == szComponent)
430         return ERROR_INVALID_PARAMETER;
431
432     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
433     if (rc != ERROR_SUCCESS)
434         return ERROR_UNKNOWN_COMPONENT;
435
436     rc = RegEnumValueW(hkey, 0, szSquished, &sz, NULL, NULL, NULL, NULL);
437     if (rc == ERROR_SUCCESS && strcmpW(szSquished,szPermKey)==0)
438     {
439         sz = GUID_SIZE;
440         rc = RegEnumValueW(hkey, 1, szSquished, &sz, NULL, NULL, NULL, NULL);
441     }
442
443     RegCloseKey(hkey);
444
445     if (rc != ERROR_SUCCESS)
446         return ERROR_INSTALL_FAILURE;
447
448     unsquash_guid(szSquished, szBuffer);
449     return ERROR_SUCCESS;
450 }
451
452 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
453                  LPSTR szBuffer, DWORD *pcchValueBuf)
454 {
455     LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
456     UINT r = ERROR_OUTOFMEMORY;
457     DWORD pcchwValueBuf = 0;
458
459     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
460           szBuffer, pcchValueBuf);
461
462     if( szProduct )
463     {
464         szwProduct = strdupAtoW( szProduct );
465         if( !szwProduct )
466             goto end;
467     }
468     
469     if( szAttribute )
470     {
471         szwAttribute = strdupAtoW( szAttribute );
472         if( !szwAttribute )
473             goto end;
474     }
475
476     if( szBuffer )
477     {
478         szwBuffer = msi_alloc( (*pcchValueBuf) * sizeof(WCHAR) );
479         pcchwValueBuf = *pcchValueBuf;
480         if( !szwBuffer )     
481             goto end;
482     }
483
484     r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, 
485                             &pcchwValueBuf );
486
487     if( ERROR_SUCCESS == r )
488     {
489         INT old_len = *pcchValueBuf;
490         *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf,
491                         szBuffer, *pcchValueBuf, NULL, NULL);
492         if (old_len > *pcchValueBuf)
493             szBuffer[*pcchValueBuf]=0;
494     }
495
496 end:
497     msi_free( szwProduct );
498     msi_free( szwAttribute );
499     msi_free( szwBuffer );
500
501     return r;
502 }
503
504 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
505                 LPWSTR szBuffer, DWORD *pcchValueBuf)
506 {
507     MSIHANDLE hProduct;
508     UINT r;
509     static const WCHAR szProductVersion[] =
510         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
511     static const WCHAR szProductLanguage[] =
512         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
513
514     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute),
515           szBuffer, pcchValueBuf);
516
517     if (NULL != szBuffer && NULL == pcchValueBuf)
518         return ERROR_INVALID_PARAMETER;
519     if (NULL == szProduct || NULL == szAttribute)
520         return ERROR_INVALID_PARAMETER;
521     
522     /* check for special properties */
523     if (strcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW)==0)
524     {
525         HKEY hkey;
526         WCHAR squished[GUID_SIZE];
527         WCHAR package[200];
528         DWORD sz = sizeof(squished);
529
530         r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
531         if (r != ERROR_SUCCESS)
532             return ERROR_UNKNOWN_PRODUCT;
533
534         r = RegQueryValueExW(hkey, INSTALLPROPERTY_PACKAGECODEW, NULL, NULL, 
535                         (LPBYTE)squished, &sz);
536         if (r != ERROR_SUCCESS)
537         {
538             RegCloseKey(hkey);
539             return ERROR_UNKNOWN_PRODUCT;
540         }
541
542         unsquash_guid(squished, package);
543         *pcchValueBuf = strlenW(package);
544         if (strlenW(package) > *pcchValueBuf)
545         {
546             RegCloseKey(hkey);
547             return ERROR_MORE_DATA;
548         }
549         else
550             strcpyW(szBuffer, package);
551
552         RegCloseKey(hkey);
553         r = ERROR_SUCCESS;
554     }
555     else if (strcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW)==0)
556     {
557         r = MsiOpenProductW(szProduct, &hProduct);
558         if (ERROR_SUCCESS != r)
559             return r;
560
561         r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf);
562         MsiCloseHandle(hProduct);
563     }
564     else if (strcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW)==0)
565     {
566         FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n");
567         if (szBuffer)
568         {
569             szBuffer[0] = '1';
570             szBuffer[1] = 0;
571         }
572         if (pcchValueBuf)
573             *pcchValueBuf = 1;
574         r = ERROR_SUCCESS;
575     }
576     else if (strcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW)==0)
577     {
578         r = MsiOpenProductW(szProduct, &hProduct);
579         if (ERROR_SUCCESS != r)
580             return r;
581
582         r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
583         MsiCloseHandle(hProduct);
584     }
585     else
586     {
587         r = MsiOpenProductW(szProduct, &hProduct);
588         if (ERROR_SUCCESS != r)
589             return r;
590
591         r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
592         MsiCloseHandle(hProduct);
593     }
594
595     return r;
596 }
597
598 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
599 {
600     LPWSTR szwLogFile = NULL;
601     UINT r;
602
603     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes);
604
605     if( szLogFile )
606     {
607         szwLogFile = strdupAtoW( szLogFile );
608         if( !szwLogFile )
609             return ERROR_OUTOFMEMORY;
610     }
611     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
612     msi_free( szwLogFile );
613     return r;
614 }
615
616 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
617 {
618     HANDLE file = INVALID_HANDLE_VALUE;
619
620     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes);
621
622     lstrcpyW(gszLogFile,szLogFile);
623     if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
624         DeleteFileW(szLogFile);
625     file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
626                            FILE_ATTRIBUTE_NORMAL, NULL);
627     if (file != INVALID_HANDLE_VALUE)
628         CloseHandle(file);
629     else
630         ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
631
632     return ERROR_SUCCESS;
633 }
634
635 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
636 {
637     LPWSTR szwProduct = NULL;
638     INSTALLSTATE r;
639
640     if( szProduct )
641     {
642          szwProduct = strdupAtoW( szProduct );
643          if( !szwProduct )
644              return ERROR_OUTOFMEMORY;
645     }
646     r = MsiQueryProductStateW( szwProduct );
647     msi_free( szwProduct );
648     return r;
649 }
650
651 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
652 {
653     UINT rc;
654     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
655     HKEY hkey = 0;
656     static const WCHAR szWindowsInstaller[] = {
657          'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 };
658     DWORD sz;
659
660     TRACE("%s\n", debugstr_w(szProduct));
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 %lx %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 %lx %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     FIXME("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
828     return INSTALLSTATE_UNKNOWN;
829 }
830
831 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
832                 DWORD *pcchBuf)
833 {
834     FIXME("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
835     return INSTALLSTATE_UNKNOWN;
836 }
837
838 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
839                 WORD wLanguageId, DWORD f)
840 {
841     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),
842           uType,wLanguageId,f);
843     return ERROR_CALL_NOT_IMPLEMENTED;
844 }
845
846 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
847                 WORD wLanguageId, DWORD f)
848 {
849     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),
850           uType,wLanguageId,f);
851     return ERROR_CALL_NOT_IMPLEMENTED;
852 }
853
854 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
855                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
856                 DWORD* pcchPathBuf )
857 {
858     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName),
859           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
860           pcchPathBuf);
861     return ERROR_CALL_NOT_IMPLEMENTED;
862 }
863
864 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
865                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
866                 DWORD* pcchPathBuf )
867 {
868     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName),
869           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
870           pcchPathBuf);
871     return ERROR_CALL_NOT_IMPLEMENTED;
872 }
873
874 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
875                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
876 {
877     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
878     return ERROR_CALL_NOT_IMPLEMENTED;
879 }
880
881 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
882                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
883 {
884     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
885     return ERROR_CALL_NOT_IMPLEMENTED;
886 }
887
888 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
889                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
890                 DWORD* pcbHashData)
891 {
892     FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
893           ppcCertContext, pbHashData, pcbHashData);
894     return ERROR_CALL_NOT_IMPLEMENTED;
895 }
896
897 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
898                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
899                 DWORD* pcbHashData)
900 {
901     FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
902           ppcCertContext, pbHashData, pcbHashData);
903     return ERROR_CALL_NOT_IMPLEMENTED;
904 }
905
906 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
907                                     LPSTR szValue, DWORD *pccbValue )
908 {
909     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
910     return ERROR_CALL_NOT_IMPLEMENTED;
911 }
912
913 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
914                                     LPWSTR szValue, DWORD *pccbValue )
915 {
916     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
917     return ERROR_CALL_NOT_IMPLEMENTED;
918 }
919
920 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
921 {
922     UINT r;
923     LPWSTR szPack = NULL;
924
925     TRACE("%s\n", debugstr_a(szPackage) );
926
927     if( szPackage )
928     {
929         szPack = strdupAtoW( szPackage );
930         if( !szPack )
931             return ERROR_OUTOFMEMORY;
932     }
933
934     r = MsiVerifyPackageW( szPack );
935
936     msi_free( szPack );
937
938     return r;
939 }
940
941 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
942 {
943     MSIHANDLE handle;
944     UINT r;
945
946     TRACE("%s\n", debugstr_w(szPackage) );
947
948     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
949     MsiCloseHandle( handle );
950
951     return r;
952 }
953
954 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
955                                          LPSTR lpPathBuf, DWORD* pcchBuf)
956 {
957     LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL;
958     INSTALLSTATE rc;
959     UINT incoming_len;
960
961     if( szProduct )
962     {
963         szwProduct = strdupAtoW( szProduct );
964         if( !szwProduct)
965             return ERROR_OUTOFMEMORY;
966     }
967
968     if( szComponent )
969     {
970         szwComponent = strdupAtoW( szComponent );
971         if( !szwComponent )
972         {
973             msi_free( szwProduct);
974             return ERROR_OUTOFMEMORY;
975         }
976     }
977
978     if( pcchBuf && *pcchBuf > 0 )
979     {
980         lpwPathBuf = msi_alloc( *pcchBuf * sizeof(WCHAR));
981         incoming_len = *pcchBuf;
982     }
983     else
984     {
985         lpwPathBuf = NULL;
986         incoming_len = 0;
987     }
988
989     rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
990
991     msi_free( szwProduct);
992     msi_free( szwComponent);
993     if (lpwPathBuf)
994     {
995         if (rc != INSTALLSTATE_UNKNOWN)
996             WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len,
997                             lpPathBuf, incoming_len, NULL, NULL);
998         msi_free( lpwPathBuf);
999     }
1000
1001     return rc;
1002 }
1003
1004 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1005                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1006 {
1007     WCHAR squished_pc[GUID_SIZE];
1008     UINT rc;
1009     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
1010     HKEY hkey = 0;
1011     LPWSTR path = NULL;
1012     DWORD sz, type;
1013
1014     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1015            debugstr_w(szComponent), lpPathBuf, pcchBuf);
1016
1017     if( !szComponent )
1018         return INSTALLSTATE_INVALIDARG;
1019     if( lpPathBuf && !pcchBuf )
1020         return INSTALLSTATE_INVALIDARG;
1021
1022     squash_guid(szProduct,squished_pc);
1023
1024     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1025     if( rc != ERROR_SUCCESS )
1026         goto end;
1027
1028     RegCloseKey(hkey);
1029
1030     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1031     if( rc != ERROR_SUCCESS )
1032         goto end;
1033
1034     sz = 0;
1035     type = 0;
1036     rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz );
1037     if( rc != ERROR_SUCCESS )
1038         goto end;
1039     if( type != REG_SZ )
1040         goto end;
1041
1042     sz += sizeof(WCHAR);
1043     path = msi_alloc( sz );
1044     if( !path )
1045         goto end;
1046
1047     rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz );
1048     if( rc != ERROR_SUCCESS )
1049         goto end;
1050
1051     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1052            debugstr_w(szProduct), debugstr_w(path));
1053
1054     if (path[0]=='0')
1055     {
1056         FIXME("Registry entry.. check entry\n");
1057         rrc = INSTALLSTATE_LOCAL;
1058     }
1059     else
1060     {
1061         /* PROBABLY a file */
1062         if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES )
1063             rrc = INSTALLSTATE_LOCAL;
1064         else
1065             rrc = INSTALLSTATE_ABSENT;
1066     }
1067
1068     if( pcchBuf )
1069     {
1070         sz = sz / sizeof(WCHAR);
1071         if( *pcchBuf >= sz )
1072             lstrcpyW( lpPathBuf, path );
1073         *pcchBuf = sz;
1074     }
1075
1076 end:
1077     msi_free(path );
1078     RegCloseKey(hkey);
1079     return rrc;
1080 }
1081
1082 /******************************************************************
1083  * MsiQueryFeatureStateA      [MSI.@]
1084  */
1085 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1086 {
1087     INSTALLSTATE rc;
1088     LPWSTR szwProduct= NULL;
1089     LPWSTR szwFeature= NULL;
1090
1091     if( szProduct )
1092     {
1093         szwProduct = strdupAtoW( szProduct );
1094         if( !szwProduct)
1095             return ERROR_OUTOFMEMORY;
1096     }
1097
1098     if( szFeature )
1099     {
1100         szwFeature = strdupAtoW( szFeature );
1101         if( !szwFeature)
1102         {
1103             msi_free( szwProduct);
1104             return ERROR_OUTOFMEMORY;
1105         }
1106     }
1107
1108     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1109
1110     msi_free( szwProduct);
1111     msi_free( szwFeature);
1112
1113     return rc;
1114 }
1115
1116 /******************************************************************
1117  * MsiQueryFeatureStateW      [MSI.@]
1118  *
1119  * This does not verify that the Feature is functional. So i am only going to
1120  * check the existence of the key in the registry. This should tell me if it is
1121  * installed.
1122  */
1123 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1124 {
1125     UINT rc;
1126     DWORD sz = 0;
1127     HKEY hkey;
1128
1129     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1130
1131     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
1132     if (rc != ERROR_SUCCESS)
1133         return INSTALLSTATE_UNKNOWN;
1134
1135     rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz);
1136     RegCloseKey(hkey);
1137
1138     if (rc == ERROR_SUCCESS)
1139         return INSTALLSTATE_LOCAL;
1140     else
1141         return INSTALLSTATE_ABSENT;
1142 }
1143
1144 /******************************************************************
1145  * MsiGetFileVersionA         [MSI.@]
1146  */
1147 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1148                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1149 {
1150     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1151     UINT ret = ERROR_OUTOFMEMORY;
1152
1153     if( szFilePath )
1154     {
1155         szwFilePath = strdupAtoW( szFilePath );
1156         if( !szwFilePath )
1157             goto end;
1158     }
1159
1160     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1161     {
1162         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1163         if( !lpwVersionBuff )
1164             goto end;
1165     }
1166
1167     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1168     {
1169         lpwLangBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1170         if( !lpwLangBuff )
1171             goto end;
1172     }
1173
1174     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1175                              lpwLangBuff, pcchLangBuf);
1176
1177     if( lpwVersionBuff )
1178         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1179                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1180     if( lpwLangBuff )
1181         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1182                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1183
1184 end:
1185     msi_free(szwFilePath);
1186     msi_free(lpwVersionBuff);
1187     msi_free(lpwLangBuff);
1188
1189     return ret;
1190 }
1191
1192 /******************************************************************
1193  * MsiGetFileVersionW         [MSI.@]
1194  */
1195 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1196                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1197 {
1198     static const WCHAR szVersionResource[] = {'\\',0};
1199     static const WCHAR szVersionFormat[] = {
1200         '%','d','.','%','d','.','%','d','.','%','d',0};
1201     static const WCHAR szLangFormat[] = {'%','d',0};
1202     UINT ret = 0;
1203     DWORD dwVerLen;
1204     LPVOID lpVer = NULL;
1205     VS_FIXEDFILEINFO *ffi;
1206     UINT puLen;
1207     WCHAR tmp[32];
1208
1209     TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath),
1210           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1211           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1212
1213     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1214     if( !dwVerLen )
1215         return GetLastError();
1216
1217     lpVer = msi_alloc(dwVerLen);
1218     if( !lpVer )
1219     {
1220         ret = ERROR_OUTOFMEMORY;
1221         goto end;
1222     }
1223
1224     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1225     {
1226         ret = GetLastError();
1227         goto end;
1228     }
1229     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1230     {
1231         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1232             (puLen > 0) )
1233         {
1234             wsprintfW(tmp, szVersionFormat,
1235                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1236                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1237             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1238             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1239         }
1240         else
1241         {
1242             *lpVersionBuf = 0;
1243             *pcchVersionBuf = 0;
1244         }
1245     }
1246
1247     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1248     {
1249         DWORD lang = GetUserDefaultLangID();
1250
1251         FIXME("Retrieve language from file\n");
1252         wsprintfW(tmp, szLangFormat, lang);
1253         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1254         *pcchLangBuf = lstrlenW(lpLangBuf);
1255     }
1256
1257 end:
1258     msi_free(lpVer);
1259     return ret;
1260 }
1261
1262
1263 /******************************************************************
1264  *      DllMain
1265  */
1266 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1267 {
1268     switch(fdwReason)
1269     {
1270     case DLL_PROCESS_ATTACH:
1271         msi_hInstance = hinstDLL;
1272         DisableThreadLibraryCalls(hinstDLL);
1273         msi_dialog_register_class();
1274         break;
1275     case DLL_PROCESS_DETACH:
1276         msi_dialog_unregister_class();
1277         /* FIXME: Cleanup */
1278         break;
1279     }
1280     return TRUE;
1281 }
1282
1283 typedef struct tagIClassFactoryImpl
1284 {
1285     const IClassFactoryVtbl *lpVtbl;
1286 } IClassFactoryImpl;
1287
1288 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
1289                 REFIID riid,LPVOID *ppobj)
1290 {
1291     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1292     FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
1293     return E_NOINTERFACE;
1294 }
1295
1296 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
1297 {
1298     return 2;
1299 }
1300
1301 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
1302 {
1303     return 1;
1304 }
1305
1306 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
1307     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
1308 {
1309     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1310
1311     FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
1312     return E_FAIL;
1313 }
1314
1315 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1316 {
1317     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1318
1319     FIXME("%p %d\n", This, dolock);
1320     return S_OK;
1321 }
1322
1323 static const IClassFactoryVtbl MsiCF_Vtbl =
1324 {
1325     MsiCF_QueryInterface,
1326     MsiCF_AddRef,
1327     MsiCF_Release,
1328     MsiCF_CreateInstance,
1329     MsiCF_LockServer
1330 };
1331
1332 static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
1333
1334 /******************************************************************
1335  * DllGetClassObject          [MSI.@]
1336  */
1337 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1338 {
1339     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1340
1341     if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
1342         IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
1343         IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
1344         IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
1345         IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
1346     {
1347         *ppv = (LPVOID) &Msi_CF;
1348         return S_OK;
1349     }
1350     return CLASS_E_CLASSNOTAVAILABLE;
1351 }
1352
1353 /******************************************************************
1354  * DllGetVersion              [MSI.@]
1355  */
1356 HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
1357 {
1358     TRACE("%p\n",pdvi);
1359
1360     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
1361         return E_INVALIDARG;
1362
1363     pdvi->dwMajorVersion = MSI_MAJORVERSION;
1364     pdvi->dwMinorVersion = MSI_MINORVERSION;
1365     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
1366     pdvi->dwPlatformID = 1;
1367
1368     return S_OK;
1369 }
1370
1371 /******************************************************************
1372  * DllCanUnloadNow            [MSI.@]
1373  */
1374 HRESULT WINAPI DllCanUnloadNow(void)
1375 {
1376     return S_FALSE;
1377 }
1378
1379 /***********************************************************************
1380  * MsiGetFeatureUsageW           [MSI.@]
1381  */
1382 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1383                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1384 {
1385     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1386           pdwUseCount, pwDateUsed);
1387     return ERROR_CALL_NOT_IMPLEMENTED;
1388 }
1389
1390 /***********************************************************************
1391  * MsiGetFeatureUsageA           [MSI.@]
1392  */
1393 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1394                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1395 {
1396     LPWSTR prod = NULL, feat = NULL;
1397     UINT ret = ERROR_OUTOFMEMORY;
1398
1399     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1400           pdwUseCount, pwDateUsed);
1401
1402     prod = strdupAtoW( szProduct );
1403     if (szProduct && !prod)
1404         goto end;
1405
1406     feat = strdupAtoW( szFeature );
1407     if (szFeature && !feat)
1408         goto end;
1409
1410     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1411
1412 end:
1413     msi_free( prod );
1414     msi_free( feat );
1415
1416     return ret;
1417 }
1418
1419 /***********************************************************************
1420  * MsiUseFeatureExW           [MSI.@]
1421  */
1422 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1423                                       DWORD dwInstallMode, DWORD dwReserved )
1424 {
1425     FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1426           dwInstallMode, dwReserved);
1427
1428     /*
1429      * Polls all the components of the feature to find install state and then
1430      *  writes:
1431      *    Software\\Microsoft\\Windows\\CurrentVersion\\
1432      *    Installer\\Products\\<squishguid>\\<feature>
1433      *      "Usage"=dword:........
1434      */
1435
1436     return INSTALLSTATE_LOCAL;
1437 }
1438
1439 /***********************************************************************
1440  * MsiUseFeatureExA           [MSI.@]
1441  */
1442 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1443                                       DWORD dwInstallMode, DWORD dwReserved )
1444 {
1445     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1446     LPWSTR prod = NULL, feat = NULL;
1447
1448     TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1449           dwInstallMode, dwReserved);
1450
1451     prod = strdupAtoW( szProduct );
1452     if (szProduct && !prod)
1453         goto end;
1454
1455     feat = strdupAtoW( szFeature );
1456     if (szFeature && !feat)
1457         goto end;
1458
1459     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1460
1461 end:
1462     msi_free( prod );
1463     msi_free( feat );
1464
1465     return ret;
1466 }
1467
1468 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1469 {
1470     FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1471
1472     return INSTALLSTATE_LOCAL;
1473 }
1474
1475 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1476 {
1477     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1478     LPWSTR prod = NULL, feat = NULL;
1479
1480     TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) );
1481
1482     prod = strdupAtoW( szProduct );
1483     if (szProduct && !prod)
1484         goto end;
1485
1486     feat = strdupAtoW( szFeature );
1487     if (szFeature && !feat)
1488         goto end;
1489
1490     ret = MsiUseFeatureW( prod, feat );
1491
1492 end:
1493     msi_free( prod );
1494     msi_free( feat );
1495
1496     return ret;
1497 }
1498
1499 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1500                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1501                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1502                 DWORD* pcchPathBuf)
1503 {
1504     HKEY hkey;
1505     UINT rc;
1506     LPWSTR info;
1507     DWORD sz;
1508     LPWSTR product = NULL;
1509     LPWSTR component = NULL;
1510     LPWSTR ptr;
1511     GUID clsid;
1512
1513     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
1514           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1515           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1516    
1517     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1518     if (rc != ERROR_SUCCESS)
1519         return ERROR_INDEX_ABSENT;
1520
1521     sz = 0;
1522     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
1523     if (sz <= 0)
1524     {
1525         RegCloseKey(hkey);
1526         return ERROR_INDEX_ABSENT;
1527     }
1528
1529     info = msi_alloc(sz);
1530     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
1531     if (rc != ERROR_SUCCESS)
1532     {
1533         RegCloseKey(hkey);
1534         msi_free(info);
1535         return ERROR_INDEX_ABSENT;
1536     }
1537
1538     /* find the component */
1539     ptr = strchrW(&info[20],'>');
1540     if (ptr)
1541         ptr++;
1542     else
1543     {
1544         RegCloseKey(hkey);
1545         msi_free(info);
1546         return ERROR_INDEX_ABSENT;
1547     }
1548
1549     if (!szProduct)
1550     {
1551         decode_base85_guid(info,&clsid);
1552         StringFromCLSID(&clsid, &product);
1553     }
1554     decode_base85_guid(ptr,&clsid);
1555     StringFromCLSID(&clsid, &component);
1556
1557     if (!szProduct)
1558         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
1559     else
1560         rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
1561    
1562     RegCloseKey(hkey);
1563     msi_free(info);
1564     msi_free(product);
1565     msi_free(component);
1566
1567     if (rc == INSTALLSTATE_LOCAL)
1568         return ERROR_SUCCESS;
1569     else 
1570         return ERROR_FILE_NOT_FOUND;
1571 }
1572
1573 /***********************************************************************
1574  * MsiProvideQualifiedComponentW [MSI.@]
1575  */
1576 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1577                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1578                 DWORD* pcchPathBuf)
1579 {
1580     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1581                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1582 }
1583
1584 /***********************************************************************
1585  * MsiProvideQualifiedComponentA [MSI.@]
1586  */
1587 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1588                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1589                 DWORD* pcchPathBuf)
1590 {
1591     LPWSTR szwComponent, szwQualifier, lpwPathBuf;
1592     DWORD pcchwPathBuf;
1593     UINT rc;
1594
1595     TRACE("%s %s %li %p %p\n",szComponent, szQualifier,
1596                     dwInstallMode, lpPathBuf, pcchPathBuf);
1597
1598     szwComponent= strdupAtoW( szComponent);
1599     szwQualifier= strdupAtoW( szQualifier);
1600
1601     lpwPathBuf = msi_alloc(*pcchPathBuf * sizeof(WCHAR));
1602
1603     pcchwPathBuf = *pcchPathBuf;
1604
1605     rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, 
1606                     dwInstallMode, lpwPathBuf, &pcchwPathBuf);
1607
1608     msi_free(szwComponent);
1609     msi_free(szwQualifier);
1610     *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf,
1611                     lpPathBuf, *pcchPathBuf, NULL, NULL);
1612
1613     msi_free(lpwPathBuf);
1614     return rc;
1615 }
1616
1617 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf,
1618                 DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf,
1619                 DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1620 {
1621     HKEY hkey;
1622     DWORD sz;
1623     UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS;
1624
1625     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1626           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1627           pcchSerialBuf);
1628
1629     rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1630     if (rc != ERROR_SUCCESS)
1631         return USERINFOSTATE_UNKNOWN;
1632
1633     if (lpUserNameBuf)
1634     {
1635         sz = *lpUserNameBuf * sizeof(WCHAR);
1636         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
1637                 NULL, (LPBYTE)lpUserNameBuf,
1638                                &sz);
1639     }
1640     if (!lpUserNameBuf && pcchUserNameBuf)
1641     {
1642         sz = 0;
1643         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
1644                 NULL, NULL, &sz);
1645     }
1646
1647     if (pcchUserNameBuf)
1648         *pcchUserNameBuf = sz / sizeof(WCHAR);
1649
1650     if (lpOrgNameBuf)
1651     {
1652         sz = *pcchOrgNameBuf * sizeof(WCHAR);
1653         rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
1654                 NULL, (LPBYTE)lpOrgNameBuf, &sz);
1655     }
1656     if (!lpOrgNameBuf && pcchOrgNameBuf)
1657     {
1658         sz = 0;
1659         rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
1660                 NULL, NULL, &sz);
1661     }
1662
1663     if (pcchOrgNameBuf)
1664         *pcchOrgNameBuf = sz / sizeof(WCHAR);
1665
1666     if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && 
1667         rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA)
1668     {
1669         RegCloseKey(hkey);
1670         return USERINFOSTATE_ABSENT;
1671     }
1672
1673     if (lpSerialBuf)
1674     {
1675         sz = *pcchSerialBuf * sizeof(WCHAR);
1676         RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL, NULL,
1677                 (LPBYTE)lpSerialBuf, &sz);
1678     }
1679     if (!lpSerialBuf && pcchSerialBuf)
1680     {
1681         sz = 0;
1682         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL,
1683                 NULL, NULL, &sz);
1684     }
1685     if (pcchSerialBuf)
1686         *pcchSerialBuf = sz / sizeof(WCHAR);
1687     
1688     RegCloseKey(hkey);
1689     return USERINFOSTATE_PRESENT;
1690 }
1691
1692 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf,
1693                 DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf,
1694                 DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1695 {
1696     FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf,
1697           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1698           pcchSerialBuf);
1699
1700     return USERINFOSTATE_UNKNOWN;
1701 }
1702
1703 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1704 {
1705     MSIHANDLE handle;
1706     UINT rc;
1707     MSIPACKAGE *package;
1708     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1709
1710     TRACE("(%s)\n",debugstr_w(szProduct));
1711
1712     rc = MsiOpenProductW(szProduct,&handle);
1713     if (rc != ERROR_SUCCESS)
1714         return ERROR_INVALID_PARAMETER;
1715
1716     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1717     rc = ACTION_PerformUIAction(package, szFirstRun);
1718     msiobj_release( &package->hdr );
1719
1720     MsiCloseHandle(handle);
1721
1722     return rc;
1723 }
1724
1725 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1726 {
1727     MSIHANDLE handle;
1728     UINT rc;
1729     MSIPACKAGE *package;
1730     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1731
1732     TRACE("(%s)\n",debugstr_a(szProduct));
1733
1734     rc = MsiOpenProductA(szProduct,&handle);
1735     if (rc != ERROR_SUCCESS)
1736         return ERROR_INVALID_PARAMETER;
1737
1738     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1739     rc = ACTION_PerformUIAction(package, szFirstRun);
1740     msiobj_release( &package->hdr );
1741
1742     MsiCloseHandle(handle);
1743
1744     return rc;
1745 }
1746
1747 /***********************************************************************
1748  * MsiConfigureFeatureA            [MSI.@]
1749  */
1750 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1751 {
1752     FIXME("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1753     return ERROR_SUCCESS;
1754 }
1755
1756 /***********************************************************************
1757  * MsiConfigureFeatureW            [MSI.@]
1758  */
1759 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1760 {
1761     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1762     return ERROR_SUCCESS;
1763 }
1764
1765 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1766 {
1767     WCHAR path[MAX_PATH];
1768
1769     if(dwReserved) {
1770         FIXME("Don't know how to handle argument %ld\n", dwReserved);
1771         return ERROR_CALL_NOT_IMPLEMENTED;
1772     }
1773
1774    if(!GetWindowsDirectoryW(path, MAX_PATH)) {
1775         FIXME("GetWindowsDirectory failed unexpected! Error %ld\n",
1776               GetLastError());
1777         return ERROR_CALL_NOT_IMPLEMENTED;
1778    }
1779
1780    strcatW(path, installerW);
1781
1782    CreateDirectoryW(path, NULL);
1783
1784    return 0;
1785 }
1786
1787 /***********************************************************************
1788  * MsiGetShortcutTargetA           [MSI.@]
1789  */
1790 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1791                                    LPSTR szProductCode, LPSTR szFeatureId,
1792                                    LPSTR szComponentCode )
1793 {
1794     LPWSTR target;
1795     const int len = MAX_FEATURE_CHARS+1;
1796     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1797     UINT r;
1798
1799     target = strdupAtoW( szShortcutTarget );
1800     if (szShortcutTarget && !target )
1801         return ERROR_OUTOFMEMORY;
1802     product[0] = 0;
1803     feature[0] = 0;
1804     component[0] = 0;
1805     r = MsiGetShortcutTargetW( target, product, feature, component );
1806     msi_free( target );
1807     if (r == ERROR_SUCCESS)
1808     {
1809         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1810         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1811         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1812     }
1813     return r;
1814 }
1815
1816 /***********************************************************************
1817  * MsiGetShortcutTargetW           [MSI.@]
1818  */
1819 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1820                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1821                                    LPWSTR szComponentCode )
1822 {
1823     IShellLinkDataList *dl = NULL;
1824     IPersistFile *pf = NULL;
1825     LPEXP_DARWIN_LINK darwin = NULL;
1826     HRESULT r;
1827
1828     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1829           szProductCode, szFeatureId, szComponentCode );
1830
1831     r = CoInitialize(NULL);
1832     if( FAILED( r ) )
1833         return ERROR_FUNCTION_FAILED;
1834
1835     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1836                           &IID_IPersistFile, (LPVOID*) &pf );
1837     if( SUCCEEDED( r ) )
1838     {
1839         r = IPersistFile_Load( pf, szShortcutTarget,
1840                                STGM_READ | STGM_SHARE_DENY_WRITE );
1841         if( SUCCEEDED( r ) )
1842         {
1843             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1844                                              (LPVOID*) dl );
1845             if( SUCCEEDED( r ) )
1846             {
1847                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1848                                                   (LPVOID) &darwin );
1849                 IShellLinkDataList_Release( dl );
1850             }
1851         }
1852         IPersistFile_Release( pf );
1853     }
1854
1855     CoUninitialize();
1856
1857     TRACE("darwin = %p\n", darwin);
1858
1859     if (darwin)
1860     {
1861         DWORD sz;
1862         UINT ret;
1863
1864         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1865                   szProductCode, szFeatureId, szComponentCode, &sz );
1866         LocalFree( darwin );
1867         return ret;
1868     }
1869
1870     return ERROR_FUNCTION_FAILED;
1871 }
1872
1873 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1874                                   DWORD dwReinstallMode )
1875 {
1876     MSIPACKAGE* package = NULL;
1877     UINT r;
1878     DWORD sz;
1879     WCHAR sourcepath[MAX_PATH];
1880     WCHAR filename[MAX_PATH];
1881     static const WCHAR szInstalled[] = {
1882         ' ','L','O','G','V','E','R','B','O','S','E','=','1',' ','I','n','s','t','a','l','l','e','d','=','1',0};
1883     static const WCHAR fmt[] = {'R','E','I','N','S','T','A','L','L','=','%','s',0};
1884     static const WCHAR REINSTALLMODE[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
1885     WCHAR reinstallmode[11];
1886     LPWSTR ptr;
1887     LPWSTR commandline;
1888
1889     FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1890                            dwReinstallMode);
1891
1892     memset(reinstallmode,0,sizeof(reinstallmode));
1893     ptr = reinstallmode;
1894
1895     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
1896         { *ptr = 'p'; ptr++; }
1897     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
1898         { *ptr = 'o'; ptr++; }
1899     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
1900         { *ptr = 'w'; ptr++; }
1901     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
1902         { *ptr = 'd'; ptr++; }
1903     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
1904         { *ptr = 'c'; ptr++; }
1905     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
1906         { *ptr = 'a'; ptr++; }
1907     if (dwReinstallMode & REINSTALLMODE_USERDATA)
1908         { *ptr = 'u'; ptr++; }
1909     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
1910         { *ptr = 'm'; ptr++; }
1911     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
1912         { *ptr = 's'; ptr++; }
1913     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1914         { *ptr = 'v'; ptr++; }
1915     
1916     sz = sizeof(sourcepath);
1917     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1918             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
1919             &sz);
1920
1921     sz = sizeof(filename);
1922     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1923             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1924
1925     strcatW(sourcepath,filename);
1926
1927     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1928         r = MSI_OpenPackageW( sourcepath, &package );
1929     else
1930         r = MSI_OpenProductW( szProduct, &package );
1931
1932     if (r != ERROR_SUCCESS)
1933         return r;
1934
1935     MSI_SetPropertyW(package,REINSTALLMODE,reinstallmode);
1936     
1937     sz = lstrlenW(szInstalled);
1938     sz += lstrlenW(fmt);
1939     sz += lstrlenW(szFeature);
1940
1941     commandline = msi_alloc(sz * sizeof(WCHAR));
1942
1943     sprintfW(commandline,fmt,szFeature);
1944     lstrcatW(commandline,szInstalled);
1945
1946     r = MSI_InstallPackage( package, sourcepath, commandline );
1947
1948     msiobj_release( &package->hdr );
1949
1950     msi_free(commandline);
1951
1952     return r;
1953 }
1954
1955 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1956                                   DWORD dwReinstallMode )
1957 {
1958     LPWSTR wszProduct;
1959     LPWSTR wszFeature;
1960     UINT rc;
1961
1962     TRACE("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1963                            dwReinstallMode);
1964
1965     wszProduct = strdupAtoW(szProduct);
1966     wszFeature = strdupAtoW(szFeature);
1967
1968     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
1969     
1970     msi_free(wszProduct);
1971     msi_free(wszFeature);
1972     return rc;
1973 }
1974
1975 /***********************************************************************
1976  * MsiEnumPatchesA            [MSI.@]
1977  */
1978 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, 
1979         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1980 {
1981     FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
1982           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1983     return ERROR_NO_MORE_ITEMS;
1984 }
1985
1986 /***********************************************************************
1987  * MsiEnumPatchesW            [MSI.@]
1988  */
1989 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, 
1990         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1991 {
1992     FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct),
1993           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1994     return ERROR_NO_MORE_ITEMS;
1995 }