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