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