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