oleaut32: Support VT_SAFEARRAY in the typelib marshaler.
[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     if (!szProduct)
671         return INSTALLSTATE_INVALIDARG;
672
673     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
674     if (rc != ERROR_SUCCESS)
675         goto end;
676
677     RegCloseKey(hkey);
678
679     rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE);
680     if (rc != ERROR_SUCCESS)
681         goto end;
682
683     sz = sizeof(rrc);
684     rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz);
685     if (rc != ERROR_SUCCESS)
686         goto end;
687
688     switch (rrc)
689     {
690     case 1:
691         /* default */
692         rrc = INSTALLSTATE_DEFAULT;
693         break;
694     default:
695         FIXME("Unknown install state read from registry (%i)\n",rrc);
696         rrc = INSTALLSTATE_UNKNOWN;
697         break;
698     }
699 end:
700     RegCloseKey(hkey);
701     return rrc;
702 }
703
704 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
705 {
706     INSTALLUILEVEL old = gUILevel;
707     HWND oldwnd = gUIhwnd;
708
709     TRACE("%08x %p\n", dwUILevel, phWnd);
710
711     gUILevel = dwUILevel;
712     if (phWnd)
713     {
714         gUIhwnd = *phWnd;
715         *phWnd = oldwnd;
716     }
717     return old;
718 }
719
720 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
721                                   DWORD dwMessageFilter, LPVOID pvContext)
722 {
723     INSTALLUI_HANDLERA prev = gUIHandlerA;
724
725     TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext);
726     gUIHandlerA = puiHandler;
727     gUIFilter = dwMessageFilter;
728     gUIContext = pvContext;
729
730     return prev;
731 }
732
733 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
734                                   DWORD dwMessageFilter, LPVOID pvContext)
735 {
736     INSTALLUI_HANDLERW prev = gUIHandlerW;
737
738     TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext);
739     gUIHandlerW = puiHandler;
740     gUIFilter = dwMessageFilter;
741     gUIContext = pvContext;
742
743     return prev;
744 }
745
746 /******************************************************************
747  *  MsiLoadStringW            [MSI.@]
748  *
749  * Loads a string from MSI's string resources.
750  *
751  * PARAMS
752  *
753  *   handle        [I]  only -1 is handled currently
754  *   id            [I]  id of the string to be loaded
755  *   lpBuffer      [O]  buffer for the string to be written to
756  *   nBufferMax    [I]  maximum size of the buffer in characters
757  *   lang          [I]  the preferred language for the string
758  *
759  * RETURNS
760  *
761  *   If successful, this function returns the language id of the string loaded
762  *   If the function fails, the function returns zero.
763  *
764  * NOTES
765  *
766  *   The type of the first parameter is unknown.  LoadString's prototype
767  *  suggests that it might be a module handle.  I have made it an MSI handle
768  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
769  *  handle.  Maybe strings can be stored in an MSI database somehow.
770  */
771 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
772                 int nBufferMax, LANGID lang )
773 {
774     HRSRC hres;
775     HGLOBAL hResData;
776     LPWSTR p;
777     DWORD i, len;
778
779     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
780
781     if( handle != -1 )
782         FIXME("don't know how to deal with handle = %08lx\n", handle);
783
784     if( !lang )
785         lang = GetUserDefaultLangID();
786
787     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
788                             (LPWSTR)1, lang );
789     if( !hres )
790         return 0;
791     hResData = LoadResource( msi_hInstance, hres );
792     if( !hResData )
793         return 0;
794     p = LockResource( hResData );
795     if( !p )
796         return 0;
797
798     for (i = 0; i < (id&0xf); i++)
799         p += *p + 1;
800     len = *p;
801
802     if( nBufferMax <= len )
803         return 0;
804
805     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
806     lpBuffer[ len ] = 0;
807
808     TRACE("found -> %s\n", debugstr_w(lpBuffer));
809
810     return lang;
811 }
812
813 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
814                 int nBufferMax, LANGID lang )
815 {
816     LPWSTR bufW;
817     LANGID r;
818     DWORD len;
819
820     bufW = msi_alloc(nBufferMax*sizeof(WCHAR));
821     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
822     if( r )
823     {
824         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
825         if( len <= nBufferMax )
826             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
827                                  lpBuffer, nBufferMax, NULL, NULL );
828         else
829             r = 0;
830     }
831     msi_free(bufW);
832     return r;
833 }
834
835 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
836                 DWORD *pcchBuf)
837 {
838     FIXME("%s %p %p\n", debugstr_a(szComponent), lpPathBuf, pcchBuf);
839     return INSTALLSTATE_UNKNOWN;
840 }
841
842 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
843                 DWORD *pcchBuf)
844 {
845     FIXME("%s %p %p\n", debugstr_w(szComponent), lpPathBuf, pcchBuf);
846     return INSTALLSTATE_UNKNOWN;
847 }
848
849 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
850                 WORD wLanguageId, DWORD f)
851 {
852     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),
853           uType,wLanguageId,f);
854     return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
855 }
856
857 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
858                 WORD wLanguageId, DWORD f)
859 {
860     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),
861           uType,wLanguageId,f);
862     return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
863 }
864
865 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
866                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
867                 DWORD* pcchPathBuf )
868 {
869     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName),
870           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
871           pcchPathBuf);
872     return ERROR_CALL_NOT_IMPLEMENTED;
873 }
874
875 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
876                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
877                 DWORD* pcchPathBuf )
878 {
879     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName),
880           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
881           pcchPathBuf);
882     return ERROR_CALL_NOT_IMPLEMENTED;
883 }
884
885 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
886                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
887 {
888     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
889     return ERROR_CALL_NOT_IMPLEMENTED;
890 }
891
892 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
893                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
894 {
895     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
896     return ERROR_CALL_NOT_IMPLEMENTED;
897 }
898
899 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
900                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
901                 DWORD* pcbHashData)
902 {
903     FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
904           ppcCertContext, pbHashData, pcbHashData);
905     return ERROR_CALL_NOT_IMPLEMENTED;
906 }
907
908 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
909                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
910                 DWORD* pcbHashData)
911 {
912     FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
913           ppcCertContext, pbHashData, pcbHashData);
914     return ERROR_CALL_NOT_IMPLEMENTED;
915 }
916
917 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
918                                     LPSTR szValue, DWORD *pccbValue )
919 {
920     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
921     return ERROR_CALL_NOT_IMPLEMENTED;
922 }
923
924 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
925                                     LPWSTR szValue, DWORD *pccbValue )
926 {
927     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
928     return ERROR_CALL_NOT_IMPLEMENTED;
929 }
930
931 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
932 {
933     UINT r;
934     LPWSTR szPack = NULL;
935
936     TRACE("%s\n", debugstr_a(szPackage) );
937
938     if( szPackage )
939     {
940         szPack = strdupAtoW( szPackage );
941         if( !szPack )
942             return ERROR_OUTOFMEMORY;
943     }
944
945     r = MsiVerifyPackageW( szPack );
946
947     msi_free( szPack );
948
949     return r;
950 }
951
952 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
953 {
954     MSIHANDLE handle;
955     UINT r;
956
957     TRACE("%s\n", debugstr_w(szPackage) );
958
959     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
960     MsiCloseHandle( handle );
961
962     return r;
963 }
964
965 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
966                                          LPSTR lpPathBuf, DWORD* pcchBuf)
967 {
968     LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL;
969     INSTALLSTATE rc;
970     UINT incoming_len;
971
972     if( szProduct )
973     {
974         szwProduct = strdupAtoW( szProduct );
975         if( !szwProduct)
976             return ERROR_OUTOFMEMORY;
977     }
978
979     if( szComponent )
980     {
981         szwComponent = strdupAtoW( szComponent );
982         if( !szwComponent )
983         {
984             msi_free( szwProduct);
985             return ERROR_OUTOFMEMORY;
986         }
987     }
988
989     if( pcchBuf && *pcchBuf > 0 )
990     {
991         lpwPathBuf = msi_alloc( *pcchBuf * sizeof(WCHAR));
992         incoming_len = *pcchBuf;
993     }
994     else
995     {
996         lpwPathBuf = NULL;
997         incoming_len = 0;
998     }
999
1000     rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
1001
1002     msi_free( szwProduct);
1003     msi_free( szwComponent);
1004     if (lpwPathBuf)
1005     {
1006         if (rc != INSTALLSTATE_UNKNOWN)
1007             WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len,
1008                             lpPathBuf, incoming_len, NULL, NULL);
1009         msi_free( lpwPathBuf);
1010     }
1011
1012     return rc;
1013 }
1014
1015 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1016                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1017 {
1018     WCHAR squished_pc[GUID_SIZE];
1019     UINT rc;
1020     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
1021     HKEY hkey = 0;
1022     LPWSTR path = NULL;
1023     DWORD sz, type;
1024
1025     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1026            debugstr_w(szComponent), lpPathBuf, pcchBuf);
1027
1028     if( !szComponent )
1029         return INSTALLSTATE_INVALIDARG;
1030     if( lpPathBuf && !pcchBuf )
1031         return INSTALLSTATE_INVALIDARG;
1032
1033     squash_guid(szProduct,squished_pc);
1034
1035     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1036     if( rc != ERROR_SUCCESS )
1037         goto end;
1038
1039     RegCloseKey(hkey);
1040
1041     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1042     if( rc != ERROR_SUCCESS )
1043         goto end;
1044
1045     sz = 0;
1046     type = 0;
1047     rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz );
1048     if( rc != ERROR_SUCCESS )
1049         goto end;
1050     if( type != REG_SZ )
1051         goto end;
1052
1053     sz += sizeof(WCHAR);
1054     path = msi_alloc( sz );
1055     if( !path )
1056         goto end;
1057
1058     rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz );
1059     if( rc != ERROR_SUCCESS )
1060         goto end;
1061
1062     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1063            debugstr_w(szProduct), debugstr_w(path));
1064
1065     if (path[0]=='0')
1066     {
1067         FIXME("Registry entry.. check entry\n");
1068         rrc = INSTALLSTATE_LOCAL;
1069     }
1070     else
1071     {
1072         /* PROBABLY a file */
1073         if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES )
1074             rrc = INSTALLSTATE_LOCAL;
1075         else
1076             rrc = INSTALLSTATE_ABSENT;
1077     }
1078
1079     if( pcchBuf )
1080     {
1081         sz = sz / sizeof(WCHAR);
1082         if( *pcchBuf >= sz )
1083             lstrcpyW( lpPathBuf, path );
1084         *pcchBuf = sz;
1085     }
1086
1087 end:
1088     msi_free(path );
1089     RegCloseKey(hkey);
1090     return rrc;
1091 }
1092
1093 /******************************************************************
1094  * MsiQueryFeatureStateA      [MSI.@]
1095  */
1096 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1097 {
1098     LPWSTR szwProduct = NULL, szwFeature= NULL;
1099     INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
1100
1101     szwProduct = strdupAtoW( szProduct );
1102     if ( szProduct && !szwProduct )
1103         goto end;
1104
1105     szwFeature = strdupAtoW( szFeature );
1106     if ( szFeature && !szwFeature )
1107         goto end;
1108
1109     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1110
1111 end:
1112     msi_free( szwProduct);
1113     msi_free( szwFeature);
1114
1115     return rc;
1116 }
1117
1118 /******************************************************************
1119  * MsiQueryFeatureStateW      [MSI.@]
1120  *
1121  * This does not verify that the Feature is functional. So i am only going to
1122  * check the existence of the key in the registry. This should tell me if it is
1123  * installed.
1124  */
1125 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1126 {
1127     WCHAR squishProduct[GUID_SIZE];
1128     UINT rc;
1129     DWORD sz = 0;
1130     HKEY hkey;
1131
1132     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1133
1134     if (!szProduct || !szFeature)
1135         return INSTALLSTATE_INVALIDARG;
1136
1137     if (!squash_guid( szProduct, squishProduct ))
1138         return INSTALLSTATE_INVALIDARG;
1139
1140     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
1141     if (rc != ERROR_SUCCESS)
1142         return INSTALLSTATE_UNKNOWN;
1143
1144     rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz);
1145     RegCloseKey(hkey);
1146
1147     if (rc == ERROR_SUCCESS)
1148         return INSTALLSTATE_LOCAL;
1149
1150     return INSTALLSTATE_UNKNOWN;
1151 }
1152
1153 /******************************************************************
1154  * MsiGetFileVersionA         [MSI.@]
1155  */
1156 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1157                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1158 {
1159     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1160     UINT ret = ERROR_OUTOFMEMORY;
1161
1162     if( szFilePath )
1163     {
1164         szwFilePath = strdupAtoW( szFilePath );
1165         if( !szwFilePath )
1166             goto end;
1167     }
1168
1169     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1170     {
1171         lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1172         if( !lpwVersionBuff )
1173             goto end;
1174     }
1175
1176     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1177     {
1178         lpwLangBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR));
1179         if( !lpwLangBuff )
1180             goto end;
1181     }
1182
1183     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1184                              lpwLangBuff, pcchLangBuf);
1185
1186     if( lpwVersionBuff )
1187         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1188                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1189     if( lpwLangBuff )
1190         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1191                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1192
1193 end:
1194     msi_free(szwFilePath);
1195     msi_free(lpwVersionBuff);
1196     msi_free(lpwLangBuff);
1197
1198     return ret;
1199 }
1200
1201 /******************************************************************
1202  * MsiGetFileVersionW         [MSI.@]
1203  */
1204 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1205                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1206 {
1207     static WCHAR szVersionResource[] = {'\\',0};
1208     static const WCHAR szVersionFormat[] = {
1209         '%','d','.','%','d','.','%','d','.','%','d',0};
1210     static const WCHAR szLangFormat[] = {'%','d',0};
1211     UINT ret = 0;
1212     DWORD dwVerLen;
1213     LPVOID lpVer = NULL;
1214     VS_FIXEDFILEINFO *ffi;
1215     UINT puLen;
1216     WCHAR tmp[32];
1217
1218     TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath),
1219           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1220           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1221
1222     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1223     if( !dwVerLen )
1224         return GetLastError();
1225
1226     lpVer = msi_alloc(dwVerLen);
1227     if( !lpVer )
1228     {
1229         ret = ERROR_OUTOFMEMORY;
1230         goto end;
1231     }
1232
1233     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1234     {
1235         ret = GetLastError();
1236         goto end;
1237     }
1238     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1239     {
1240         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1241             (puLen > 0) )
1242         {
1243             wsprintfW(tmp, szVersionFormat,
1244                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1245                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1246             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1247             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1248         }
1249         else
1250         {
1251             *lpVersionBuf = 0;
1252             *pcchVersionBuf = 0;
1253         }
1254     }
1255
1256     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1257     {
1258         DWORD lang = GetUserDefaultLangID();
1259
1260         FIXME("Retrieve language from file\n");
1261         wsprintfW(tmp, szLangFormat, lang);
1262         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1263         *pcchLangBuf = lstrlenW(lpLangBuf);
1264     }
1265
1266 end:
1267     msi_free(lpVer);
1268     return ret;
1269 }
1270
1271
1272 /******************************************************************
1273  *      DllMain
1274  */
1275 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1276 {
1277     switch(fdwReason)
1278     {
1279     case DLL_PROCESS_ATTACH:
1280         msi_hInstance = hinstDLL;
1281         DisableThreadLibraryCalls(hinstDLL);
1282         msi_dialog_register_class();
1283         break;
1284     case DLL_PROCESS_DETACH:
1285         msi_dialog_unregister_class();
1286         /* FIXME: Cleanup */
1287         break;
1288     }
1289     return TRUE;
1290 }
1291
1292 typedef struct tagIClassFactoryImpl
1293 {
1294     const IClassFactoryVtbl *lpVtbl;
1295 } IClassFactoryImpl;
1296
1297 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
1298                 REFIID riid,LPVOID *ppobj)
1299 {
1300     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1301     FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
1302     return E_NOINTERFACE;
1303 }
1304
1305 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
1306 {
1307     LockModule();
1308     return 2;
1309 }
1310
1311 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
1312 {
1313     UnlockModule();
1314     return 1;
1315 }
1316
1317 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
1318     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
1319 {
1320     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1321
1322     FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
1323     return E_FAIL;
1324 }
1325
1326 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1327 {
1328     TRACE("(%p)->(%d)\n", iface, dolock);
1329
1330     if(dolock)
1331         LockModule();
1332     else
1333         UnlockModule();
1334
1335     return S_OK;
1336 }
1337
1338 static const IClassFactoryVtbl MsiCF_Vtbl =
1339 {
1340     MsiCF_QueryInterface,
1341     MsiCF_AddRef,
1342     MsiCF_Release,
1343     MsiCF_CreateInstance,
1344     MsiCF_LockServer
1345 };
1346
1347 static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
1348
1349 /******************************************************************
1350  * DllGetClassObject          [MSI.@]
1351  */
1352 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1353 {
1354     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1355
1356     if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
1357         IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
1358         IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
1359         IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
1360         IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
1361     {
1362         *ppv = (LPVOID) &Msi_CF;
1363         return S_OK;
1364     }
1365     return CLASS_E_CLASSNOTAVAILABLE;
1366 }
1367
1368 /******************************************************************
1369  * DllGetVersion              [MSI.@]
1370  */
1371 HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
1372 {
1373     TRACE("%p\n",pdvi);
1374
1375     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
1376         return E_INVALIDARG;
1377
1378     pdvi->dwMajorVersion = MSI_MAJORVERSION;
1379     pdvi->dwMinorVersion = MSI_MINORVERSION;
1380     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
1381     pdvi->dwPlatformID = 1;
1382
1383     return S_OK;
1384 }
1385
1386 /******************************************************************
1387  * DllCanUnloadNow            [MSI.@]
1388  */
1389 HRESULT WINAPI DllCanUnloadNow(void)
1390 {
1391     return dll_count == 0 ? S_OK : S_FALSE;
1392 }
1393
1394 /***********************************************************************
1395  * MsiGetFeatureUsageW           [MSI.@]
1396  */
1397 UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
1398                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1399 {
1400     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1401           pdwUseCount, pwDateUsed);
1402     return ERROR_CALL_NOT_IMPLEMENTED;
1403 }
1404
1405 /***********************************************************************
1406  * MsiGetFeatureUsageA           [MSI.@]
1407  */
1408 UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
1409                                  DWORD* pdwUseCount, WORD* pwDateUsed )
1410 {
1411     LPWSTR prod = NULL, feat = NULL;
1412     UINT ret = ERROR_OUTOFMEMORY;
1413
1414     TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1415           pdwUseCount, pwDateUsed);
1416
1417     prod = strdupAtoW( szProduct );
1418     if (szProduct && !prod)
1419         goto end;
1420
1421     feat = strdupAtoW( szFeature );
1422     if (szFeature && !feat)
1423         goto end;
1424
1425     ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
1426
1427 end:
1428     msi_free( prod );
1429     msi_free( feat );
1430
1431     return ret;
1432 }
1433
1434 /***********************************************************************
1435  * MsiUseFeatureExW           [MSI.@]
1436  */
1437 INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
1438                                       DWORD dwInstallMode, DWORD dwReserved )
1439 {
1440     INSTALLSTATE state;
1441
1442     TRACE("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1443           dwInstallMode, dwReserved);
1444
1445     state = MsiQueryFeatureStateW( szProduct, szFeature );
1446
1447     if (dwReserved)
1448         return INSTALLSTATE_INVALIDARG;
1449
1450     if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
1451     {
1452         FIXME("mark product %s feature %s as used\n",
1453               debugstr_w(szProduct), debugstr_w(szFeature) );
1454     }
1455
1456     return state;
1457 }
1458
1459 /***********************************************************************
1460  * MsiUseFeatureExA           [MSI.@]
1461  */
1462 INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
1463                                       DWORD dwInstallMode, DWORD dwReserved )
1464 {
1465     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1466     LPWSTR prod = NULL, feat = NULL;
1467
1468     TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1469           dwInstallMode, dwReserved);
1470
1471     prod = strdupAtoW( szProduct );
1472     if (szProduct && !prod)
1473         goto end;
1474
1475     feat = strdupAtoW( szFeature );
1476     if (szFeature && !feat)
1477         goto end;
1478
1479     ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
1480
1481 end:
1482     msi_free( prod );
1483     msi_free( feat );
1484
1485     return ret;
1486 }
1487
1488 INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
1489 {
1490     FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1491
1492     return INSTALLSTATE_LOCAL;
1493 }
1494
1495 INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
1496 {
1497     INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
1498     LPWSTR prod = NULL, feat = NULL;
1499
1500     TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) );
1501
1502     prod = strdupAtoW( szProduct );
1503     if (szProduct && !prod)
1504         goto end;
1505
1506     feat = strdupAtoW( szFeature );
1507     if (szFeature && !feat)
1508         goto end;
1509
1510     ret = MsiUseFeatureW( prod, feat );
1511
1512 end:
1513     msi_free( prod );
1514     msi_free( feat );
1515
1516     return ret;
1517 }
1518
1519 /***********************************************************************
1520  * MsiProvideQualifiedComponentExW [MSI.@]
1521  */
1522 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1523                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1524                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1525                 DWORD* pcchPathBuf)
1526 {
1527     HKEY hkey;
1528     UINT rc;
1529     LPWSTR info;
1530     DWORD sz;
1531     WCHAR product[MAX_FEATURE_CHARS+1];
1532     WCHAR component[MAX_FEATURE_CHARS+1];
1533     WCHAR feature[MAX_FEATURE_CHARS+1];
1534
1535     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
1536           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1537           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1538    
1539     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1540     if (rc != ERROR_SUCCESS)
1541         return ERROR_INDEX_ABSENT;
1542
1543     sz = 0;
1544     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
1545     if (sz <= 0)
1546     {
1547         RegCloseKey(hkey);
1548         return ERROR_INDEX_ABSENT;
1549     }
1550
1551     info = msi_alloc(sz);
1552     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
1553     if (rc != ERROR_SUCCESS)
1554     {
1555         RegCloseKey(hkey);
1556         msi_free(info);
1557         return ERROR_INDEX_ABSENT;
1558     }
1559
1560     MsiDecomposeDescriptorW(info, product, feature, component, &sz);
1561     
1562     if (!szProduct)
1563         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
1564     else
1565         rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
1566    
1567     RegCloseKey(hkey);
1568     msi_free(info);
1569
1570     if (rc == INSTALLSTATE_LOCAL)
1571         return ERROR_SUCCESS;
1572     else 
1573         return ERROR_FILE_NOT_FOUND;
1574 }
1575
1576 /***********************************************************************
1577  * MsiProvideQualifiedComponentW [MSI.@]
1578  */
1579 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1580                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1581                 DWORD* pcchPathBuf)
1582 {
1583     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1584                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1585 }
1586
1587 /***********************************************************************
1588  * MsiProvideQualifiedComponentA [MSI.@]
1589  */
1590 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1591                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1592                 DWORD* pcchPathBuf)
1593 {
1594     LPWSTR szwComponent, szwQualifier, lpwPathBuf;
1595     DWORD pcchwPathBuf;
1596     UINT rc;
1597
1598     TRACE("%s %s %li %p %p\n",szComponent, szQualifier,
1599                     dwInstallMode, lpPathBuf, pcchPathBuf);
1600
1601     szwComponent= strdupAtoW( szComponent);
1602     szwQualifier= strdupAtoW( szQualifier);
1603
1604     lpwPathBuf = msi_alloc(*pcchPathBuf * sizeof(WCHAR));
1605
1606     pcchwPathBuf = *pcchPathBuf;
1607
1608     rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, 
1609                     dwInstallMode, lpwPathBuf, &pcchwPathBuf);
1610
1611     msi_free(szwComponent);
1612     msi_free(szwQualifier);
1613     *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf,
1614                     lpPathBuf, *pcchPathBuf, NULL, NULL);
1615
1616     msi_free(lpwPathBuf);
1617     return rc;
1618 }
1619
1620 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf,
1621                 DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf,
1622                 DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1623 {
1624     HKEY hkey;
1625     DWORD sz;
1626     UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS;
1627
1628     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1629           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1630           pcchSerialBuf);
1631
1632     rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1633     if (rc != ERROR_SUCCESS)
1634         return USERINFOSTATE_UNKNOWN;
1635
1636     if (lpUserNameBuf)
1637     {
1638         sz = *lpUserNameBuf * sizeof(WCHAR);
1639         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
1640                 NULL, (LPBYTE)lpUserNameBuf,
1641                                &sz);
1642     }
1643     if (!lpUserNameBuf && pcchUserNameBuf)
1644     {
1645         sz = 0;
1646         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_REGOWNERW, NULL,
1647                 NULL, NULL, &sz);
1648     }
1649
1650     if (pcchUserNameBuf)
1651         *pcchUserNameBuf = sz / sizeof(WCHAR);
1652
1653     if (lpOrgNameBuf)
1654     {
1655         sz = *pcchOrgNameBuf * sizeof(WCHAR);
1656         rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
1657                 NULL, (LPBYTE)lpOrgNameBuf, &sz);
1658     }
1659     if (!lpOrgNameBuf && pcchOrgNameBuf)
1660     {
1661         sz = 0;
1662         rc2 = RegQueryValueExW( hkey, INSTALLPROPERTY_REGCOMPANYW, NULL,
1663                 NULL, NULL, &sz);
1664     }
1665
1666     if (pcchOrgNameBuf)
1667         *pcchOrgNameBuf = sz / sizeof(WCHAR);
1668
1669     if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && 
1670         rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA)
1671     {
1672         RegCloseKey(hkey);
1673         return USERINFOSTATE_ABSENT;
1674     }
1675
1676     if (lpSerialBuf)
1677     {
1678         sz = *pcchSerialBuf * sizeof(WCHAR);
1679         RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL, NULL,
1680                 (LPBYTE)lpSerialBuf, &sz);
1681     }
1682     if (!lpSerialBuf && pcchSerialBuf)
1683     {
1684         sz = 0;
1685         rc = RegQueryValueExW( hkey, INSTALLPROPERTY_PRODUCTIDW, NULL,
1686                 NULL, NULL, &sz);
1687     }
1688     if (pcchSerialBuf)
1689         *pcchSerialBuf = sz / sizeof(WCHAR);
1690     
1691     RegCloseKey(hkey);
1692     return USERINFOSTATE_PRESENT;
1693 }
1694
1695 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf,
1696                 DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf,
1697                 DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1698 {
1699     FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf,
1700           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1701           pcchSerialBuf);
1702
1703     return USERINFOSTATE_UNKNOWN;
1704 }
1705
1706 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1707 {
1708     MSIHANDLE handle;
1709     UINT rc;
1710     MSIPACKAGE *package;
1711     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1712
1713     TRACE("(%s)\n",debugstr_w(szProduct));
1714
1715     rc = MsiOpenProductW(szProduct,&handle);
1716     if (rc != ERROR_SUCCESS)
1717         return ERROR_INVALID_PARAMETER;
1718
1719     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1720     rc = ACTION_PerformUIAction(package, szFirstRun);
1721     msiobj_release( &package->hdr );
1722
1723     MsiCloseHandle(handle);
1724
1725     return rc;
1726 }
1727
1728 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1729 {
1730     MSIHANDLE handle;
1731     UINT rc;
1732     MSIPACKAGE *package;
1733     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1734
1735     TRACE("(%s)\n",debugstr_a(szProduct));
1736
1737     rc = MsiOpenProductA(szProduct,&handle);
1738     if (rc != ERROR_SUCCESS)
1739         return ERROR_INVALID_PARAMETER;
1740
1741     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1742     rc = ACTION_PerformUIAction(package, szFirstRun);
1743     msiobj_release( &package->hdr );
1744
1745     MsiCloseHandle(handle);
1746
1747     return rc;
1748 }
1749
1750 /***********************************************************************
1751  * MsiConfigureFeatureA            [MSI.@]
1752  */
1753 UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState)
1754 {
1755     FIXME("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState);
1756     return ERROR_SUCCESS;
1757 }
1758
1759 /***********************************************************************
1760  * MsiConfigureFeatureW            [MSI.@]
1761  */
1762 UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState)
1763 {
1764     FIXME("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState);
1765     return ERROR_SUCCESS;
1766 }
1767
1768 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1769 {
1770     WCHAR path[MAX_PATH];
1771
1772     if(dwReserved) {
1773         FIXME("Don't know how to handle argument %ld\n", dwReserved);
1774         return ERROR_CALL_NOT_IMPLEMENTED;
1775     }
1776
1777    if(!GetWindowsDirectoryW(path, MAX_PATH)) {
1778         FIXME("GetWindowsDirectory failed unexpected! Error %ld\n",
1779               GetLastError());
1780         return ERROR_CALL_NOT_IMPLEMENTED;
1781    }
1782
1783    strcatW(path, installerW);
1784
1785    CreateDirectoryW(path, NULL);
1786
1787    return 0;
1788 }
1789
1790 /***********************************************************************
1791  * MsiGetShortcutTargetA           [MSI.@]
1792  */
1793 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1794                                    LPSTR szProductCode, LPSTR szFeatureId,
1795                                    LPSTR szComponentCode )
1796 {
1797     LPWSTR target;
1798     const int len = MAX_FEATURE_CHARS+1;
1799     WCHAR product[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1], component[MAX_FEATURE_CHARS+1];
1800     UINT r;
1801
1802     target = strdupAtoW( szShortcutTarget );
1803     if (szShortcutTarget && !target )
1804         return ERROR_OUTOFMEMORY;
1805     product[0] = 0;
1806     feature[0] = 0;
1807     component[0] = 0;
1808     r = MsiGetShortcutTargetW( target, product, feature, component );
1809     msi_free( target );
1810     if (r == ERROR_SUCCESS)
1811     {
1812         WideCharToMultiByte( CP_ACP, 0, product, -1, szProductCode, len, NULL, NULL );
1813         WideCharToMultiByte( CP_ACP, 0, feature, -1, szFeatureId, len, NULL, NULL );
1814         WideCharToMultiByte( CP_ACP, 0, component, -1, szComponentCode, len, NULL, NULL );
1815     }
1816     return r;
1817 }
1818
1819 /***********************************************************************
1820  * MsiGetShortcutTargetW           [MSI.@]
1821  */
1822 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1823                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1824                                    LPWSTR szComponentCode )
1825 {
1826     IShellLinkDataList *dl = NULL;
1827     IPersistFile *pf = NULL;
1828     LPEXP_DARWIN_LINK darwin = NULL;
1829     HRESULT r, init;
1830
1831     TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
1832           szProductCode, szFeatureId, szComponentCode );
1833
1834     init = CoInitialize(NULL);
1835
1836     r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1837                           &IID_IPersistFile, (LPVOID*) &pf );
1838     if( SUCCEEDED( r ) )
1839     {
1840         r = IPersistFile_Load( pf, szShortcutTarget,
1841                                STGM_READ | STGM_SHARE_DENY_WRITE );
1842         if( SUCCEEDED( r ) )
1843         {
1844             r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
1845                                              (LPVOID*) &dl );
1846             if( SUCCEEDED( r ) )
1847             {
1848                 IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
1849                                                   (LPVOID) &darwin );
1850                 IShellLinkDataList_Release( dl );
1851             }
1852         }
1853         IPersistFile_Release( pf );
1854     }
1855
1856     if (SUCCEEDED(init))
1857         CoUninitialize();
1858
1859     TRACE("darwin = %p\n", darwin);
1860
1861     if (darwin)
1862     {
1863         DWORD sz;
1864         UINT ret;
1865
1866         ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
1867                   szProductCode, szFeatureId, szComponentCode, &sz );
1868         LocalFree( darwin );
1869         return ret;
1870     }
1871
1872     return ERROR_FUNCTION_FAILED;
1873 }
1874
1875 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1876                                   DWORD dwReinstallMode )
1877 {
1878     MSIPACKAGE* package = NULL;
1879     UINT r;
1880     DWORD sz;
1881     WCHAR sourcepath[MAX_PATH];
1882     WCHAR filename[MAX_PATH];
1883     static const WCHAR szInstalled[] = {
1884         ' ','L','O','G','V','E','R','B','O','S','E','=','1',' ','I','n','s','t','a','l','l','e','d','=','1',0};
1885     static const WCHAR fmt[] = {'R','E','I','N','S','T','A','L','L','=','%','s',0};
1886     static const WCHAR REINSTALLMODE[] = {'R','E','I','N','S','T','A','L','L','M','O','D','E',0};
1887     WCHAR reinstallmode[11];
1888     LPWSTR ptr;
1889     LPWSTR commandline;
1890
1891     FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1892                            dwReinstallMode);
1893
1894     ptr = reinstallmode;
1895
1896     if (dwReinstallMode & REINSTALLMODE_FILEMISSING)
1897         *ptr++ = 'p';
1898     if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION)
1899         *ptr++ = 'o';
1900     if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION)
1901         *ptr++ = 'w';
1902     if (dwReinstallMode & REINSTALLMODE_FILEEXACT)
1903         *ptr++ = 'd';
1904     if (dwReinstallMode & REINSTALLMODE_FILEVERIFY)
1905         *ptr++ = 'c';
1906     if (dwReinstallMode & REINSTALLMODE_FILEREPLACE)
1907         *ptr++ = 'a';
1908     if (dwReinstallMode & REINSTALLMODE_USERDATA)
1909         *ptr++ = 'u';
1910     if (dwReinstallMode & REINSTALLMODE_MACHINEDATA)
1911         *ptr++ = 'm';
1912     if (dwReinstallMode & REINSTALLMODE_SHORTCUT)
1913         *ptr++ = 's';
1914     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1915         *ptr++ = 'v';
1916     *ptr = 0;
1917     
1918     sz = sizeof(sourcepath);
1919     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1920             MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath,
1921             &sz);
1922
1923     sz = sizeof(filename);
1924     MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED, 
1925             MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz);
1926
1927     strcatW(sourcepath,filename);
1928
1929     if (dwReinstallMode & REINSTALLMODE_PACKAGE)
1930         r = MSI_OpenPackageW( sourcepath, &package );
1931     else
1932         r = MSI_OpenProductW( szProduct, &package );
1933
1934     if (r != ERROR_SUCCESS)
1935         return r;
1936
1937     MSI_SetPropertyW(package,REINSTALLMODE,reinstallmode);
1938     
1939     sz = lstrlenW(szInstalled);
1940     sz += lstrlenW(fmt);
1941     sz += lstrlenW(szFeature);
1942
1943     commandline = msi_alloc(sz * sizeof(WCHAR));
1944
1945     sprintfW(commandline,fmt,szFeature);
1946     lstrcatW(commandline,szInstalled);
1947
1948     r = MSI_InstallPackage( package, sourcepath, commandline );
1949
1950     msiobj_release( &package->hdr );
1951
1952     msi_free(commandline);
1953
1954     return r;
1955 }
1956
1957 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1958                                   DWORD dwReinstallMode )
1959 {
1960     LPWSTR wszProduct;
1961     LPWSTR wszFeature;
1962     UINT rc;
1963
1964     TRACE("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1965                            dwReinstallMode);
1966
1967     wszProduct = strdupAtoW(szProduct);
1968     wszFeature = strdupAtoW(szFeature);
1969
1970     rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode);
1971     
1972     msi_free(wszProduct);
1973     msi_free(wszFeature);
1974     return rc;
1975 }
1976
1977 /***********************************************************************
1978  * MsiEnumPatchesA            [MSI.@]
1979  */
1980 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex, 
1981         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1982 {
1983     FIXME("%s %ld %p %p %p\n", debugstr_a(szProduct),
1984           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1985     return ERROR_NO_MORE_ITEMS;
1986 }
1987
1988 /***********************************************************************
1989  * MsiEnumPatchesW            [MSI.@]
1990  */
1991 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, 
1992         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, DWORD* pcchTransformsBuf)
1993 {
1994     FIXME("%s %ld %p %p %p\n", debugstr_w(szProduct),
1995           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1996     return ERROR_NO_MORE_ITEMS;
1997 }
1998
1999 /***********************************************************************
2000  * MsiGetFileHashW            [MSI.@]
2001  */
2002 UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
2003                              PMSIFILEHASHINFO pHash )
2004 {
2005     FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
2006     return ERROR_CALL_NOT_IMPLEMENTED;
2007 }
2008
2009 /***********************************************************************
2010  * MsiGetFileHashA            [MSI.@]
2011  */
2012 UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
2013                              PMSIFILEHASHINFO pHash )
2014 {
2015     FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
2016     return ERROR_CALL_NOT_IMPLEMENTED;
2017 }
2018
2019 /***********************************************************************
2020  * MsiAdvertiseScriptW        [MSI.@]
2021  */
2022 UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
2023                                  PHKEY phRegData, BOOL fRemoveItems )
2024 {
2025     FIXME("%s %08lx %p %d\n",
2026           debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2027     return ERROR_CALL_NOT_IMPLEMENTED;
2028 }
2029
2030 /***********************************************************************
2031  * MsiAdvertiseScriptA        [MSI.@]
2032  */
2033 UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
2034                                  PHKEY phRegData, BOOL fRemoveItems )
2035 {
2036     FIXME("%s %08lx %p %d\n",
2037           debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
2038     return ERROR_CALL_NOT_IMPLEMENTED;
2039 }