Use shell icon cache instead of an own IExtractIcon implementation.
[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, 1(one) if per machine.\n");
578         if (szBuffer)
579             szBuffer[0] = 1;
580         if (pcchValueBuf)
581             *pcchValueBuf = 1;
582         r = ERROR_SUCCESS;
583     }
584     else if (strcmpW(szAttribute, szLanguage)==0)
585     {
586         r = MsiOpenProductW(szProduct, &hProduct);
587         if (ERROR_SUCCESS != r)
588             return r;
589
590         r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
591         MsiCloseHandle(hProduct);
592     }
593     else
594     {
595         r = MsiOpenProductW(szProduct, &hProduct);
596         if (ERROR_SUCCESS != r)
597             return r;
598
599         r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
600         MsiCloseHandle(hProduct);
601     }
602
603     return r;
604 }
605
606 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
607 {
608     LPWSTR szwLogFile = NULL;
609     UINT r;
610
611     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes);
612
613     if( szLogFile )
614     {
615         szwLogFile = strdupAtoW( szLogFile );
616         if( !szwLogFile )
617             return ERROR_OUTOFMEMORY;
618     }
619     r = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
620     HeapFree( GetProcessHeap(), 0, szwLogFile );
621     return r;
622 }
623
624 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
625 {
626     HANDLE file = INVALID_HANDLE_VALUE;
627
628     TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes);
629
630     lstrcpyW(gszLogFile,szLogFile);
631     if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
632         DeleteFileW(szLogFile);
633     file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
634                            FILE_ATTRIBUTE_NORMAL, NULL);
635     if (file != INVALID_HANDLE_VALUE)
636         CloseHandle(file);
637     else
638         ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
639
640     return ERROR_SUCCESS;
641 }
642
643 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
644 {
645     LPWSTR szwProduct = NULL;
646     INSTALLSTATE r;
647
648     if( szProduct )
649     {
650          szwProduct = strdupAtoW( szProduct );
651          if( !szwProduct )
652              return ERROR_OUTOFMEMORY;
653     }
654     r = MsiQueryProductStateW( szwProduct );
655     HeapFree( GetProcessHeap(), 0, szwProduct );
656     return r;
657 }
658
659 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
660 {
661     UINT rc;
662     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
663     HKEY hkey = 0;
664     static const WCHAR szWindowsInstaller[] = {
665          'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 };
666     DWORD sz;
667
668     TRACE("%s\n", debugstr_w(szProduct));
669
670     rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE);
671     if (rc != ERROR_SUCCESS)
672         goto end;
673
674     RegCloseKey(hkey);
675
676     rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE);
677     if (rc != ERROR_SUCCESS)
678         goto end;
679
680     sz = sizeof(rrc);
681     rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz);
682     if (rc != ERROR_SUCCESS)
683         goto end;
684
685     switch (rrc)
686     {
687     case 1:
688         /* default */
689         rrc = INSTALLSTATE_DEFAULT;
690         break;
691     default:
692         FIXME("Unknown install state read from registry (%i)\n",rrc);
693         rrc = INSTALLSTATE_UNKNOWN;
694         break;
695     }
696 end:
697     RegCloseKey(hkey);
698     return rrc;
699 }
700
701 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
702 {
703     INSTALLUILEVEL old = gUILevel;
704     HWND oldwnd = gUIhwnd;
705
706     TRACE("%08x %p\n", dwUILevel, phWnd);
707
708     gUILevel = dwUILevel;
709     if (phWnd)
710     {
711         gUIhwnd = *phWnd;
712         *phWnd = oldwnd;
713     }
714     return old;
715 }
716
717 INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
718                                   DWORD dwMessageFilter, LPVOID pvContext)
719 {
720     INSTALLUI_HANDLERA prev = gUIHandlerA;
721
722     TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext);
723     gUIHandlerA = puiHandler;
724     gUIFilter = dwMessageFilter;
725     gUIContext = pvContext;
726
727     return prev;
728 }
729
730 INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler,
731                                   DWORD dwMessageFilter, LPVOID pvContext)
732 {
733     INSTALLUI_HANDLERW prev = gUIHandlerW;
734
735     TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext);
736     gUIHandlerW = puiHandler;
737     gUIFilter = dwMessageFilter;
738     gUIContext = pvContext;
739
740     return prev;
741 }
742
743 /******************************************************************
744  *  MsiLoadStringW            [MSI.@]
745  *
746  * Loads a string from MSI's string resources.
747  *
748  * PARAMS
749  *
750  *   handle        [I]  only -1 is handled currently
751  *   id            [I]  id of the string to be loaded
752  *   lpBuffer      [O]  buffer for the string to be written to
753  *   nBufferMax    [I]  maximum size of the buffer in characters
754  *   lang          [I]  the preferred language for the string
755  *
756  * RETURNS
757  *
758  *   If successful, this function returns the language id of the string loaded
759  *   If the function fails, the function returns zero.
760  *
761  * NOTES
762  *
763  *   The type of the first parameter is unknown.  LoadString's prototype
764  *  suggests that it might be a module handle.  I have made it an MSI handle
765  *  for starters, as -1 is an invalid MSI handle, but not an invalid module
766  *  handle.  Maybe strings can be stored in an MSI database somehow.
767  */
768 LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer,
769                 int nBufferMax, LANGID lang )
770 {
771     HRSRC hres;
772     HGLOBAL hResData;
773     LPWSTR p;
774     DWORD i, len;
775
776     TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang);
777
778     if( handle != -1 )
779         FIXME("don't know how to deal with handle = %08lx\n", handle);
780
781     if( !lang )
782         lang = GetUserDefaultLangID();
783
784     hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING,
785                             (LPWSTR)1, lang );
786     if( !hres )
787         return 0;
788     hResData = LoadResource( msi_hInstance, hres );
789     if( !hResData )
790         return 0;
791     p = LockResource( hResData );
792     if( !p )
793         return 0;
794
795     for (i = 0; i < (id&0xf); i++)
796         p += *p + 1;
797     len = *p;
798
799     if( nBufferMax <= len )
800         return 0;
801
802     memcpy( lpBuffer, p+1, len * sizeof(WCHAR));
803     lpBuffer[ len ] = 0;
804
805     TRACE("found -> %s\n", debugstr_w(lpBuffer));
806
807     return lang;
808 }
809
810 LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer,
811                 int nBufferMax, LANGID lang )
812 {
813     LPWSTR bufW;
814     LANGID r;
815     DWORD len;
816
817     bufW = HeapAlloc(GetProcessHeap(), 0, nBufferMax*sizeof(WCHAR));
818     r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang);
819     if( r )
820     {
821         len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL );
822         if( len <= nBufferMax )
823             WideCharToMultiByte( CP_ACP, 0, bufW, -1,
824                                  lpBuffer, nBufferMax, NULL, NULL );
825         else
826             r = 0;
827     }
828     HeapFree(GetProcessHeap(), 0, bufW);
829     return r;
830 }
831
832 INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
833                 DWORD *pcchBuf)
834 {
835     FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf);
836     return INSTALLSTATE_UNKNOWN;
837 }
838
839 INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
840                 DWORD *pcchBuf)
841 {
842     FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf);
843     return INSTALLSTATE_UNKNOWN;
844 }
845
846 UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType,
847                 WORD wLanguageId, DWORD f)
848 {
849     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),
850           uType,wLanguageId,f);
851     return ERROR_CALL_NOT_IMPLEMENTED;
852 }
853
854 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
855                 WORD wLanguageId, DWORD f)
856 {
857     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),
858           uType,wLanguageId,f);
859     return ERROR_CALL_NOT_IMPLEMENTED;
860 }
861
862 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
863                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf,
864                 DWORD* pcchPathBuf )
865 {
866     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName),
867           debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
868           pcchPathBuf);
869     return ERROR_CALL_NOT_IMPLEMENTED;
870 }
871
872 UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext,
873                 DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf,
874                 DWORD* pcchPathBuf )
875 {
876     FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName),
877           debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf,
878           pcchPathBuf);
879     return ERROR_CALL_NOT_IMPLEMENTED;
880 }
881
882 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor,
883                 LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
884 {
885     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
886     return ERROR_CALL_NOT_IMPLEMENTED;
887 }
888
889 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor,
890                 LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
891 {
892     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
893     return ERROR_CALL_NOT_IMPLEMENTED;
894 }
895
896 HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath,
897                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
898                 DWORD* pcbHashData)
899 {
900     FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags,
901           ppcCertContext, pbHashData, pcbHashData);
902     return ERROR_CALL_NOT_IMPLEMENTED;
903 }
904
905 HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath,
906                 DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData,
907                 DWORD* pcbHashData)
908 {
909     FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags,
910           ppcCertContext, pbHashData, pcbHashData);
911     return ERROR_CALL_NOT_IMPLEMENTED;
912 }
913
914 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
915                                     LPSTR szValue, DWORD *pccbValue )
916 {
917     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
918     return ERROR_CALL_NOT_IMPLEMENTED;
919 }
920
921 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
922                                     LPWSTR szValue, DWORD *pccbValue )
923 {
924     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
925     return ERROR_CALL_NOT_IMPLEMENTED;
926 }
927
928 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
929 {
930     UINT r;
931     LPWSTR szPack = NULL;
932
933     TRACE("%s\n", debugstr_a(szPackage) );
934
935     if( szPackage )
936     {
937         szPack = strdupAtoW( szPackage );
938         if( !szPack )
939             return ERROR_OUTOFMEMORY;
940     }
941
942     r = MsiVerifyPackageW( szPack );
943
944     HeapFree( GetProcessHeap(), 0, szPack );
945
946     return r;
947 }
948
949 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
950 {
951     MSIHANDLE handle;
952     UINT r;
953
954     TRACE("%s\n", debugstr_w(szPackage) );
955
956     r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle );
957     MsiCloseHandle( handle );
958
959     return r;
960 }
961
962 INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
963                                          LPSTR lpPathBuf, DWORD* pcchBuf)
964 {
965     LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL;
966     INSTALLSTATE rc;
967     UINT incoming_len;
968
969     if( szProduct )
970     {
971         szwProduct = strdupAtoW( szProduct );
972         if( !szwProduct)
973             return ERROR_OUTOFMEMORY;
974     }
975
976     if( szComponent )
977     {
978         szwComponent = strdupAtoW( szComponent );
979         if( !szwComponent )
980         {
981             HeapFree( GetProcessHeap(), 0, szwProduct);
982             return ERROR_OUTOFMEMORY;
983         }
984     }
985
986     if( pcchBuf && *pcchBuf > 0 )
987     {
988         lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR));
989         incoming_len = *pcchBuf;
990     }
991     else
992     {
993         lpwPathBuf = NULL;
994         incoming_len = 0;
995     }
996
997     rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
998
999     HeapFree( GetProcessHeap(), 0, szwProduct);
1000     HeapFree( GetProcessHeap(), 0, szwComponent);
1001     if (lpwPathBuf)
1002     {
1003         if (rc != INSTALLSTATE_UNKNOWN)
1004             WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len,
1005                             lpPathBuf, incoming_len, NULL, NULL);
1006         HeapFree( GetProcessHeap(), 0, lpwPathBuf);
1007     }
1008
1009     return rc;
1010 }
1011
1012 INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
1013                                          LPWSTR lpPathBuf, DWORD* pcchBuf)
1014 {
1015     WCHAR squished_pc[GUID_SIZE];
1016     UINT rc;
1017     INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN;
1018     HKEY hkey = 0;
1019     LPWSTR path = NULL;
1020     DWORD sz, type;
1021
1022     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
1023            debugstr_w(szComponent), lpPathBuf, pcchBuf);
1024
1025     if( lpPathBuf && !pcchBuf )
1026         return INSTALLSTATE_INVALIDARG;
1027
1028     squash_guid(szProduct,squished_pc);
1029
1030     rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE);
1031     if( rc != ERROR_SUCCESS )
1032         goto end;
1033
1034     RegCloseKey(hkey);
1035
1036     rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE);
1037     if( rc != ERROR_SUCCESS )
1038         goto end;
1039
1040     sz = 0;
1041     type = 0;
1042     rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz );
1043     if( rc != ERROR_SUCCESS )
1044         goto end;
1045     if( type != REG_SZ )
1046         goto end;
1047
1048     sz += sizeof(WCHAR);
1049     path = HeapAlloc( GetProcessHeap(), 0, sz );
1050     if( !path )
1051         goto end;
1052
1053     rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz );
1054     if( rc != ERROR_SUCCESS )
1055         goto end;
1056
1057     TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent),
1058            debugstr_w(szProduct), debugstr_w(path));
1059
1060     if (path[0]=='0')
1061     {
1062         FIXME("Registry entry.. check entry\n");
1063         rrc = INSTALLSTATE_LOCAL;
1064     }
1065     else
1066     {
1067         /* PROBABLY a file */
1068         if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES )
1069             rrc = INSTALLSTATE_LOCAL;
1070         else
1071             rrc = INSTALLSTATE_ABSENT;
1072     }
1073
1074     if( pcchBuf )
1075     {
1076         sz = sz / sizeof(WCHAR);
1077         if( *pcchBuf >= sz )
1078             lstrcpyW( lpPathBuf, path );
1079         *pcchBuf = sz;
1080     }
1081
1082 end:
1083     HeapFree(GetProcessHeap(), 0, path );
1084     RegCloseKey(hkey);
1085     return rrc;
1086 }
1087
1088 /******************************************************************
1089  * MsiQueryFeatureStateA      [MSI.@]
1090  */
1091 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
1092 {
1093     INSTALLSTATE rc;
1094     LPWSTR szwProduct= NULL;
1095     LPWSTR szwFeature= NULL;
1096
1097     if( szProduct )
1098     {
1099         szwProduct = strdupAtoW( szProduct );
1100         if( !szwProduct)
1101             return ERROR_OUTOFMEMORY;
1102     }
1103
1104     if( szFeature )
1105     {
1106         szwFeature = strdupAtoW( szFeature );
1107         if( !szwFeature)
1108         {
1109             HeapFree( GetProcessHeap(), 0, szwProduct);
1110             return ERROR_OUTOFMEMORY;
1111         }
1112     }
1113
1114     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
1115
1116     HeapFree( GetProcessHeap(), 0, szwProduct);
1117     HeapFree( GetProcessHeap(), 0, szwFeature);
1118
1119     return rc;
1120 }
1121
1122 /******************************************************************
1123  * MsiQueryFeatureStateW      [MSI.@]
1124  *
1125  * This does not verify that the Feature is functional. So i am only going to
1126  * check the existence of the key in the registry. This should tell me if it is
1127  * installed.
1128  */
1129 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
1130 {
1131     UINT rc;
1132     DWORD sz = 0;
1133     HKEY hkey;
1134
1135     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1136
1137     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
1138     if (rc != ERROR_SUCCESS)
1139         return INSTALLSTATE_UNKNOWN;
1140
1141     rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz);
1142     RegCloseKey(hkey);
1143
1144     if (rc == ERROR_SUCCESS)
1145         return INSTALLSTATE_LOCAL;
1146     else
1147         return INSTALLSTATE_ABSENT;
1148 }
1149
1150 /******************************************************************
1151  * MsiGetFileVersionA         [MSI.@]
1152  */
1153 UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf,
1154                 DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf)
1155 {
1156     LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL;
1157     UINT ret = ERROR_OUTOFMEMORY;
1158
1159     if( szFilePath )
1160     {
1161         szwFilePath = strdupAtoW( szFilePath );
1162         if( !szwFilePath )
1163             goto end;
1164     }
1165
1166     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1167     {
1168         lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR));
1169         if( !lpwVersionBuff )
1170             goto end;
1171     }
1172
1173     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1174     {
1175         lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR));
1176         if( !lpwLangBuff )
1177             goto end;
1178     }
1179
1180     ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf,
1181                              lpwLangBuff, pcchLangBuf);
1182
1183     if( lpwVersionBuff )
1184         WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1,
1185                             lpVersionBuf, *pcchVersionBuf, NULL, NULL);
1186     if( lpwLangBuff )
1187         WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1,
1188                             lpLangBuf, *pcchLangBuf, NULL, NULL);
1189
1190 end:
1191     HeapFree(GetProcessHeap(), 0, szwFilePath);
1192     HeapFree(GetProcessHeap(), 0, lpwVersionBuff);
1193     HeapFree(GetProcessHeap(), 0, lpwLangBuff);
1194
1195     return ret;
1196 }
1197
1198 /******************************************************************
1199  * MsiGetFileVersionW         [MSI.@]
1200  */
1201 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
1202                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
1203 {
1204     static const WCHAR szVersionResource[] = {'\\',0};
1205     static const WCHAR szVersionFormat[] = {
1206         '%','d','.','%','d','.','%','d','.','%','d',0};
1207     static const WCHAR szLangFormat[] = {'%','d',0};
1208     UINT ret = 0;
1209     DWORD dwVerLen;
1210     LPVOID lpVer = NULL;
1211     VS_FIXEDFILEINFO *ffi;
1212     UINT puLen;
1213     WCHAR tmp[32];
1214
1215     TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath),
1216           lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
1217           lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
1218
1219     dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
1220     if( !dwVerLen )
1221         return GetLastError();
1222
1223     lpVer = HeapAlloc(GetProcessHeap(), 0, dwVerLen);
1224     if( !lpVer )
1225     {
1226         ret = ERROR_OUTOFMEMORY;
1227         goto end;
1228     }
1229
1230     if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
1231     {
1232         ret = GetLastError();
1233         goto end;
1234     }
1235     if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
1236     {
1237         if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
1238             (puLen > 0) )
1239         {
1240             wsprintfW(tmp, szVersionFormat,
1241                   HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS),
1242                   HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS));
1243             lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf);
1244             *pcchVersionBuf = lstrlenW(lpVersionBuf);
1245         }
1246         else
1247         {
1248             *lpVersionBuf = 0;
1249             *pcchVersionBuf = 0;
1250         }
1251     }
1252
1253     if( lpLangBuf && pcchLangBuf && *pcchLangBuf )
1254     {
1255         DWORD lang = GetUserDefaultLangID();
1256
1257         FIXME("Retrieve language from file\n");
1258         wsprintfW(tmp, szLangFormat, lang);
1259         lstrcpynW(lpLangBuf, tmp, *pcchLangBuf);
1260         *pcchLangBuf = lstrlenW(lpLangBuf);
1261     }
1262
1263 end:
1264     HeapFree(GetProcessHeap(), 0, lpVer);
1265     return ret;
1266 }
1267
1268
1269 /******************************************************************
1270  *      DllMain
1271  */
1272 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1273 {
1274     switch(fdwReason)
1275     {
1276     case DLL_PROCESS_ATTACH:
1277         msi_hInstance = hinstDLL;
1278         DisableThreadLibraryCalls(hinstDLL);
1279         msi_dialog_register_class();
1280         break;
1281     case DLL_PROCESS_DETACH:
1282         msi_dialog_unregister_class();
1283         /* FIXME: Cleanup */
1284         break;
1285     }
1286     return TRUE;
1287 }
1288
1289 typedef struct tagIClassFactoryImpl
1290 {
1291     const IClassFactoryVtbl *lpVtbl;
1292 } IClassFactoryImpl;
1293
1294 static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
1295                 REFIID riid,LPVOID *ppobj)
1296 {
1297     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1298     FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
1299     return E_NOINTERFACE;
1300 }
1301
1302 static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
1303 {
1304     return 2;
1305 }
1306
1307 static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
1308 {
1309     return 1;
1310 }
1311
1312 static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
1313     LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
1314 {
1315     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1316
1317     FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
1318     return E_FAIL;
1319 }
1320
1321 static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
1322 {
1323     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
1324
1325     FIXME("%p %d\n", This, dolock);
1326     return S_OK;
1327 }
1328
1329 static const IClassFactoryVtbl MsiCF_Vtbl =
1330 {
1331     MsiCF_QueryInterface,
1332     MsiCF_AddRef,
1333     MsiCF_Release,
1334     MsiCF_CreateInstance,
1335     MsiCF_LockServer
1336 };
1337
1338 static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
1339
1340 /******************************************************************
1341  * DllGetClassObject          [MSI.@]
1342  */
1343 HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
1344 {
1345     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
1346
1347     if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
1348         IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
1349         IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
1350         IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
1351         IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
1352     {
1353         *ppv = (LPVOID) &Msi_CF;
1354         return S_OK;
1355     }
1356     return CLASS_E_CLASSNOTAVAILABLE;
1357 }
1358
1359 /******************************************************************
1360  * DllGetVersion              [MSI.@]
1361  */
1362 HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi)
1363 {
1364     TRACE("%p\n",pdvi);
1365
1366     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
1367         return E_INVALIDARG;
1368
1369     pdvi->dwMajorVersion = MSI_MAJORVERSION;
1370     pdvi->dwMinorVersion = MSI_MINORVERSION;
1371     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
1372     pdvi->dwPlatformID = 1;
1373
1374     return S_OK;
1375 }
1376
1377 /******************************************************************
1378  * DllCanUnloadNow            [MSI.@]
1379  */
1380 BOOL WINAPI MSI_DllCanUnloadNow(void)
1381 {
1382     return S_FALSE;
1383 }
1384
1385 UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature,
1386                                 DWORD* pdwUseCount, WORD* pwDateUsed)
1387 {
1388     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
1389           pdwUseCount, pwDateUsed);
1390     return ERROR_CALL_NOT_IMPLEMENTED;
1391 }
1392
1393 UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature,
1394                                 DWORD* pdwUseCount, WORD* pwDateUsed)
1395 {
1396     FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
1397           pdwUseCount, pwDateUsed);
1398     return ERROR_CALL_NOT_IMPLEMENTED;
1399 }
1400
1401 INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature,
1402                              DWORD dwInstallMode, DWORD dwReserved)
1403 {
1404     FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1405           dwInstallMode, dwReserved);
1406
1407     /*
1408      * Polls all the components of the feature to find install state and then
1409      *  writes:
1410      *    Software\\Microsoft\\Windows\\CurrentVersion\\
1411      *    Installer\\Products\\<squishguid>\\<feature>
1412      *      "Usage"=dword:........
1413      */
1414
1415     return INSTALLSTATE_LOCAL;
1416 }
1417
1418 /***********************************************************************
1419  * MsiUseFeatureExA           [MSI.@]
1420  */
1421 INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature,
1422                              DWORD dwInstallMode, DWORD dwReserved)
1423 {
1424     FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1425           dwInstallMode, dwReserved);
1426
1427     return INSTALLSTATE_LOCAL;
1428 }
1429
1430 INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature)
1431 {
1432     FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
1433
1434     return INSTALLSTATE_LOCAL;
1435 }
1436
1437 INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature)
1438 {
1439     FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature));
1440
1441     return INSTALLSTATE_LOCAL;
1442 }
1443
1444 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
1445                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
1446                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
1447                 DWORD* pcchPathBuf)
1448 {
1449     HKEY hkey;
1450     UINT rc;
1451     LPWSTR info;
1452     DWORD sz;
1453     LPWSTR product = NULL;
1454     LPWSTR component = NULL;
1455     LPWSTR ptr;
1456     GUID clsid;
1457
1458     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
1459           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
1460           Unused1, Unused2, lpPathBuf, pcchPathBuf);
1461    
1462     rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE);
1463     if (rc != ERROR_SUCCESS)
1464         return ERROR_INDEX_ABSENT;
1465
1466     sz = 0;
1467     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz);
1468     if (sz <= 0)
1469     {
1470         RegCloseKey(hkey);
1471         return ERROR_INDEX_ABSENT;
1472     }
1473
1474     info = HeapAlloc(GetProcessHeap(),0,sz);
1475     rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz);
1476     if (rc != ERROR_SUCCESS)
1477     {
1478         RegCloseKey(hkey);
1479         HeapFree(GetProcessHeap(),0,info);
1480         return ERROR_INDEX_ABSENT;
1481     }
1482
1483     /* find the component */
1484     ptr = strchrW(&info[20],'>');
1485     if (ptr)
1486         ptr++;
1487     else
1488     {
1489         RegCloseKey(hkey);
1490         HeapFree(GetProcessHeap(),0,info);
1491         return ERROR_INDEX_ABSENT;
1492     }
1493
1494     if (!szProduct)
1495     {
1496         decode_base85_guid(info,&clsid);
1497         StringFromCLSID(&clsid, &product);
1498     }
1499     decode_base85_guid(ptr,&clsid);
1500     StringFromCLSID(&clsid, &component);
1501
1502     if (!szProduct)
1503         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
1504     else
1505         rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf);
1506    
1507     RegCloseKey(hkey);
1508     HeapFree(GetProcessHeap(),0,info);
1509     HeapFree(GetProcessHeap(),0,product);
1510     HeapFree(GetProcessHeap(),0,component);
1511
1512     if (rc == INSTALLSTATE_LOCAL)
1513         return ERROR_SUCCESS;
1514     else 
1515         return ERROR_FILE_NOT_FOUND;
1516 }
1517
1518 /***********************************************************************
1519  * MsiProvideQualifiedComponentW [MSI.@]
1520  */
1521 UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent,
1522                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf,
1523                 DWORD* pcchPathBuf)
1524 {
1525     return MsiProvideQualifiedComponentExW(szComponent, szQualifier, 
1526                     dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf);
1527 }
1528
1529 /***********************************************************************
1530  * MsiProvideQualifiedComponentA [MSI.@]
1531  */
1532 UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent,
1533                 LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf,
1534                 DWORD* pcchPathBuf)
1535 {
1536     LPWSTR szwComponent, szwQualifier, lpwPathBuf;
1537     DWORD pcchwPathBuf;
1538     UINT rc;
1539
1540     TRACE("%s %s %li %p %p\n",szComponent, szQualifier,
1541                     dwInstallMode, lpPathBuf, pcchPathBuf);
1542
1543     szwComponent= strdupAtoW( szComponent);
1544     szwQualifier= strdupAtoW( szQualifier);
1545
1546     lpwPathBuf = HeapAlloc(GetProcessHeap(),0,*pcchPathBuf * sizeof(WCHAR));
1547
1548     pcchwPathBuf = *pcchPathBuf;
1549
1550     rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, 
1551                     dwInstallMode, lpwPathBuf, &pcchwPathBuf);
1552
1553     HeapFree(GetProcessHeap(),0,szwComponent);
1554     HeapFree(GetProcessHeap(),0,szwQualifier);
1555     *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf,
1556                     lpPathBuf, *pcchPathBuf, NULL, NULL);
1557
1558     HeapFree(GetProcessHeap(),0,lpwPathBuf);
1559     return rc;
1560 }
1561
1562 USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf,
1563                 DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf,
1564                 DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf)
1565 {
1566     HKEY hkey;
1567     DWORD sz;
1568     UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS;
1569     static const WCHAR szOwner[] = {'R','e','g','O','w','n','e','r',0};
1570     static const WCHAR szCompany[] = {'R','e','g','C','o','m','p','a','n','y',0};
1571     static const WCHAR szSerial[] = {'P','r','o','d','u','c','t','I','D',0};
1572
1573     TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf,
1574           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1575           pcchSerialBuf);
1576
1577     rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE);
1578     if (rc != ERROR_SUCCESS)
1579         return USERINFOSTATE_UNKNOWN;
1580
1581     if (lpUserNameBuf)
1582     {
1583         sz = *lpUserNameBuf * sizeof(WCHAR);
1584         rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, (LPBYTE)lpUserNameBuf,
1585                                &sz);
1586     }
1587     if (!lpUserNameBuf && pcchUserNameBuf)
1588     {
1589         sz = 0;
1590         rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, NULL, &sz);
1591     }
1592
1593     if (pcchUserNameBuf)
1594         *pcchUserNameBuf = sz / sizeof(WCHAR);
1595
1596     if (lpOrgNameBuf)
1597     {
1598         sz = *pcchOrgNameBuf * sizeof(WCHAR);
1599         rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, 
1600                                (LPBYTE)lpOrgNameBuf, &sz);
1601     }
1602     if (!lpOrgNameBuf && pcchOrgNameBuf)
1603     {
1604         sz = 0;
1605         rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, NULL, &sz);
1606     }
1607
1608     if (pcchOrgNameBuf)
1609         *pcchOrgNameBuf = sz / sizeof(WCHAR);
1610
1611     if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && 
1612         rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA)
1613     {
1614         RegCloseKey(hkey);
1615         return USERINFOSTATE_ABSENT;
1616     }
1617
1618     if (lpSerialBuf)
1619     {
1620         sz = *pcchSerialBuf * sizeof(WCHAR);
1621         RegQueryValueExW( hkey, szSerial, NULL, NULL, (LPBYTE)lpSerialBuf,
1622                                &sz);
1623     }
1624     if (!lpSerialBuf && pcchSerialBuf)
1625     {
1626         sz = 0;
1627         rc = RegQueryValueExW( hkey, szSerial, NULL, NULL, NULL, &sz);
1628     }
1629     if (pcchSerialBuf)
1630         *pcchSerialBuf = sz / sizeof(WCHAR);
1631     
1632     RegCloseKey(hkey);
1633     return USERINFOSTATE_PRESENT;
1634 }
1635
1636 USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf,
1637                 DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf,
1638                 DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf)
1639 {
1640     FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf,
1641           pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf,
1642           pcchSerialBuf);
1643
1644     return USERINFOSTATE_UNKNOWN;
1645 }
1646
1647 UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct)
1648 {
1649     MSIHANDLE handle;
1650     UINT rc;
1651     MSIPACKAGE *package;
1652     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1653
1654     TRACE("(%s)\n",debugstr_w(szProduct));
1655
1656     rc = MsiOpenProductW(szProduct,&handle);
1657     if (rc != ERROR_SUCCESS)
1658         return ERROR_INVALID_PARAMETER;
1659
1660     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1661     rc = ACTION_PerformUIAction(package, szFirstRun);
1662     msiobj_release( &package->hdr );
1663
1664     MsiCloseHandle(handle);
1665
1666     return rc;
1667 }
1668
1669 UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct)
1670 {
1671     MSIHANDLE handle;
1672     UINT rc;
1673     MSIPACKAGE *package;
1674     static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0};
1675
1676     TRACE("(%s)\n",debugstr_a(szProduct));
1677
1678     rc = MsiOpenProductA(szProduct,&handle);
1679     if (rc != ERROR_SUCCESS)
1680         return ERROR_INVALID_PARAMETER;
1681
1682     package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE);
1683     rc = ACTION_PerformUIAction(package, szFirstRun);
1684     msiobj_release( &package->hdr );
1685
1686     MsiCloseHandle(handle);
1687
1688     return rc;
1689 }
1690
1691 UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
1692 {
1693     WCHAR path[MAX_PATH];
1694
1695     if(dwReserved) {
1696         FIXME("Don't know how to handle argument %ld\n", dwReserved);
1697         return ERROR_CALL_NOT_IMPLEMENTED;
1698     }
1699
1700    if(!GetWindowsDirectoryW(path, MAX_PATH)) {
1701         FIXME("GetWindowsDirectory failed unexpected! Error %ld\n",
1702               GetLastError());
1703         return ERROR_CALL_NOT_IMPLEMENTED;
1704    }
1705
1706    strcatW(path, installerW);
1707
1708    CreateDirectoryW(path, NULL);
1709
1710    return 0;
1711 }
1712
1713 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
1714                                    LPSTR szProductCode, LPSTR szFeatureId,
1715                                    LPSTR szComponentCode )
1716 {
1717     FIXME("\n");
1718     return ERROR_CALL_NOT_IMPLEMENTED;
1719 }
1720
1721 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
1722                                    LPWSTR szProductCode, LPWSTR szFeatureId,
1723                                    LPWSTR szComponentCode )
1724 {
1725     FIXME("\n");
1726     return ERROR_CALL_NOT_IMPLEMENTED;
1727 }
1728
1729 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
1730                                   DWORD dwReinstallMode )
1731 {
1732     FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
1733                            dwReinstallMode);
1734     return ERROR_SUCCESS;
1735 }
1736
1737 UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature,
1738                                   DWORD dwReinstallMode )
1739 {
1740     FIXME("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
1741                            dwReinstallMode);
1742     return ERROR_SUCCESS;
1743 }