- implement encoding and decoding of enumerated types, unsigned
[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     static const WCHAR szLocalPackage[] = {
87         'L','o','c','a','l','P','a','c','k','a','g','e', 0
88     };
89     LPWSTR path = NULL;
90     UINT r;
91     HKEY hKeyProduct = NULL;
92     DWORD count, type;
93
94     TRACE("%s %p\n",debugstr_w(szProduct), phProduct);
95
96     r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE);
97     if( r != ERROR_SUCCESS )
98     {
99         r = ERROR_UNKNOWN_PRODUCT;
100         goto end;
101     }
102
103     /* find the size of the path */
104     type = count = 0;
105     r = RegQueryValueExW( hKeyProduct, szLocalPackage,
106                           NULL, &type, NULL, &count );
107     if( r != ERROR_SUCCESS )
108     {
109         r = ERROR_UNKNOWN_PRODUCT;
110         goto end;
111     }
112
113     /* now alloc and fetch the path of the database to open */
114     path = HeapAlloc( GetProcessHeap(), 0, count );
115     if( !path )
116         goto end;
117
118     r = RegQueryValueExW( hKeyProduct, szLocalPackage,
119                           NULL, &type, (LPBYTE) path, &count );
120     if( r != ERROR_SUCCESS )
121     {
122         r = ERROR_UNKNOWN_PRODUCT;
123         goto end;
124     }
125
126     r = MsiOpenPackageW( path, phProduct );
127
128 end:
129     HeapFree( GetProcessHeap(), 0, path );
130     if( hKeyProduct )
131         RegCloseKey( hKeyProduct );
132
133     return r;
134 }
135
136 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
137                 LPCSTR szTransforms, LANGID lgidLanguage)
138 {
139     FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath),
140           debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
141     return ERROR_CALL_NOT_IMPLEMENTED;
142 }
143
144 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
145                 LPCWSTR szTransforms, LANGID lgidLanguage)
146 {
147     FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath),
148           debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
149     return ERROR_CALL_NOT_IMPLEMENTED;
150 }
151
152 UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath,
153       LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
154 {
155     FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath),
156           debugstr_a(szScriptfilePath), debugstr_a(szTransforms),
157           lgidLanguage, dwPlatform, dwOptions);
158     return ERROR_CALL_NOT_IMPLEMENTED;
159 }
160
161 UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath,
162       LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
163 {
164     FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath),
165           debugstr_w(szScriptfilePath), debugstr_w(szTransforms),
166           lgidLanguage, dwPlatform, dwOptions);
167     return ERROR_CALL_NOT_IMPLEMENTED;
168 }
169
170 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
171 {
172     LPWSTR szwPath = NULL, szwCommand = NULL;
173     UINT r = ERROR_OUTOFMEMORY;
174
175     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
176
177     if( szPackagePath )
178     {
179         szwPath = strdupAtoW( szPackagePath );
180         if( !szwPath )
181             goto end;
182     }
183
184     if( szCommandLine )
185     {
186         szwCommand = strdupAtoW( szCommandLine );
187         if( !szwCommand )
188             goto end;
189     }
190
191     r = MsiInstallProductW( szwPath, szwCommand );
192
193 end:
194     HeapFree( GetProcessHeap(), 0, szwPath );
195     HeapFree( GetProcessHeap(), 0, szwCommand );
196
197     return r;
198 }
199
200 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
201 {
202     MSIPACKAGE *package = NULL;
203     UINT r;
204     MSIHANDLE handle;
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     r = MSI_OpenPackageW(szPackagePath,&package);
213     if (r != ERROR_SUCCESS)
214         return r;
215
216     handle = alloc_msihandle( &package->hdr );
217
218     r = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine);
219
220     MsiCloseHandle(handle);
221     msiobj_release( &package->hdr );
222     return r;
223 }
224
225 UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
226 {
227     FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode);
228     return ERROR_CALL_NOT_IMPLEMENTED;
229 }
230
231 UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
232 {
233     FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode);
234     return ERROR_CALL_NOT_IMPLEMENTED;
235 }
236
237 UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage,
238         INSTALLTYPE eInstallType, LPCSTR szCommandLine)
239 {
240     FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage),
241           eInstallType, debugstr_a(szCommandLine));
242     return ERROR_CALL_NOT_IMPLEMENTED;
243 }
244
245 UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage,
246          INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
247 {
248     FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage),
249           eInstallType, debugstr_w(szCommandLine));
250     return ERROR_CALL_NOT_IMPLEMENTED;
251 }
252
253 UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel,
254                         INSTALLSTATE eInstallState, LPCWSTR szCommandLine)
255 {
256     MSIHANDLE handle = -1;
257     MSIPACKAGE* package;
258     UINT rc;
259     HKEY hkey=0,hkey1=0;
260     DWORD sz;
261     static const WCHAR szSouceList[] = {
262         'S','o','u','r','c','e','L','i','s','t',0};
263     static const WCHAR szLUS[] = {
264         'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
265     WCHAR sourcepath[0x200];
266     static const WCHAR szInstalled[] = {
267         ' ','I','n','s','t','a','l','l','e','d','=','1',0};
268     LPWSTR commandline;
269
270     FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState,
271           debugstr_w(szCommandLine));
272
273     if (eInstallState != INSTALLSTATE_LOCAL &&
274         eInstallState != INSTALLSTATE_DEFAULT)
275     {
276         FIXME("Not implemented for anything other than local installs\n");
277         return ERROR_CALL_NOT_IMPLEMENTED;
278     }
279
280     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
281     if (rc != ERROR_SUCCESS)
282         goto end;
283
284     rc = RegOpenKeyW(hkey,szSouceList,&hkey1);
285     if (rc != ERROR_SUCCESS)
286         goto end;
287
288     sz = sizeof(sourcepath);
289     rc = RegQueryValueExW(hkey1, szLUS, NULL, NULL,(LPBYTE)sourcepath, &sz);
290     if (rc != ERROR_SUCCESS)
291         goto end;
292
293     RegCloseKey(hkey1);
294     /*
295      * ok 1, we need to find the msi file for this product.
296      *    2, find the source dir for the files
297      *    3, do the configure/install.
298      *    4, cleanupany runonce entry.
299      */
300
301     rc = MsiOpenProductW(szProduct,&handle);
302     if (rc != ERROR_SUCCESS)
303         goto end;
304
305     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
306     if (!package)
307     {
308         rc = ERROR_INVALID_HANDLE;
309         goto end;
310     }
311
312     sz = lstrlenW(szInstalled);
313
314     if (szCommandLine)
315         sz += lstrlenW(szCommandLine);
316
317     commandline = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
318
319     if (szCommandLine)
320         lstrcpyW(commandline,szCommandLine);
321     else
322         commandline[0] = 0;
323
324     if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN)
325         lstrcatW(commandline,szInstalled);
326
327     rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline);
328
329     msiobj_release( &package->hdr );
330
331     HeapFree(GetProcessHeap(),0,commandline);
332 end:
333     RegCloseKey(hkey);
334     if (handle != -1)
335         MsiCloseHandle(handle);
336
337     return rc;
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     HeapFree( GetProcessHeap(), 0, szwProduct );
365     HeapFree( GetProcessHeap(), 0, 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     HeapFree( GetProcessHeap(), 0, 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     HeapFree( GetProcessHeap(), 0, 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 = HeapAlloc( GetProcessHeap(), 0, (*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         *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf,
497                         szBuffer, *pcchValueBuf, NULL, NULL);
498
499 end:
500     HeapFree( GetProcessHeap(), 0, szwProduct );
501     HeapFree( GetProcessHeap(), 0, szwAttribute );
502     HeapFree( GetProcessHeap(), 0, szwBuffer );
503
504     return r;
505 }
506
507 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
508                 LPWSTR szBuffer, DWORD *pcchValueBuf)
509 {
510     MSIHANDLE hProduct;
511     UINT r;
512     static const WCHAR szPackageCode[] =
513         {'P','a','c','k','a','g','e','C','o','d','e',0};
514     static const WCHAR szVersionString[] =
515         {'V','e','r','s','i','o','n','S','t','r','i','n','g',0};
516     static const WCHAR szProductVersion[] =
517         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
518     static const WCHAR szAssignmentType[] =
519         {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0};
520     static const WCHAR szLanguage[] =
521         {'L','a','n','g','u','a','g','e',0};
522     static const WCHAR szProductLanguage[] =
523         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
524
525     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute),
526           szBuffer, pcchValueBuf);
527
528     if (NULL != szBuffer && NULL == pcchValueBuf)
529         return ERROR_INVALID_PARAMETER;
530     if (NULL == szProduct || NULL == szAttribute)
531         return ERROR_INVALID_PARAMETER;
532     
533     /* check for special properties */
534     if (strcmpW(szAttribute, szPackageCode)==0)
535     {
536         HKEY hkey;
537         WCHAR squished[GUID_SIZE];
538         WCHAR package[200];
539         DWORD sz = sizeof(squished);
540
541         r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE);
542         if (r != ERROR_SUCCESS)
543             return ERROR_UNKNOWN_PRODUCT;
544
545         r = RegQueryValueExW(hkey, szPackageCode, NULL, NULL, 
546                         (LPBYTE)squished, &sz);
547         if (r != ERROR_SUCCESS)
548         {
549             RegCloseKey(hkey);
550             return ERROR_UNKNOWN_PRODUCT;
551         }
552
553         unsquash_guid(squished, package);
554         *pcchValueBuf = strlenW(package);
555         if (strlenW(package) > *pcchValueBuf)
556         {
557             RegCloseKey(hkey);
558             return ERROR_MORE_DATA;
559         }
560         else
561             strcpyW(szBuffer, package);
562
563         RegCloseKey(hkey);
564         r = ERROR_SUCCESS;
565     }
566     else if (strcmpW(szAttribute, szVersionString)==0)
567     {
568         r = MsiOpenProductW(szProduct, &hProduct);
569         if (ERROR_SUCCESS != r)
570             return r;
571
572         r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf);
573         MsiCloseHandle(hProduct);
574     }
575     else if (strcmpW(szAttribute, szAssignmentType)==0)
576     {
577         FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n");
578         if (szBuffer)
579         {
580             szBuffer[0] = '1';
581             szBuffer[1] = 0;
582         }
583         if (pcchValueBuf)
584             *pcchValueBuf = 1;
585         r = ERROR_SUCCESS;
586     }
587     else if (strcmpW(szAttribute, szLanguage)==0)
588     {
589         r = MsiOpenProductW(szProduct, &hProduct);
590         if (ERROR_SUCCESS != r)
591             return r;
592
593         r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
594         MsiCloseHandle(hProduct);
595     }
596     else
597     {
598         r = MsiOpenProductW(szProduct, &hProduct);
599         if (ERROR_SUCCESS != r)
600             return r;
601
602         r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
603         MsiCloseHandle(hProduct);
604     }
605
606     return r;
607 }
608
609 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
610 {
611     LPWSTR szwLogFile = NULL;
612     UINT r;
613
614     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes);
615
616     if( szLogFile )
617     {
618         szwLogFile = strdupAtoW( szLogFile );
619         if( !szwLogFile )
620             return ERROR_OUTOFMEMORY;
621     }
622     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
623     HeapFree( GetProcessHeap(), 0, szwLogFile );
624     return r;
625 }
626
627 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
628 {
629     HANDLE file = INVALID_HANDLE_VALUE;
630
631     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes);
632
633     lstrcpyW(gszLogFile,szLogFile);
634     if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
635         DeleteFileW(szLogFile);
636     file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
637                            FILE_ATTRIBUTE_NORMAL, NULL);
638     if (file != INVALID_HANDLE_VALUE)
639         CloseHandle(file);
640     else
641         ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
642
643     return ERROR_SUCCESS;
644 }
645
646 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
647 {
648     LPWSTR szwProduct = NULL;
649     INSTALLSTATE r;
650
651     if( szProduct )
652     {
653          szwProduct = strdupAtoW( szProduct );
654          if( !szwProduct )
655              return ERROR_OUTOFMEMORY;
656     }
657     r = MsiQueryProductStateW( szwProduct );
658     HeapFree( GetProcessHeap(), 0, szwProduct );
659     return r;
660 }
661
662 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
663 {
664     UINT rc;
665     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
666     HKEY hkey = 0;
667     static const WCHAR szWindowsInstaller[] = {
668          'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 };
669     DWORD sz;
670
671     TRACE("%s\n", debugstr_w(szProduct));
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 = HeapAlloc(GetProcessHeap(), 0, 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     HeapFree(GetProcessHeap(), 0, bufW);
832     return r;
833 }
834
835 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
836                 DWORD *pcchBuf)
837 {
838     FIXME("%s %p %08lx\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 %08lx\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 ERROR_CALL_NOT_IMPLEMENTED;
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 ERROR_CALL_NOT_IMPLEMENTED;
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     HeapFree( GetProcessHeap(), 0, 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             HeapFree( GetProcessHeap(), 0, szwProduct);
985             return ERROR_OUTOFMEMORY;
986         }
987     }
988
989     if( pcchBuf && *pcchBuf > 0 )
990     {
991         lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *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     HeapFree( GetProcessHeap(), 0, szwProduct);
1003     HeapFree( GetProcessHeap(), 0, 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         HeapFree( GetProcessHeap(), 0, 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( lpPathBuf && !pcchBuf )
1029         return INSTALLSTATE_INVALIDARG;
1030
1031     squash_guid(szProduct,squished_pc);
1032
1033     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1034     if( rc != ERROR_SUCCESS )
1035         goto end;
1036
1037     RegCloseKey(hkey);
1038
1039     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1040     if( rc != ERROR_SUCCESS )
1041         goto end;
1042
1043     sz = 0;
1044     type = 0;
1045     rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz );
1046     if( rc != ERROR_SUCCESS )
1047         goto end;
1048     if( type != REG_SZ )
1049         goto end;
1050
1051     sz += sizeof(WCHAR);
1052     path = HeapAlloc( GetProcessHeap(), 0, sz );
1053     if( !path )
1054         goto end;
1055
1056     rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz );
1057     if( rc != ERROR_SUCCESS )
1058         goto end;
1059
1060     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1061            debugstr_w(szProduct), debugstr_w(path));
1062
1063     if (path[0]=='0')
1064     {
1065         FIXME("Registry entry.. check entry\n");
1066         rrc = INSTALLSTATE_LOCAL;
1067     }
1068     else
1069     {
1070         /* PROBABLY a file */
1071         if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES )
1072             rrc = INSTALLSTATE_LOCAL;
1073         else
1074             rrc = INSTALLSTATE_ABSENT;
1075     }
1076
1077     if( pcchBuf )
1078     {
1079         sz = sz / sizeof(WCHAR);
1080         if( *pcchBuf >= sz )
1081             lstrcpyW( lpPathBuf, path );
1082         *pcchBuf = sz;
1083     }
1084
1085 end:
1086     HeapFree(GetProcessHeap(), 0, path );
1087     RegCloseKey(hkey);
1088     return rrc;
1089 }
1090
1091 /******************************************************************
1092  * MsiQueryFeatureStateA      [MSI.@]
1093  */
1094 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1095 {
1096     INSTALLSTATE rc;
1097     LPWSTR szwProduct= NULL;
1098     LPWSTR szwFeature= NULL;
1099
1100     if( szProduct )
1101     {
1102         szwProduct = strdupAtoW( szProduct );
1103         if( !szwProduct)
1104             return ERROR_OUTOFMEMORY;
1105     }
1106
1107     if( szFeature )
1108     {
1109         szwFeature = strdupAtoW( szFeature );
1110         if( !szwFeature)
1111         {
1112             HeapFree( GetProcessHeap(), 0, szwProduct);
1113             return ERROR_OUTOFMEMORY;
1114         }
1115     }
1116
1117     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1118
1119     HeapFree( GetProcessHeap(), 0, szwProduct);
1120     HeapFree( GetProcessHeap(), 0, szwFeature);
1121
1122     return rc;
1123 }
1124
1125 /******************************************************************
1126  * MsiQueryFeatureStateW      [MSI.@]
1127  *
1128  * This does not verify that the Feature is functional. So i am only going to
1129  * check the existence of the key in the registry. This should tell me if it is
1130  * installed.
1131  */
1132 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1133 {
1134     UINT rc;
1135     DWORD sz = 0;
1136     HKEY hkey;
1137
1138     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
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     else
1150         return INSTALLSTATE_ABSENT;
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 = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR));
1172         if( !lpwVersionBuff )
1173             goto end;
1174     }
1175
1176     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1177     {
1178         lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *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     HeapFree(GetProcessHeap(), 0, szwFilePath);
1195     HeapFree(GetProcessHeap(), 0, lpwVersionBuff);
1196     HeapFree(GetProcessHeap(), 0, 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 const 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 = HeapAlloc(GetProcessHeap(), 0, 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     HeapFree(GetProcessHeap(), 0, 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     return 2;
1308 }
1309
1310 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
1311 {
1312     return 1;
1313 }
1314
1315 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
1316     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
1317 {
1318     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1319
1320     FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
1321     return E_FAIL;
1322 }
1323
1324 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1325 {
1326     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1327
1328     FIXME("%p %d\n", This, dolock);
1329     return S_OK;
1330 }
1331
1332 static const IClassFactoryVtbl MsiCF_Vtbl =
1333 {
1334     MsiCF_QueryInterface,
1335     MsiCF_AddRef,
1336     MsiCF_Release,
1337     MsiCF_CreateInstance,
1338     MsiCF_LockServer
1339 };
1340
1341 static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
1342
1343 /******************************************************************
1344  * DllGetClassObject          [MSI.@]
1345  */
1346 HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1347 {
1348     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1349
1350     if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
1351         IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
1352         IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
1353         IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
1354         IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
1355     {
1356         *ppv = (LPVOID) &Msi_CF;
1357         return S_OK;
1358     }
1359     return CLASS_E_CLASSNOTAVAILABLE;
1360 }
1361
1362 /******************************************************************
1363  * DllGetVersion              [MSI.@]
1364  */
1365 HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi)
1366 {
1367     TRACE("%p\n",pdvi);
1368
1369     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
1370         return E_INVALIDARG;
1371
1372     pdvi->dwMajorVersion = MSI_MAJORVERSION;
1373     pdvi->dwMinorVersion = MSI_MINORVERSION;
1374     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
1375     pdvi->dwPlatformID = 1;
1376
1377     return S_OK;
1378 }
1379
1380 /******************************************************************
1381  * DllCanUnloadNow            [MSI.@]
1382  */
1383 BOOL WINAPI MSI_DllCanUnloadNow(void)
1384 {
1385     return S_FALSE;
1386 }
1387
1388 UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature,
1389                                 DWORD* pdwUseCount, WORD* pwDateUsed)
1390 {
1391     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1392           pdwUseCount, pwDateUsed);
1393     return ERROR_CALL_NOT_IMPLEMENTED;
1394 }
1395
1396 UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature,
1397                                 DWORD* pdwUseCount, WORD* pwDateUsed)
1398 {
1399     FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1400           pdwUseCount, pwDateUsed);
1401     return ERROR_CALL_NOT_IMPLEMENTED;
1402 }
1403
1404 INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature,
1405                              DWORD dwInstallMode, DWORD dwReserved)
1406 {
1407     FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1408           dwInstallMode, dwReserved);
1409
1410     /*
1411      * Polls all the components of the feature to find install state and then
1412      *  writes:
1413      *    Software\\Microsoft\\Windows\\CurrentVersion\\
1414      *    Installer\\Products\\<squishguid>\\<feature>
1415      *      "Usage"=dword:........
1416      */
1417
1418     return INSTALLSTATE_LOCAL;
1419 }
1420
1421 /***********************************************************************
1422  * MsiUseFeatureExA           [MSI.@]
1423  */
1424 INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature,
1425                              DWORD dwInstallMode, DWORD dwReserved)
1426 {
1427     FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1428           dwInstallMode, dwReserved);
1429
1430     return INSTALLSTATE_LOCAL;
1431 }
1432
1433 INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature)
1434 {
1435     FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1436
1437     return INSTALLSTATE_LOCAL;
1438 }
1439
1440 INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature)
1441 {
1442     FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature));
1443
1444     return INSTALLSTATE_LOCAL;
1445 }
1446
1447 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1448                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1449                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1450                 DWORD* pcchPathBuf)
1451 {
1452     HKEY hkey;
1453     UINT rc;
1454     LPWSTR info;
1455     DWORD sz;
1456     LPWSTR product = NULL;
1457     LPWSTR component = NULL;
1458     LPWSTR ptr;
1459     GUID clsid;
1460
1461     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
1462           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1463           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1464    
1465     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1466     if (rc != ERROR_SUCCESS)
1467         return ERROR_INDEX_ABSENT;
1468
1469     sz = 0;
1470     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
1471     if (sz <= 0)
1472     {
1473         RegCloseKey(hkey);
1474         return ERROR_INDEX_ABSENT;
1475     }
1476
1477     info = HeapAlloc(GetProcessHeap(),0,sz);
1478     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
1479     if (rc != ERROR_SUCCESS)
1480     {
1481         RegCloseKey(hkey);
1482         HeapFree(GetProcessHeap(),0,info);
1483         return ERROR_INDEX_ABSENT;
1484     }
1485
1486     /* find the component */
1487     ptr = strchrW(&info[20],'>');
1488     if (ptr)
1489         ptr++;
1490     else
1491     {
1492         RegCloseKey(hkey);
1493         HeapFree(GetProcessHeap(),0,info);
1494         return ERROR_INDEX_ABSENT;
1495     }
1496
1497     if (!szProduct)
1498     {
1499         decode_base85_guid(info,&clsid);
1500         StringFromCLSID(&clsid, &product);
1501     }
1502     decode_base85_guid(ptr,&clsid);
1503     StringFromCLSID(&clsid, &component);
1504
1505     if (!szProduct)
1506         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
1507     else
1508         rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
1509    
1510     RegCloseKey(hkey);
1511     HeapFree(GetProcessHeap(),0,info);
1512     HeapFree(GetProcessHeap(),0,product);
1513     HeapFree(GetProcessHeap(),0,component);
1514
1515     if (rc == INSTALLSTATE_LOCAL)
1516         return ERROR_SUCCESS;
1517     else 
1518         return ERROR_FILE_NOT_FOUND;
1519 }
1520
1521 /***********************************************************************
1522  * MsiProvideQualifiedComponentW [MSI.@]
1523  */
1524 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1525                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1526                 DWORD* pcchPathBuf)
1527 {
1528     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1529                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1530 }
1531
1532 /***********************************************************************
1533  * MsiProvideQualifiedComponentA [MSI.@]
1534  */
1535 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1536                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1537                 DWORD* pcchPathBuf)
1538 {
1539     LPWSTR szwComponent, szwQualifier, lpwPathBuf;
1540     DWORD pcchwPathBuf;
1541     UINT rc;
1542
1543     TRACE("%s %s %li %p %p\n",szComponent, szQualifier,
1544                     dwInstallMode, lpPathBuf, pcchPathBuf);
1545
1546     szwComponent= strdupAtoW( szComponent);
1547     szwQualifier= strdupAtoW( szQualifier);
1548
1549     lpwPathBuf = HeapAlloc(GetProcessHeap(),0,*pcchPathBuf * sizeof(WCHAR));
1550
1551     pcchwPathBuf = *pcchPathBuf;
1552
1553     rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, 
1554                     dwInstallMode, lpwPathBuf, &pcchwPathBuf);
1555
1556     HeapFree(GetProcessHeap(),0,szwComponent);
1557     HeapFree(GetProcessHeap(),0,szwQualifier);
1558     *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf,
1559                     lpPathBuf, *pcchPathBuf, NULL, NULL);
1560
1561     HeapFree(GetProcessHeap(),0,lpwPathBuf);
1562     return rc;
1563 }
1564
1565 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf,
1566                 DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf,
1567                 DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1568 {
1569     HKEY hkey;
1570     DWORD sz;
1571     UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS;
1572     static const WCHAR szOwner[] = {'R','e','g','O','w','n','e','r',0};
1573     static const WCHAR szCompany[] = {'R','e','g','C','o','m','p','a','n','y',0};
1574     static const WCHAR szSerial[] = {'P','r','o','d','u','c','t','I','D',0};
1575
1576     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1577           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1578           pcchSerialBuf);
1579
1580     rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1581     if (rc != ERROR_SUCCESS)
1582         return USERINFOSTATE_UNKNOWN;
1583
1584     if (lpUserNameBuf)
1585     {
1586         sz = *lpUserNameBuf * sizeof(WCHAR);
1587         rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, (LPBYTE)lpUserNameBuf,
1588                                &sz);
1589     }
1590     if (!lpUserNameBuf && pcchUserNameBuf)
1591     {
1592         sz = 0;
1593         rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, NULL, &sz);
1594     }
1595
1596     if (pcchUserNameBuf)
1597         *pcchUserNameBuf = sz / sizeof(WCHAR);
1598
1599     if (lpOrgNameBuf)
1600     {
1601         sz = *pcchOrgNameBuf * sizeof(WCHAR);
1602         rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, 
1603                                (LPBYTE)lpOrgNameBuf, &sz);
1604     }
1605     if (!lpOrgNameBuf && pcchOrgNameBuf)
1606     {
1607         sz = 0;
1608         rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, NULL, &sz);
1609     }
1610
1611     if (pcchOrgNameBuf)
1612         *pcchOrgNameBuf = sz / sizeof(WCHAR);
1613
1614     if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && 
1615         rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA)
1616     {
1617         RegCloseKey(hkey);
1618         return USERINFOSTATE_ABSENT;
1619     }
1620
1621     if (lpSerialBuf)
1622     {
1623         sz = *pcchSerialBuf * sizeof(WCHAR);
1624         RegQueryValueExW( hkey, szSerial, NULL, NULL, (LPBYTE)lpSerialBuf,
1625                                &sz);
1626     }
1627     if (!lpSerialBuf && pcchSerialBuf)
1628     {
1629         sz = 0;
1630         rc = RegQueryValueExW( hkey, szSerial, NULL, NULL, NULL, &sz);
1631     }
1632     if (pcchSerialBuf)
1633         *pcchSerialBuf = sz / sizeof(WCHAR);
1634     
1635     RegCloseKey(hkey);
1636     return USERINFOSTATE_PRESENT;
1637 }
1638
1639 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf,
1640                 DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf,
1641                 DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1642 {
1643     FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf,
1644           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1645           pcchSerialBuf);
1646
1647     return USERINFOSTATE_UNKNOWN;
1648 }
1649
1650 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1651 {
1652     MSIHANDLE handle;
1653     UINT rc;
1654     MSIPACKAGE *package;
1655     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1656
1657     TRACE("(%s)\n",debugstr_w(szProduct));
1658
1659     rc = MsiOpenProductW(szProduct,&handle);
1660     if (rc != ERROR_SUCCESS)
1661         return ERROR_INVALID_PARAMETER;
1662
1663     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1664     rc = ACTION_PerformUIAction(package, szFirstRun);
1665     msiobj_release( &package->hdr );
1666
1667     MsiCloseHandle(handle);
1668
1669     return rc;
1670 }
1671
1672 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1673 {
1674     MSIHANDLE handle;
1675     UINT rc;
1676     MSIPACKAGE *package;
1677     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1678
1679     TRACE("(%s)\n",debugstr_a(szProduct));
1680
1681     rc = MsiOpenProductA(szProduct,&handle);
1682     if (rc != ERROR_SUCCESS)
1683         return ERROR_INVALID_PARAMETER;
1684
1685     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1686     rc = ACTION_PerformUIAction(package, szFirstRun);
1687     msiobj_release( &package->hdr );
1688
1689     MsiCloseHandle(handle);
1690
1691     return rc;
1692 }
1693
1694 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1695 {
1696     WCHAR path[MAX_PATH];
1697
1698     if(dwReserved) {
1699         FIXME("Don't know how to handle argument %ld\n", dwReserved);
1700         return ERROR_CALL_NOT_IMPLEMENTED;
1701     }
1702
1703    if(!GetWindowsDirectoryW(path, MAX_PATH)) {
1704         FIXME("GetWindowsDirectory failed unexpected! Error %ld\n",
1705               GetLastError());
1706         return ERROR_CALL_NOT_IMPLEMENTED;
1707    }
1708
1709    strcatW(path, installerW);
1710
1711    CreateDirectoryW(path, NULL);
1712
1713    return 0;
1714 }
1715
1716 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1717                                    LPSTR szProductCode, LPSTR szFeatureId,
1718                                    LPSTR szComponentCode )
1719 {
1720     FIXME("\n");
1721     return ERROR_CALL_NOT_IMPLEMENTED;
1722 }
1723
1724 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1725                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1726                                    LPWSTR szComponentCode )
1727 {
1728     FIXME("\n");
1729     return ERROR_CALL_NOT_IMPLEMENTED;
1730 }
1731
1732 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1733                                   DWORD dwReinstallMode )
1734 {
1735     FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1736                            dwReinstallMode);
1737     return ERROR_SUCCESS;
1738 }
1739
1740 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1741                                   DWORD dwReinstallMode )
1742 {
1743     FIXME("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1744                            dwReinstallMode);
1745     return ERROR_SUCCESS;
1746 }