msi: Add an implementation of MsiGetDatabaseState.
[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 /* the UI level */
47 INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
48 HWND           gUIhwnd = 0;
49 INSTALLUI_HANDLERA gUIHandlerA = NULL;
50 INSTALLUI_HANDLERW gUIHandlerW = NULL;
51 DWORD gUIFilter = 0;
52 LPVOID gUIContext = NULL;
53 WCHAR gszLogFile[MAX_PATH];
54 HINSTANCE msi_hInstance;
55
56 static LONG dll_count;
57
58 static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0};
59
60 /*
61  * Dll lifetime tracking declaration
62  */
63 static void LockModule(void)
64 {
65     InterlockedIncrement(&dll_count);
66 }
67
68 static void UnlockModule(void)
69 {
70     InterlockedDecrement(&dll_count);
71 }
72
73
74 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
75 {
76     UINT r;
77     LPWSTR szwProd = NULL;
78
79     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
80
81     if( szProduct )
82     {
83         szwProd = strdupAtoW( szProduct );
84         if( !szwProd )
85             return ERROR_OUTOFMEMORY;
86     }
87
88     r = MsiOpenProductW( szwProd, phProduct );
89
90     msi_free( szwProd );
91
92     return r;
93 }
94
95 static UINT MSI_OpenProductW( LPCWSTR szProduct, MSIPACKAGE **ppackage )
96 {
97     LPWSTR path = NULL;
98     UINT r;
99     HKEY hKeyProduct = NULL;
100     DWORD count, type;
101
102     TRACE("%s %p\n", debugstr_w(szProduct), ppackage );
103
104     r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE);
105     if( r != ERROR_SUCCESS )
106     {
107         r = ERROR_UNKNOWN_PRODUCT;
108         goto end;
109     }
110
111     /* find the size of the path */
112     type = count = 0;
113     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
114                           NULL, &type, NULL, &count );
115     if( r != ERROR_SUCCESS )
116     {
117         r = ERROR_UNKNOWN_PRODUCT;
118         goto end;
119     }
120
121     /* now alloc and fetch the path of the database to open */
122     path = msi_alloc( count );
123     if( !path )
124         goto end;
125
126     r = RegQueryValueExW( hKeyProduct, INSTALLPROPERTY_LOCALPACKAGEW,
127                           NULL, &type, (LPBYTE) path, &count );
128     if( r != ERROR_SUCCESS )
129     {
130         r = ERROR_UNKNOWN_PRODUCT;
131         goto end;
132     }
133
134     r = MSI_OpenPackageW( path, ppackage );
135
136 end:
137     msi_free( path );
138     if( hKeyProduct )
139         RegCloseKey( hKeyProduct );
140
141     return r;
142 }
143
144 UINT WINAPI MsiOpenProductW( LPCWSTR szProduct, MSIHANDLE *phProduct )
145 {
146    MSIPACKAGE *package = NULL;
147    UINT r;
148
149    r = MSI_OpenProductW( szProduct, &package );
150    if( r == ERROR_SUCCESS )
151    {
152        *phProduct = alloc_msihandle( &package->hdr );
153        msiobj_release( &package->hdr );
154    }
155    return r;
156 }
157
158 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
159                 LPCSTR szTransforms, LANGID lgidLanguage)
160 {
161     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
162           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
163     return ERROR_CALL_NOT_IMPLEMENTED;
164 }
165
166 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
167                 LPCWSTR szTransforms, LANGID lgidLanguage)
168 {
169     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
170           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
171     return ERROR_CALL_NOT_IMPLEMENTED;
172 }
173
174 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
175       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
176 {
177     FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath),
178           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
179           lgidLanguage, dwPlatform, dwOptions);
180     return ERROR_CALL_NOT_IMPLEMENTED;
181 }
182
183 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
184       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
185 {
186     FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath),
187           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
188           lgidLanguage, dwPlatform, dwOptions);
189     return ERROR_CALL_NOT_IMPLEMENTED;
190 }
191
192 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
193 {
194     LPWSTR szwPath = NULL, szwCommand = NULL;
195     UINT r = ERROR_OUTOFMEMORY;
196
197     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
198
199     if( szPackagePath )
200     {
201         szwPath = strdupAtoW( szPackagePath );
202         if( !szwPath )
203             goto end;
204     }
205
206     if( szCommandLine )
207     {
208         szwCommand = strdupAtoW( szCommandLine );
209         if( !szwCommand )
210             goto end;
211     }
212
213     r = MsiInstallProductW( szwPath, szwCommand );
214
215 end:
216     msi_free( szwPath );
217     msi_free( szwCommand );
218
219     return r;
220 }
221
222 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
223 {
224     MSIPACKAGE *package = NULL;
225     UINT r;
226
227     FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
228
229     r = MSI_OpenPackageW( szPackagePath, &package );
230     if (r == ERROR_SUCCESS)
231     {
232         r = MSI_InstallPackage( package, szPackagePath, szCommandLine );
233         msiobj_release( &package->hdr );
234     }
235
236     return r;
237 }
238
239 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
240 {
241     FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode);
242     return ERROR_CALL_NOT_IMPLEMENTED;
243 }
244
245 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
246 {
247     FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode);
248     return ERROR_CALL_NOT_IMPLEMENTED;
249 }
250
251 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
252         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
253 {
254     FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
255           eInstallType, debugstr_a(szCommandLine));
256     return ERROR_CALL_NOT_IMPLEMENTED;
257 }
258
259 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
260          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
261 {
262     FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
263           eInstallType, debugstr_w(szCommandLine));
264     return ERROR_CALL_NOT_IMPLEMENTED;
265 }
266
267 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
268                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
269 {
270     MSIPACKAGE* package = NULL;
271     UINT r;
272     DWORD sz;
273     WCHAR sourcepath[MAX_PATH];
274     WCHAR filename[MAX_PATH];
275     static const WCHAR szInstalled[] = {
276         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
277     LPWSTR commandline;
278
279     FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
280           debugstr_w(szCommandLine));
281
282     if (eInstallState != INSTALLSTATE_LOCAL &&
283         eInstallState != INSTALLSTATE_DEFAULT)
284     {
285         FIXME("Not implemented for anything other than local installs\n");
286         return ERROR_CALL_NOT_IMPLEMENTED;
287     }
288
289     sz = sizeof(sourcepath);
290     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
291             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
292             &sz);
293
294     sz = sizeof(filename);
295     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
296             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
297
298     lstrcatW(sourcepath,filename);
299
300     /*
301      * ok 1, we need to find the msi file for this product.
302      *    2, find the source dir for the files
303      *    3, do the configure/install.
304      *    4, cleanupany runonce entry.
305      */
306
307     r = MSI_OpenProductW( szProduct, &package );
308     if (r != ERROR_SUCCESS)
309         return r;
310
311     sz = lstrlenW(szInstalled) + 1;
312
313     if (szCommandLine)
314         sz += lstrlenW(szCommandLine);
315
316     commandline = msi_alloc(sz * sizeof(WCHAR));
317     if (!commandline )
318     {
319         r = ERROR_OUTOFMEMORY;
320         goto end;
321     }
322
323     commandline[0] = 0;
324     if (szCommandLine)
325         lstrcpyW(commandline,szCommandLine);
326
327     if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN)
328         lstrcatW(commandline,szInstalled);
329
330     r = MSI_InstallPackage( package, sourcepath, commandline );
331
332     msi_free(commandline);
333
334 end:
335     msiobj_release( &package->hdr );
336
337     return r;
338 }
339
340 UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel,
341                         INSTALLSTATE eInstallState, LPCSTR szCommandLine)
342 {
343     LPWSTR szwProduct = NULL;
344     LPWSTR szwCommandLine = NULL;
345     UINT r = ERROR_OUTOFMEMORY;
346
347     if( szProduct )
348     {
349         szwProduct = strdupAtoW( szProduct );
350         if( !szwProduct )
351             goto end;
352     }
353
354     if( szCommandLine)
355     {
356         szwCommandLine = strdupAtoW( szCommandLine );
357         if( !szwCommandLine)
358             goto end;
359     }
360
361     r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState,
362                                 szwCommandLine );
363 end:
364     msi_free( szwProduct );
365     msi_free( szwCommandLine);
366
367     return r;
368 }
369
370 UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel,
371                                  INSTALLSTATE eInstallState)
372 {
373     LPWSTR szwProduct = NULL;
374     UINT r;
375
376     TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
377
378     if( szProduct )
379     {
380         szwProduct = strdupAtoW( szProduct );
381         if( !szwProduct )
382             return ERROR_OUTOFMEMORY;
383     }
384
385     r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
386     msi_free( szwProduct );
387
388     return r;
389 }
390
391 UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel,
392                                  INSTALLSTATE eInstallState)
393 {
394     FIXME("%s %d %d\n", debugstr_w(szProduct), iInstallLevel, eInstallState);
395
396     return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL);
397 }
398
399 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
400 {
401     LPWSTR szwComponent = NULL;
402     UINT r;
403     WCHAR szwBuffer[GUID_SIZE];
404
405     TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
406
407     if( szComponent )
408     {
409         szwComponent = strdupAtoW( szComponent );
410         if( !szwComponent )
411             return ERROR_OUTOFMEMORY;
412     }
413
414     r = MsiGetProductCodeW( szwComponent, szwBuffer );
415
416     if( ERROR_SUCCESS == r )
417         WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
418
419     msi_free( szwComponent );
420
421     return r;
422 }
423
424 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
425 {
426     UINT rc;
427     HKEY hkey;
428     WCHAR szSquished[GUID_SIZE];
429     DWORD sz = GUID_SIZE;
430     static const WCHAR szPermKey[] =
431         { '0','0','0','0','0','0','0','0','0','0','0','0',
432           '0','0','0','0','0','0','0','0','0','0','0','0',
433           '0','0','0','0','0','0','0','0',0};
434
435     TRACE("%s %p\n",debugstr_w(szComponent), szBuffer);
436
437     if (NULL == szComponent)
438         return ERROR_INVALID_PARAMETER;
439
440     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
441     if (rc != ERROR_SUCCESS)
442         return ERROR_UNKNOWN_COMPONENT;
443
444     rc = RegEnumValueW(hkey, 0, szSquished, &sz, NULL, NULL, NULL, NULL);
445     if (rc == ERROR_SUCCESS && strcmpW(szSquished,szPermKey)==0)
446     {
447         sz = GUID_SIZE;
448         rc = RegEnumValueW(hkey, 1, szSquished, &sz, NULL, NULL, NULL, NULL);
449     }
450
451     RegCloseKey(hkey);
452
453     if (rc != ERROR_SUCCESS)
454         return ERROR_INSTALL_FAILURE;
455
456     unsquash_guid(szSquished, szBuffer);
457     return ERROR_SUCCESS;
458 }
459
460 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
461                  LPSTR szBuffer, DWORD *pcchValueBuf)
462 {
463     LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
464     UINT r = ERROR_OUTOFMEMORY;
465     DWORD pcchwValueBuf = 0;
466
467     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
468           szBuffer, pcchValueBuf);
469
470     if( szProduct )
471     {
472         szwProduct = strdupAtoW( szProduct );
473         if( !szwProduct )
474             goto end;
475     }
476     
477     if( szAttribute )
478     {
479         szwAttribute = strdupAtoW( szAttribute );
480         if( !szwAttribute )
481             goto end;
482     }
483
484     if( szBuffer )
485     {
486         szwBuffer = msi_alloc( (*pcchValueBuf) * sizeof(WCHAR) );
487         pcchwValueBuf = *pcchValueBuf;
488         if( !szwBuffer )     
489             goto end;
490     }
491
492     r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, 
493                             &pcchwValueBuf );
494
495     if( ERROR_SUCCESS == r )
496     {
497         INT old_len = *pcchValueBuf;
498         *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf,
499                         szBuffer, *pcchValueBuf, NULL, NULL);
500         if (old_len > *pcchValueBuf)
501             szBuffer[*pcchValueBuf]=0;
502     }
503
504 end:
505     msi_free( szwProduct );
506     msi_free( szwAttribute );
507     msi_free( szwBuffer );
508
509     return r;
510 }
511
512 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
513                 LPWSTR szBuffer, DWORD *pcchValueBuf)
514 {
515     MSIHANDLE hProduct;
516     UINT r;
517     static const WCHAR szProductVersion[] =
518         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
519     static const WCHAR szProductLanguage[] =
520         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
521
522     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute),
523           szBuffer, pcchValueBuf);
524
525     if (NULL != szBuffer && NULL == pcchValueBuf)
526         return ERROR_INVALID_PARAMETER;
527     if (NULL == szProduct || NULL == szAttribute)
528         return ERROR_INVALID_PARAMETER;
529     
530     /* check for special properties */
531     if (strcmpW(szAttribute, INSTALLPROPERTY_PACKAGECODEW)==0)
532     {
533         HKEY hkey;
534         WCHAR squished[GUID_SIZE];
535         WCHAR package[200];
536         DWORD sz = sizeof(squished);
537
538         r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
539         if (r != ERROR_SUCCESS)
540             return ERROR_UNKNOWN_PRODUCT;
541
542         r = RegQueryValueExW(hkey, INSTALLPROPERTY_PACKAGECODEW, NULL, NULL, 
543                         (LPBYTE)squished, &sz);
544         if (r != ERROR_SUCCESS)
545         {
546             RegCloseKey(hkey);
547             return ERROR_UNKNOWN_PRODUCT;
548         }
549
550         unsquash_guid(squished, package);
551         *pcchValueBuf = strlenW(package);
552         if (strlenW(package) > *pcchValueBuf)
553         {
554             RegCloseKey(hkey);
555             return ERROR_MORE_DATA;
556         }
557         else
558             strcpyW(szBuffer, package);
559
560         RegCloseKey(hkey);
561         r = ERROR_SUCCESS;
562     }
563     else if (strcmpW(szAttribute, INSTALLPROPERTY_VERSIONSTRINGW)==0)
564     {
565         r = MsiOpenProductW(szProduct, &hProduct);
566         if (ERROR_SUCCESS != r)
567             return r;
568
569         r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf);
570         MsiCloseHandle(hProduct);
571     }
572     else if (strcmpW(szAttribute, INSTALLPROPERTY_ASSIGNMENTTYPEW)==0)
573     {
574         FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n");
575         if (szBuffer)
576         {
577             szBuffer[0] = '1';
578             szBuffer[1] = 0;
579         }
580         if (pcchValueBuf)
581             *pcchValueBuf = 1;
582         r = ERROR_SUCCESS;
583     }
584     else if (strcmpW(szAttribute, INSTALLPROPERTY_LANGUAGEW)==0)
585     {
586         r = MsiOpenProductW(szProduct, &hProduct);
587         if (ERROR_SUCCESS != r)
588             return r;
589
590         r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
591         MsiCloseHandle(hProduct);
592     }
593     else
594     {
595         r = MsiOpenProductW(szProduct, &hProduct);
596         if (ERROR_SUCCESS != r)
597             return r;
598
599         r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
600         MsiCloseHandle(hProduct);
601     }
602
603     return r;
604 }
605
606 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
607 {
608     LPWSTR szwLogFile = NULL;
609     UINT r;
610
611     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes);
612
613     if( szLogFile )
614     {
615         szwLogFile = strdupAtoW( szLogFile );
616         if( !szwLogFile )
617             return ERROR_OUTOFMEMORY;
618     }
619     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
620     msi_free( szwLogFile );
621     return r;
622 }
623
624 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
625 {
626     HANDLE file = INVALID_HANDLE_VALUE;
627
628     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes);
629
630     lstrcpyW(gszLogFile,szLogFile);
631     if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
632         DeleteFileW(szLogFile);
633     file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
634                            FILE_ATTRIBUTE_NORMAL, NULL);
635     if (file != INVALID_HANDLE_VALUE)
636         CloseHandle(file);
637     else
638         ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
639
640     return ERROR_SUCCESS;
641 }
642
643 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
644 {
645     LPWSTR szwProduct = NULL;
646     INSTALLSTATE r;
647
648     if( szProduct )
649     {
650          szwProduct = strdupAtoW( szProduct );
651          if( !szwProduct )
652              return ERROR_OUTOFMEMORY;
653     }
654     r = MsiQueryProductStateW( szwProduct );
655     msi_free( szwProduct );
656     return r;
657 }
658
659 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
660 {
661     UINT rc;
662     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
663     HKEY hkey = 0;
664     static const WCHAR szWindowsInstaller[] = {
665          'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 };
666     DWORD sz;
667
668     TRACE("%s\n", debugstr_w(szProduct));
669
670     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
671     if (rc != ERROR_SUCCESS)
672         goto end;
673
674     RegCloseKey(hkey);
675
676     rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE);
677     if (rc != ERROR_SUCCESS)
678         goto end;
679
680     sz = sizeof(rrc);
681     rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz);
682     if (rc != ERROR_SUCCESS)
683         goto end;
684
685     switch (rrc)
686     {
687     case 1:
688         /* default */
689         rrc = INSTALLSTATE_DEFAULT;
690         break;
691     default:
692         FIXME("Unknown install state read from registry (%i)\n",rrc);
693         rrc = INSTALLSTATE_UNKNOWN;
694         break;
695     }
696 end:
697     RegCloseKey(hkey);
698     return rrc;
699 }
700
701 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
702 {
703     INSTALLUILEVEL old = gUILevel;
704     HWND oldwnd = gUIhwnd;
705
706     TRACE("%08x %p\n", dwUILevel, phWnd);
707
708     gUILevel = dwUILevel;
709     if (phWnd)
710     {
711         gUIhwnd = *phWnd;
712         *phWnd = oldwnd;
713     }
714     return old;
715 }
716
717 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
718                                   DWORD dwMessageFilter, LPVOID pvContext)
719 {
720     INSTALLUI_HANDLERA prev = gUIHandlerA;
721
722     TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext);
723     gUIHandlerA = puiHandler;
724     gUIFilter = dwMessageFilter;
725     gUIContext = pvContext;
726
727     return prev;
728 }
729
730 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
731                                   DWORD dwMessageFilter, LPVOID pvContext)
732 {
733     INSTALLUI_HANDLERW prev = gUIHandlerW;
734
735     TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext);
736     gUIHandlerW = puiHandler;
737     gUIFilter = dwMessageFilter;
738     gUIContext = pvContext;
739
740     return prev;
741 }
742
743 /******************************************************************
744  *  MsiLoadStringW            [MSI.@]
745  *
746  * Loads a string from MSI's string resources.
747  *
748  * PARAMS
749  *
750  *   handle        [I]  only -1 is handled currently
751  *   id            [I]  id of the string to be loaded
752  *   lpBuffer      [O]  buffer for the string to be written to
753  *   nBufferMax    [I]  maximum size of the buffer in characters
754  *   lang          [I]  the preferred language for the string
755  *
756  * RETURNS
757  *
758  *   If successful, this function returns the language id of the string loaded
759  *   If the function fails, the function returns zero.
760  *
761  * NOTES
762  *
763  *   The type of the first parameter is unknown.  LoadString's prototype
764  *  suggests that it might be a module handle.  I have made it an MSI handle
765  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
766  *  handle.  Maybe strings can be stored in an MSI database somehow.
767  */
768 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
769                 int nBufferMax, LANGID lang )
770 {
771     HRSRC hres;
772     HGLOBAL hResData;
773     LPWSTR p;
774     DWORD i, len;
775
776     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
777
778     if( handle != -1 )
779         FIXME("don't know how to deal with handle = %08lx\n", handle);
780
781     if( !lang )
782         lang = GetUserDefaultLangID();
783
784     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
785                             (LPWSTR)1, lang );
786     if( !hres )
787         return 0;
788     hResData = LoadResource( msi_hInstance, hres );
789     if( !hResData )
790         return 0;
791     p = LockResource( hResData );
792     if( !p )
793         return 0;
794
795     for (i = 0; i < (id&0xf); i++)
796         p += *p + 1;
797     len = *p;
798
799     if( nBufferMax <= len )
800         return 0;
801
802     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
803     lpBuffer[ len ] = 0;
804
805     TRACE("found -> %s\n", debugstr_w(lpBuffer));
806
807     return lang;
808 }
809
810 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
811                 int nBufferMax, LANGID lang )
812 {
813     LPWSTR bufW;
814     LANGID r;
815     DWORD len;
816
817     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
818     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
819     if( r )
820     {
821         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
822         if( len <= nBufferMax )
823             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
824                                  lpBuffer, nBufferMax, NULL, NULL );
825         else
826             r = 0;
827     }
828     msi_free(bufW);
829     return r;
830 }
831
832 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
833                 DWORD *pcchBuf)
834 {
835     FIXME("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
836     return INSTALLSTATE_UNKNOWN;
837 }
838
839 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
840                 DWORD *pcchBuf)
841 {
842     FIXME("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
843     return INSTALLSTATE_UNKNOWN;
844 }
845
846 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
847                 WORD wLanguageId, DWORD f)
848 {
849     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),
850           uType,wLanguageId,f);
851     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
852 }
853
854 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
855                 WORD wLanguageId, DWORD f)
856 {
857     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),
858           uType,wLanguageId,f);
859     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
860 }
861
862 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
863                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
864                 DWORD* pcchPathBuf )
865 {
866     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName),
867           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
868           pcchPathBuf);
869     return ERROR_CALL_NOT_IMPLEMENTED;
870 }
871
872 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
873                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
874                 DWORD* pcchPathBuf )
875 {
876     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName),
877           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
878           pcchPathBuf);
879     return ERROR_CALL_NOT_IMPLEMENTED;
880 }
881
882 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
883                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
884 {
885     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
886     return ERROR_CALL_NOT_IMPLEMENTED;
887 }
888
889 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
890                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
891 {
892     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
893     return ERROR_CALL_NOT_IMPLEMENTED;
894 }
895
896 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
897                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
898                 DWORD* pcbHashData)
899 {
900     FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
901           ppcCertContext, pbHashData, pcbHashData);
902     return ERROR_CALL_NOT_IMPLEMENTED;
903 }
904
905 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
906                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
907                 DWORD* pcbHashData)
908 {
909     FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
910           ppcCertContext, pbHashData, pcbHashData);
911     return ERROR_CALL_NOT_IMPLEMENTED;
912 }
913
914 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
915                                     LPSTR szValue, DWORD *pccbValue )
916 {
917     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
918     return ERROR_CALL_NOT_IMPLEMENTED;
919 }
920
921 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
922                                     LPWSTR szValue, DWORD *pccbValue )
923 {
924     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
925     return ERROR_CALL_NOT_IMPLEMENTED;
926 }
927
928 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
929 {
930     UINT r;
931     LPWSTR szPack = NULL;
932
933     TRACE("%s\n", debugstr_a(szPackage) );
934
935     if( szPackage )
936     {
937         szPack = strdupAtoW( szPackage );
938         if( !szPack )
939             return ERROR_OUTOFMEMORY;
940     }
941
942     r = MsiVerifyPackageW( szPack );
943
944     msi_free( szPack );
945
946     return r;
947 }
948
949 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
950 {
951     MSIHANDLE handle;
952     UINT r;
953
954     TRACE("%s\n", debugstr_w(szPackage) );
955
956     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
957     MsiCloseHandle( handle );
958
959     return r;
960 }
961
962 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
963                                          LPSTR lpPathBuf, DWORD* pcchBuf)
964 {
965     LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL;
966     INSTALLSTATE rc;
967     UINT incoming_len;
968
969     if( szProduct )
970     {
971         szwProduct = strdupAtoW( szProduct );
972         if( !szwProduct)
973             return ERROR_OUTOFMEMORY;
974     }
975
976     if( szComponent )
977     {
978         szwComponent = strdupAtoW( szComponent );
979         if( !szwComponent )
980         {
981             msi_free( szwProduct);
982             return ERROR_OUTOFMEMORY;
983         }
984     }
985
986     if( pcchBuf && *pcchBuf > 0 )
987     {
988         lpwPathBuf = msi_alloc( *pcchBuf * sizeof(WCHAR));
989         incoming_len = *pcchBuf;
990     }
991     else
992     {
993         lpwPathBuf = NULL;
994         incoming_len = 0;
995     }
996
997     rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
998
999     msi_free( szwProduct);
1000     msi_free( szwComponent);
1001     if (lpwPathBuf)
1002     {
1003         if (rc != INSTALLSTATE_UNKNOWN)
1004             WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len,
1005                             lpPathBuf, incoming_len, NULL, NULL);
1006         msi_free( lpwPathBuf);
1007     }
1008
1009     return rc;
1010 }
1011
1012 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1013                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1014 {
1015     WCHAR squished_pc[GUID_SIZE];
1016     UINT rc;
1017     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
1018     HKEY hkey = 0;
1019     LPWSTR path = NULL;
1020     DWORD sz, type;
1021
1022     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1023            debugstr_w(szComponent), lpPathBuf, pcchBuf);
1024
1025     if( !szComponent )
1026         return INSTALLSTATE_INVALIDARG;
1027     if( lpPathBuf && !pcchBuf )
1028         return INSTALLSTATE_INVALIDARG;
1029
1030     squash_guid(szProduct,squished_pc);
1031
1032     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1033     if( rc != ERROR_SUCCESS )
1034         goto end;
1035
1036     RegCloseKey(hkey);
1037
1038     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1039     if( rc != ERROR_SUCCESS )
1040         goto end;
1041
1042     sz = 0;
1043     type = 0;
1044     rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz );
1045     if( rc != ERROR_SUCCESS )
1046         goto end;
1047     if( type != REG_SZ )
1048         goto end;
1049
1050     sz += sizeof(WCHAR);
1051     path = msi_alloc( sz );
1052     if( !path )
1053         goto end;
1054
1055     rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz );
1056     if( rc != ERROR_SUCCESS )
1057         goto end;
1058
1059     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1060            debugstr_w(szProduct), debugstr_w(path));
1061
1062     if (path[0]=='0')
1063     {
1064         FIXME("Registry entry.. check entry\n");
1065         rrc = INSTALLSTATE_LOCAL;
1066     }
1067     else
1068     {
1069         /* PROBABLY a file */
1070         if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES )
1071             rrc = INSTALLSTATE_LOCAL;
1072         else
1073             rrc = INSTALLSTATE_ABSENT;
1074     }
1075
1076     if( pcchBuf )
1077     {
1078         sz = sz / sizeof(WCHAR);
1079         if( *pcchBuf >= sz )
1080             lstrcpyW( lpPathBuf, path );
1081         *pcchBuf = sz;
1082     }
1083
1084 end:
1085     msi_free(path );
1086     RegCloseKey(hkey);
1087     return rrc;
1088 }
1089
1090 /******************************************************************
1091  * MsiQueryFeatureStateA      [MSI.@]
1092  */
1093 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1094 {
1095     LPWSTR szwProduct = NULL, szwFeature= NULL;
1096     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1097
1098     szwProduct = strdupAtoW( szProduct );
1099     if ( szProduct && !szwProduct )
1100         goto end;
1101
1102     szwFeature = strdupAtoW( szFeature );
1103     if ( szFeature && !szwFeature )
1104         goto end;
1105
1106     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1107
1108 end:
1109     msi_free( szwProduct);
1110     msi_free( szwFeature);
1111
1112     return rc;
1113 }
1114
1115 /******************************************************************
1116  * MsiQueryFeatureStateW      [MSI.@]
1117  *
1118  * This does not verify that the Feature is functional. So i am only going to
1119  * check the existence of the key in the registry. This should tell me if it is
1120  * installed.
1121  */
1122 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1123 {
1124     WCHAR squishProduct[GUID_SIZE];
1125     UINT rc;
1126     DWORD sz = 0;
1127     HKEY hkey;
1128
1129     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1130
1131     if (!szProduct || !szFeature)
1132         return INSTALLSTATE_INVALIDARG;
1133
1134     if (!squash_guid( szProduct, squishProduct ))
1135         return INSTALLSTATE_INVALIDARG;
1136
1137     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
1138     if (rc != ERROR_SUCCESS)
1139         return INSTALLSTATE_UNKNOWN;
1140
1141     rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz);
1142     RegCloseKey(hkey);
1143
1144     if (rc == ERROR_SUCCESS)
1145         return INSTALLSTATE_LOCAL;
1146
1147     return INSTALLSTATE_UNKNOWN;
1148 }
1149
1150 /******************************************************************
1151  * MsiGetFileVersionA         [MSI.@]
1152  */
1153 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1154                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1155 {
1156     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1157     UINT ret = ERROR_OUTOFMEMORY;
1158
1159     if( szFilePath )
1160     {
1161         szwFilePath = strdupAtoW( szFilePath );
1162         if( !szwFilePath )
1163             goto end;
1164     }
1165
1166     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1167     {
1168         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1169         if( !lpwVersionBuff )
1170             goto end;
1171     }
1172
1173     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1174     {
1175         lpwLangBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1176         if( !lpwLangBuff )
1177             goto end;
1178     }
1179
1180     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1181                              lpwLangBuff, pcchLangBuf);
1182
1183     if( lpwVersionBuff )
1184         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1185                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1186     if( lpwLangBuff )
1187         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1188                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1189
1190 end:
1191     msi_free(szwFilePath);
1192     msi_free(lpwVersionBuff);
1193     msi_free(lpwLangBuff);
1194
1195     return ret;
1196 }
1197
1198 /******************************************************************
1199  * MsiGetFileVersionW         [MSI.@]
1200  */
1201 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1202                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1203 {
1204     static WCHAR szVersionResource[] = {'\\',0};
1205     static const WCHAR szVersionFormat[] = {
1206         '%','d','.','%','d','.','%','d','.','%','d',0};
1207     static const WCHAR szLangFormat[] = {'%','d',0};
1208     UINT ret = 0;
1209     DWORD dwVerLen;
1210     LPVOID lpVer = NULL;
1211     VS_FIXEDFILEINFO *ffi;
1212     UINT puLen;
1213     WCHAR tmp[32];
1214
1215     TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath),
1216           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1217           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1218
1219     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1220     if( !dwVerLen )
1221         return GetLastError();
1222
1223     lpVer = msi_alloc(dwVerLen);
1224     if( !lpVer )
1225     {
1226         ret = ERROR_OUTOFMEMORY;
1227         goto end;
1228     }
1229
1230     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1231     {
1232         ret = GetLastError();
1233         goto end;
1234     }
1235     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1236     {
1237         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1238             (puLen > 0) )
1239         {
1240             wsprintfW(tmp, szVersionFormat,
1241                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1242                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1243             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1244             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1245         }
1246         else
1247         {
1248             *lpVersionBuf = 0;
1249             *pcchVersionBuf = 0;
1250         }
1251     }
1252
1253     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1254     {
1255         DWORD lang = GetUserDefaultLangID();
1256
1257         FIXME("Retrieve language from file\n");
1258         wsprintfW(tmp, szLangFormat, lang);
1259         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1260         *pcchLangBuf = lstrlenW(lpLangBuf);
1261     }
1262
1263 end:
1264     msi_free(lpVer);
1265     return ret;
1266 }
1267
1268
1269 /******************************************************************
1270  *      DllMain
1271  */
1272 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1273 {
1274     switch(fdwReason)
1275     {
1276     case DLL_PROCESS_ATTACH:
1277         msi_hInstance = hinstDLL;
1278         DisableThreadLibraryCalls(hinstDLL);
1279         msi_dialog_register_class();
1280         break;
1281     case DLL_PROCESS_DETACH:
1282         msi_dialog_unregister_class();
1283         /* FIXME: Cleanup */
1284         break;
1285     }
1286     return TRUE;
1287 }
1288
1289 typedef struct tagIClassFactoryImpl
1290 {
1291     const IClassFactoryVtbl *lpVtbl;
1292 } IClassFactoryImpl;
1293
1294 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
1295                 REFIID riid,LPVOID *ppobj)
1296 {
1297     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1298     FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
1299     return E_NOINTERFACE;
1300 }
1301
1302 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
1303 {
1304     LockModule();
1305     return 2;
1306 }
1307
1308 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
1309 {
1310     UnlockModule();
1311     return 1;
1312 }
1313
1314 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
1315     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
1316 {
1317     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1318
1319     FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
1320     return E_FAIL;
1321 }
1322
1323 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1324 {
1325     TRACE("(%p)->(%d)\n", iface, dolock);
1326
1327     if(dolock)
1328         LockModule();
1329     else
1330         UnlockModule();
1331
1332     return S_OK;
1333 }
1334
1335 static const IClassFactoryVtbl MsiCF_Vtbl =
1336 {
1337     MsiCF_QueryInterface,
1338     MsiCF_AddRef,
1339     MsiCF_Release,
1340     MsiCF_CreateInstance,
1341     MsiCF_LockServer
1342 };
1343
1344 static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
1345
1346 /******************************************************************
1347  * DllGetClassObject          [MSI.@]
1348  */
1349 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1350 {
1351     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1352
1353     if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
1354         IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
1355         IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
1356         IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
1357         IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
1358     {
1359         *ppv = (LPVOID) &Msi_CF;
1360         return S_OK;
1361     }
1362     return CLASS_E_CLASSNOTAVAILABLE;
1363 }
1364
1365 /******************************************************************
1366  * DllGetVersion              [MSI.@]
1367  */
1368 HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
1369 {
1370     TRACE("%p\n",pdvi);
1371
1372     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
1373         return E_INVALIDARG;
1374
1375     pdvi->dwMajorVersion = MSI_MAJORVERSION;
1376     pdvi->dwMinorVersion = MSI_MINORVERSION;
1377     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
1378     pdvi->dwPlatformID = 1;
1379
1380     return S_OK;
1381 }
1382
1383 /******************************************************************
1384  * DllCanUnloadNow            [MSI.@]
1385  */
1386 HRESULT WINAPI DllCanUnloadNow(void)
1387 {
1388     return dll_count == 0 ? S_OK : S_FALSE;
1389 }
1390
1391 /***********************************************************************
1392  * MsiGetFeatureUsageW           [MSI.@]
1393  */
1394 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1395                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1396 {
1397     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1398           pdwUseCount, pwDateUsed);
1399     return ERROR_CALL_NOT_IMPLEMENTED;
1400 }
1401
1402 /***********************************************************************
1403  * MsiGetFeatureUsageA           [MSI.@]
1404  */
1405 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1406                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1407 {
1408     LPWSTR prod = NULL, feat = NULL;
1409     UINT ret = ERROR_OUTOFMEMORY;
1410
1411     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1412           pdwUseCount, pwDateUsed);
1413
1414     prod = strdupAtoW( szProduct );
1415     if (szProduct && !prod)
1416         goto end;
1417
1418     feat = strdupAtoW( szFeature );
1419     if (szFeature && !feat)
1420         goto end;
1421
1422     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1423
1424 end:
1425     msi_free( prod );
1426     msi_free( feat );
1427
1428     return ret;
1429 }
1430
1431 /***********************************************************************
1432  * MsiUseFeatureExW           [MSI.@]
1433  */
1434 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1435                                       DWORD dwInstallMode, DWORD dwReserved )
1436 {
1437     INSTALLSTATE state;
1438
1439     TRACE("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1440           dwInstallMode, dwReserved);
1441
1442     state = MsiQueryFeatureStateW( szProduct, szFeature );
1443
1444     if (dwReserved)
1445         return INSTALLSTATE_INVALIDARG;
1446
1447     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1448     {
1449         FIXME("mark product %s feature %s as used\n",
1450               debugstr_w(szProduct), debugstr_w(szFeature) );
1451     }
1452
1453     return state;
1454 }
1455
1456 /***********************************************************************
1457  * MsiUseFeatureExA           [MSI.@]
1458  */
1459 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1460                                       DWORD dwInstallMode, DWORD dwReserved )
1461 {
1462     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1463     LPWSTR prod = NULL, feat = NULL;
1464
1465     TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1466           dwInstallMode, dwReserved);
1467
1468     prod = strdupAtoW( szProduct );
1469     if (szProduct && !prod)
1470         goto end;
1471
1472     feat = strdupAtoW( szFeature );
1473     if (szFeature && !feat)
1474         goto end;
1475
1476     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1477
1478 end:
1479     msi_free( prod );
1480     msi_free( feat );
1481
1482     return ret;
1483 }
1484
1485 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1486 {
1487     FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1488
1489     return INSTALLSTATE_LOCAL;
1490 }
1491
1492 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1493 {
1494     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1495     LPWSTR prod = NULL, feat = NULL;
1496
1497     TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) );
1498
1499     prod = strdupAtoW( szProduct );
1500     if (szProduct && !prod)
1501         goto end;
1502
1503     feat = strdupAtoW( szFeature );
1504     if (szFeature && !feat)
1505         goto end;
1506
1507     ret = MsiUseFeatureW( prod, feat );
1508
1509 end:
1510     msi_free( prod );
1511     msi_free( feat );
1512
1513     return ret;
1514 }
1515
1516 /***********************************************************************
1517  * MsiProvideQualifiedComponentExW [MSI.@]
1518  */
1519 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1520                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1521                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1522                 DWORD* pcchPathBuf)
1523 {
1524     HKEY hkey;
1525     UINT rc;
1526     LPWSTR info;
1527     DWORD sz;
1528     WCHAR product[MAX_FEATURE_CHARS+1];
1529     WCHAR component[MAX_FEATURE_CHARS+1];
1530     WCHAR feature[MAX_FEATURE_CHARS+1];
1531
1532     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
1533           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1534           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1535    
1536     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1537     if (rc != ERROR_SUCCESS)
1538         return ERROR_INDEX_ABSENT;
1539
1540     sz = 0;
1541     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
1542     if (sz <= 0)
1543     {
1544         RegCloseKey(hkey);
1545         return ERROR_INDEX_ABSENT;
1546     }
1547
1548     info = msi_alloc(sz);
1549     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
1550     if (rc != ERROR_SUCCESS)
1551     {
1552         RegCloseKey(hkey);
1553         msi_free(info);
1554         return ERROR_INDEX_ABSENT;
1555     }
1556
1557     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1558     
1559     if (!szProduct)
1560         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
1561     else
1562         rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
1563    
1564     RegCloseKey(hkey);
1565     msi_free(info);
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, init;
1827
1828     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1829           szProductCode, szFeatureId, szComponentCode );
1830
1831     init = CoInitialize(NULL);
1832
1833     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1834                           &IID_IPersistFile, (LPVOID*) &pf );
1835     if( SUCCEEDED( r ) )
1836     {
1837         r = IPersistFile_Load( pf, szShortcutTarget,
1838                                STGM_READ | STGM_SHARE_DENY_WRITE );
1839         if( SUCCEEDED( r ) )
1840         {
1841             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1842                                              (LPVOID*) &dl );
1843             if( SUCCEEDED( r ) )
1844             {
1845                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1846                                                   (LPVOID) &darwin );
1847                 IShellLinkDataList_Release( dl );
1848             }
1849         }
1850         IPersistFile_Release( pf );
1851     }
1852
1853     if (SUCCEEDED(init))
1854         CoUninitialize();
1855
1856     TRACE("darwin = %p\n", darwin);
1857
1858     if (darwin)
1859     {
1860         DWORD sz;
1861         UINT ret;
1862
1863         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1864                   szProductCode, szFeatureId, szComponentCode, &sz );
1865         LocalFree( darwin );
1866         return ret;
1867     }
1868
1869     return ERROR_FUNCTION_FAILED;
1870 }
1871
1872 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1873                                   DWORD dwReinstallMode )
1874 {
1875     MSIPACKAGE* package = NULL;
1876     UINT r;
1877     DWORD sz;
1878     WCHAR sourcepath[MAX_PATH];
1879     WCHAR filename[MAX_PATH];
1880     static const WCHAR szInstalled[] = {
1881         ' ','L','O','G','V','E','R','B','O','S','E','=','1',' ','I','n','s','t','a','l','l','e','d','=','1',0};
1882     static const WCHAR fmt[] = {'R','E','I','N','S','T','A','L','L','=','%','s',0};
1883     static const WCHAR REINSTALLMODE[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
1884     WCHAR reinstallmode[11];
1885     LPWSTR ptr;
1886     LPWSTR commandline;
1887
1888     FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1889                            dwReinstallMode);
1890
1891     memset(reinstallmode,0,sizeof(reinstallmode));
1892     ptr = reinstallmode;
1893
1894     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
1895         { *ptr = 'p'; ptr++; }
1896     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
1897         { *ptr = 'o'; ptr++; }
1898     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
1899         { *ptr = 'w'; ptr++; }
1900     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
1901         { *ptr = 'd'; ptr++; }
1902     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
1903         { *ptr = 'c'; ptr++; }
1904     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
1905         { *ptr = 'a'; ptr++; }
1906     if (dwReinstallMode & REINSTALLMODE_USERDATA)
1907         { *ptr = 'u'; ptr++; }
1908     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
1909         { *ptr = 'm'; ptr++; }
1910     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
1911         { *ptr = 's'; ptr++; }
1912     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1913         { *ptr = 'v'; ptr++; }
1914     
1915     sz = sizeof(sourcepath);
1916     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1917             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
1918             &sz);
1919
1920     sz = sizeof(filename);
1921     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1922             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1923
1924     strcatW(sourcepath,filename);
1925
1926     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1927         r = MSI_OpenPackageW( sourcepath, &package );
1928     else
1929         r = MSI_OpenProductW( szProduct, &package );
1930
1931     if (r != ERROR_SUCCESS)
1932         return r;
1933
1934     MSI_SetPropertyW(package,REINSTALLMODE,reinstallmode);
1935     
1936     sz = lstrlenW(szInstalled);
1937     sz += lstrlenW(fmt);
1938     sz += lstrlenW(szFeature);
1939
1940     commandline = msi_alloc(sz * sizeof(WCHAR));
1941
1942     sprintfW(commandline,fmt,szFeature);
1943     lstrcatW(commandline,szInstalled);
1944
1945     r = MSI_InstallPackage( package, sourcepath, commandline );
1946
1947     msiobj_release( &package->hdr );
1948
1949     msi_free(commandline);
1950
1951     return r;
1952 }
1953
1954 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1955                                   DWORD dwReinstallMode )
1956 {
1957     LPWSTR wszProduct;
1958     LPWSTR wszFeature;
1959     UINT rc;
1960
1961     TRACE("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1962                            dwReinstallMode);
1963
1964     wszProduct = strdupAtoW(szProduct);
1965     wszFeature = strdupAtoW(szFeature);
1966
1967     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
1968     
1969     msi_free(wszProduct);
1970     msi_free(wszFeature);
1971     return rc;
1972 }
1973
1974 /***********************************************************************
1975  * MsiEnumPatchesA            [MSI.@]
1976  */
1977 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, 
1978         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1979 {
1980     FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
1981           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1982     return ERROR_NO_MORE_ITEMS;
1983 }
1984
1985 /***********************************************************************
1986  * MsiEnumPatchesW            [MSI.@]
1987  */
1988 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, 
1989         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1990 {
1991     FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct),
1992           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1993     return ERROR_NO_MORE_ITEMS;
1994 }
1995
1996 /***********************************************************************
1997  * MsiGetFileHashW            [MSI.@]
1998  */
1999 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2000                              PMSIFILEHASHINFO pHash )
2001 {
2002     FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2003     return ERROR_CALL_NOT_IMPLEMENTED;
2004 }
2005
2006 /***********************************************************************
2007  * MsiGetFileHashA            [MSI.@]
2008  */
2009 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2010                              PMSIFILEHASHINFO pHash )
2011 {
2012     FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2013     return ERROR_CALL_NOT_IMPLEMENTED;
2014 }
2015
2016 /***********************************************************************
2017  * MsiAdvertiseScriptW        [MSI.@]
2018  */
2019 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2020                                  PHKEY phRegData, BOOL fRemoveItems )
2021 {
2022     FIXME("%s %08lx %p %d\n",
2023           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2024     return ERROR_CALL_NOT_IMPLEMENTED;
2025 }
2026
2027 /***********************************************************************
2028  * MsiAdvertiseScriptA        [MSI.@]
2029  */
2030 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2031                                  PHKEY phRegData, BOOL fRemoveItems )
2032 {
2033     FIXME("%s %08lx %p %d\n",
2034           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2035     return ERROR_CALL_NOT_IMPLEMENTED;
2036 }