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