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