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