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