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