Fix handle allocation and the CREATE TABLE query.
[wine] / dlls / msi / msi.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003 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
37 WINE_DEFAULT_DEBUG_CHANNEL(msi);
38
39 /*
40  * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
41  *  which is a problem because LPCTSTR isn't defined when compiling wine.
42  * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
43  *  and make sure to only use it in W functions.
44  */
45 #define LPCTSTR LPCWSTR
46
47 const WCHAR szInstaller[] = {
48 'S','o','f','t','w','a','r','e','\\',
49 'M','i','c','r','o','s','o','f','t','\\',
50 'W','i','n','d','o','w','s','\\',
51 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
52 'I','n','s','t','a','l','l','e','r',0 };
53
54 const WCHAR szFeatures[] = {
55 'F','e','a','t','u','r','e','s',0 };
56 const WCHAR szComponents[] = {
57 'C','o','m','p','o','n','e','n','t','s',0 };
58
59 /*
60  *  .MSI  file format
61  *
62  *  A .msi file is a structured storage file.
63  *  It should contain a number of streams.
64  */
65
66 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
67 {
68     DWORD i,n=0;
69
70     out[n++]='{';
71     for(i=0; i<8; i++)
72         out[n++] = in[7-i];
73     out[n++]='-';
74     for(i=0; i<4; i++)
75         out[n++] = in[11-i];
76     out[n++]='-';
77     for(i=0; i<4; i++)
78         out[n++] = in[15-i];
79     out[n++]='-';
80     for(i=0; i<2; i++)
81     {
82         out[n++] = in[17+i*2];
83         out[n++] = in[16+i*2];
84     }
85     out[n++]='-';
86     for( ; i<8; i++)
87     {
88         out[n++] = in[17+i*2];
89         out[n++] = in[16+i*2];
90     }
91     out[n++]='}';
92     out[n]=0;
93     return TRUE;
94 }
95
96 BOOL squash_guid(LPCWSTR in, LPWSTR out)
97 {
98     DWORD i,n=0;
99
100     if(in[n++] != '{')
101         return FALSE;
102     for(i=0; i<8; i++)
103         out[7-i] = in[n++];
104     if(in[n++] != '-')
105         return FALSE;
106     for(i=0; i<4; i++)
107         out[11-i] = in[n++];
108     if(in[n++] != '-')
109         return FALSE;
110     for(i=0; i<4; i++)
111         out[15-i] = in[n++];
112     if(in[n++] != '-')
113         return FALSE;
114     for(i=0; i<2; i++)
115     {
116         out[17+i*2] = in[n++];
117         out[16+i*2] = in[n++];
118     }
119     if(in[n++] != '-')
120         return FALSE;
121     for( ; i<8; i++)
122     {
123         out[17+i*2] = in[n++];
124         out[16+i*2] = in[n++];
125     }
126     out[32]=0;
127     if(in[n++] != '}')
128         return FALSE;
129     if(in[n])
130         return FALSE;
131     return TRUE;
132 }
133
134 VOID MSI_CloseDatabase( VOID *arg )
135 {
136     MSIDATABASE *db = (MSIDATABASE *) arg;
137
138     free_cached_tables( db );
139     IStorage_Release( db->storage );
140 }
141
142 UINT WINAPI MsiOpenDatabaseA(
143                LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
144 {
145     HRESULT r = ERROR_FUNCTION_FAILED;
146     LPWSTR szwDBPath = NULL, szwPersist = NULL;
147     UINT len;
148
149     TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
150
151     if( szDBPath )
152     {
153         len = MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, NULL, 0 );
154         szwDBPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
155         if( !szwDBPath )
156             goto end;
157         MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, szwDBPath, len );
158     }
159
160     if( HIWORD(szPersist) )
161     {
162         len = MultiByteToWideChar( CP_ACP, 0, szPersist, -1, NULL, 0 );
163         szwPersist = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
164         if( !szwPersist )
165             goto end;
166         MultiByteToWideChar( CP_ACP, 0, szPersist, -1, szwPersist, len );
167     }
168     else
169         szwPersist = (LPWSTR) szPersist;
170
171     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
172
173 end:
174     if( szwPersist )
175         HeapFree( GetProcessHeap(), 0, szwPersist );
176     if( szwDBPath )
177         HeapFree( GetProcessHeap(), 0, szwDBPath );
178
179     return r;
180 }
181
182 UINT WINAPI MsiOpenDatabaseW(
183               LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
184 {
185     IStorage *stg = NULL;
186     HRESULT r;
187     MSIHANDLE handle;
188     MSIDATABASE *db;
189     UINT ret;
190     LPWSTR szMode;
191
192     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
193
194     if( !phDB )
195         return ERROR_INVALID_PARAMETER;
196
197     szMode = (LPWSTR) szPersist;
198     if( HIWORD( szPersist ) )
199     {
200         /* UINT len = lstrlenW( szPerist ) + 1; */
201         FIXME("don't support persist files yet\b");
202         return ERROR_INVALID_PARAMETER;
203         /* szMode = HeapAlloc( GetProcessHeap(), 0, len * sizeof (DWORD) ); */
204     }
205     else if( szPersist == MSIDBOPEN_READONLY )
206     {
207         r = StgOpenStorage( szDBPath, NULL,
208               STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
209     }
210     else if( szPersist == MSIDBOPEN_CREATE )
211     {
212         r = StgCreateDocfile( szDBPath, 
213               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
214         if( r == ERROR_SUCCESS )
215             r = init_string_table( stg );
216     }
217     else if( szPersist == MSIDBOPEN_TRANSACT )
218     {
219         r = StgOpenStorage( szDBPath, NULL,
220               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
221     }
222     else
223     {
224         ERR("unknown flag %p\n",szPersist);
225         return ERROR_INVALID_PARAMETER;
226     }
227
228     if( FAILED( r ) )
229     {
230         FIXME("open failed r = %08lx!\n",r);
231         return ERROR_FUNCTION_FAILED;
232     }
233
234     handle = alloc_msihandle( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
235                               MSI_CloseDatabase, (void**) &db );
236     if( !handle )
237     {
238         FIXME("Failed to allocate a handle\n");
239         ret = ERROR_FUNCTION_FAILED;
240         goto end;
241     }
242
243     db->storage = stg;
244     db->mode = szMode;
245     /* db->strings = NULL;
246     db->first_table = NULL;
247     db->last_table = NULL; */
248
249     ret = load_string_table( db );
250     if( ret != ERROR_SUCCESS )
251         goto end;
252
253     *phDB = handle;
254
255     IStorage_AddRef( stg );
256 end:
257     if( stg )
258         IStorage_Release( stg );
259
260     return ret;
261 }
262
263 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
264 {
265     UINT len, ret;
266     LPWSTR szwProd = NULL;
267
268     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
269
270     if( szProduct )
271     {
272         len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
273         szwProd = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
274         if( szwProd )
275             MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProd, len );
276     }
277
278     ret = MsiOpenProductW( szwProd, phProduct );
279
280     if( szwProd )
281         HeapFree( GetProcessHeap(), 0, szwProd );
282
283     return ret;
284 }
285
286 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
287 {
288     const WCHAR szKey[] = {
289         'S','o','f','t','w','a','r','e','\\',
290         'M','i','c','r','o','s','o','f','t','\\',
291         'W','i','n','d','o','w','s','\\',
292         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
293         'U','n','i','n','s','t','a','l','l',0 };
294     const WCHAR szLocalPackage[] = {
295         'L','o','c','a','l','P','a','c','k','a','g','e', 0
296     };
297     LPWSTR path = NULL;
298     UINT r;
299     HKEY hKeyProduct = NULL, hKeyUninstall = NULL;
300     DWORD count, type;
301
302     TRACE("%s %p\n",debugstr_w(szProduct), phProduct);
303
304     r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szKey, &hKeyUninstall );
305     if( r != ERROR_SUCCESS )
306         return r;
307
308     r = RegOpenKeyW( hKeyUninstall, szProduct, &hKeyProduct );
309     if( r != ERROR_SUCCESS )
310         goto end;
311
312     /* find the size of the path */
313     type = count = 0;
314     r = RegQueryValueExW( hKeyProduct, szLocalPackage,
315                           NULL, &type, NULL, &count );
316     if( r != ERROR_SUCCESS )
317         goto end;
318
319     /* now alloc and fetch the path of the database to open */
320     path = HeapAlloc( GetProcessHeap(), 0, count );
321     if( !path )
322         goto end;
323
324     r = RegQueryValueExW( hKeyProduct, szLocalPackage,
325                           NULL, &type, (LPBYTE) path, &count );
326     if( r != ERROR_SUCCESS )
327         goto end;
328
329     r = MsiOpenPackageW( path, phProduct );
330
331 end:
332     if( path )
333         HeapFree( GetProcessHeap(), 0, path );
334     if( hKeyProduct )
335         RegCloseKey( hKeyProduct );
336     RegCloseKey( hKeyUninstall );
337
338     return r;
339 }
340
341 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
342 {
343     FIXME("%s %p\n",debugstr_a(szPackage), phPackage);
344     return ERROR_CALL_NOT_IMPLEMENTED;
345 }
346
347 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
348 {
349     FIXME("%s %p\n",debugstr_w(szPackage), phPackage);
350     return ERROR_CALL_NOT_IMPLEMENTED;
351 }
352
353 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
354 {
355     FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
356     return ERROR_CALL_NOT_IMPLEMENTED;
357 }
358
359 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
360 {
361     FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
362     return ERROR_CALL_NOT_IMPLEMENTED;
363 }
364
365 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage)
366 {
367     FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
368     return ERROR_CALL_NOT_IMPLEMENTED;
369 }
370
371 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage)
372 {
373     FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
374     return ERROR_CALL_NOT_IMPLEMENTED;
375 }
376
377 UINT WINAPI MsiAdvertiseProductExA(
378     LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
379 {
380     FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
381         debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions);
382     return ERROR_CALL_NOT_IMPLEMENTED;
383 }
384
385 UINT WINAPI MsiAdvertiseProductExW(
386     LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
387 {
388     FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
389         debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions);
390     return ERROR_CALL_NOT_IMPLEMENTED;
391 }
392
393 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
394 {
395     LPWSTR szwPath = NULL, szwCommand = NULL;
396     UINT r = ERROR_FUNCTION_FAILED; /* FIXME: check return code */
397
398     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
399
400     if( szPackagePath )
401     {
402         UINT len = MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, NULL, 0 );
403         szwPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
404         if( !szwPath )
405             goto end;
406         MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, szwPath, len );
407     }
408
409     if( szCommandLine )
410     {
411         UINT len = MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, NULL, 0 );
412         szwCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
413         if( !szwCommand )
414             goto end;
415         MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, szwCommand, len );
416     }
417  
418     r = MsiInstallProductW( szwPath, szwCommand );
419
420 end:
421     if( szwPath )
422         HeapFree( GetProcessHeap(), 0, szwPath );
423     
424     if( szwCommand )
425         HeapFree( GetProcessHeap(), 0, szwCommand );
426
427     return r;
428 }
429
430 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
431 {
432     FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
433
434     return ERROR_CALL_NOT_IMPLEMENTED;
435 }
436
437 UINT WINAPI MsiConfigureProductA(
438               LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
439 {
440     FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
441     return ERROR_CALL_NOT_IMPLEMENTED;
442 }
443
444 UINT WINAPI MsiConfigureProductW(
445               LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
446 {
447     FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState);
448     return ERROR_CALL_NOT_IMPLEMENTED;
449 }
450
451 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
452 {
453     FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
454     return ERROR_CALL_NOT_IMPLEMENTED;
455 }
456
457 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
458 {
459     FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer));
460     return ERROR_CALL_NOT_IMPLEMENTED;
461 }
462
463 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf)
464 {
465     FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf);
466     return ERROR_CALL_NOT_IMPLEMENTED;
467 }
468
469 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf)
470 {
471     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf);
472     return ERROR_CALL_NOT_IMPLEMENTED;
473 }
474
475 UINT WINAPI MsiDatabaseImportA(LPCSTR szFolderPath, LPCSTR szFilename)
476 {
477     FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename));
478     return ERROR_CALL_NOT_IMPLEMENTED;
479 }
480
481 UINT WINAPI MsiDatabaseImportW(LPCWSTR szFolderPath, LPCWSTR szFilename)
482 {
483     FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename));
484     return ERROR_CALL_NOT_IMPLEMENTED;
485 }
486
487 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, BOOL fAppend)
488 {
489     FIXME("%08lx %s %d\n", dwLogMode, debugstr_a(szLogFile), fAppend);
490     return ERROR_SUCCESS;
491     /* return ERROR_CALL_NOT_IMPLEMENTED; */
492 }
493
494 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, BOOL fAppend)
495 {
496     FIXME("%08lx %s %d\n", dwLogMode, debugstr_w(szLogFile), fAppend);
497     return ERROR_CALL_NOT_IMPLEMENTED;
498 }
499
500 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
501 {
502     FIXME("%s\n", debugstr_a(szProduct));
503     return INSTALLSTATE_UNKNOWN;
504 }
505
506 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
507 {
508     FIXME("%s\n", debugstr_w(szProduct));
509     return INSTALLSTATE_UNKNOWN;
510 }
511
512 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
513 {
514     FIXME("%08x %p\n", dwUILevel, phWnd);
515     return dwUILevel;
516 }
517
518 UINT WINAPI MsiLoadStringA(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
519 {
520     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
521     return ERROR_CALL_NOT_IMPLEMENTED;
522 }
523
524 UINT WINAPI MsiLoadStringW(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
525 {
526     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
527     return ERROR_CALL_NOT_IMPLEMENTED;
528 }
529
530 UINT WINAPI MsiMessageBoxA(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
531 {
532     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
533     return ERROR_CALL_NOT_IMPLEMENTED;
534 }
535
536 UINT WINAPI MsiMessageBoxW(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
537 {
538     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
539     return ERROR_CALL_NOT_IMPLEMENTED;
540 }
541
542 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
543 {
544     DWORD r;
545     WCHAR szwGuid[GUID_SIZE];
546
547     TRACE("%ld %p\n",index,lpguid);
548
549     r = MsiEnumProductsW(index, szwGuid);
550     if( r == ERROR_SUCCESS )
551         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
552
553     return r;
554 }
555
556 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
557 {
558     HKEY hkey = 0, hkeyFeatures = 0;
559     DWORD r;
560     WCHAR szKeyName[33];
561
562     TRACE("%ld %p\n",index,lpguid);
563
564     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
565     if( r != ERROR_SUCCESS )
566         goto end;
567
568     r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
569     if( r != ERROR_SUCCESS )
570         goto end;
571
572     r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE);
573
574     unsquash_guid(szKeyName, lpguid);
575
576 end:
577
578     if( hkeyFeatures )
579         RegCloseKey(hkeyFeatures);
580     if( hkey )
581         RegCloseKey(hkey);
582
583     return r;
584 }
585
586 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
587       LPSTR szFeature, LPSTR szParent)
588 {
589     DWORD r;
590     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
591     LPWSTR szwProduct = NULL;
592
593     TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent);
594
595     if( szProduct )
596     {
597         UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
598         szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
599         if( szwProduct )
600             MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
601         else
602             return ERROR_FUNCTION_FAILED;
603     }
604
605     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
606     if( r == ERROR_SUCCESS )
607     {
608         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
609                             szFeature, GUID_SIZE, NULL, NULL);
610         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
611                             szParent, GUID_SIZE, NULL, NULL);
612     }
613
614     if( szwProduct )
615         HeapFree( GetProcessHeap(), 0, szwProduct);
616
617     return r;
618 }
619
620 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
621       LPWSTR szFeature, LPWSTR szParent)
622 {
623     HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0;
624     DWORD r, sz;
625     WCHAR szRegName[GUID_SIZE];
626
627     TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
628
629     if( !squash_guid(szProduct, szRegName) )
630         return ERROR_INVALID_PARAMETER;
631
632     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
633     if( r != ERROR_SUCCESS )
634         goto end;
635
636     r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
637     if( r != ERROR_SUCCESS )
638         goto end;
639
640     r = RegOpenKeyW(hkeyFeatures, szRegName, &hkeyProduct);
641     if( r != ERROR_SUCCESS )
642         goto end;
643
644     sz = GUID_SIZE;
645     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
646
647 end:
648     if( hkeyProduct )
649         RegCloseKey(hkeyProduct);
650     if( hkeyFeatures )
651         RegCloseKey(hkeyFeatures);
652     if( hkey )
653         RegCloseKey(hkey);
654
655     return r;
656 }
657
658 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
659 {
660     DWORD r;
661     WCHAR szwGuid[GUID_SIZE];
662
663     TRACE("%ld %p\n",index,lpguid);
664
665     r = MsiEnumComponentsW(index, szwGuid);
666     if( r == ERROR_SUCCESS )
667         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
668
669     return r;
670 }
671
672 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
673 {
674     HKEY hkey = 0, hkeyComponents = 0;
675     DWORD r;
676     WCHAR szKeyName[33];
677
678     TRACE("%ld %p\n",index,lpguid);
679
680     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
681     if( r != ERROR_SUCCESS )
682         goto end;
683
684     r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
685     if( r != ERROR_SUCCESS )
686         goto end;
687
688     r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE);
689
690     unsquash_guid(szKeyName, lpguid);
691
692 end:
693
694     if( hkeyComponents )
695         RegCloseKey(hkeyComponents);
696     if( hkey )
697         RegCloseKey(hkey);
698
699     return r;
700 }
701
702 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
703 {
704     DWORD r;
705     WCHAR szwProduct[GUID_SIZE];
706     LPWSTR szwComponent = NULL;
707
708     TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct);
709
710     if( szComponent )
711     {
712         UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 );
713         szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
714         if( szwComponent )
715             MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len );
716         else
717             return ERROR_FUNCTION_FAILED;
718     }
719
720     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
721     if( r == ERROR_SUCCESS )
722     {
723         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
724                             szProduct, GUID_SIZE, NULL, NULL);
725     }
726
727     if( szwComponent )
728         HeapFree( GetProcessHeap(), 0, szwComponent);
729
730     return r;
731 }
732
733 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
734 {
735     HKEY hkey = 0, hkeyComponents = 0, hkeyComp = 0;
736     DWORD r, sz;
737     WCHAR szRegName[GUID_SIZE], szValName[GUID_SIZE];
738
739     TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct);
740
741     if( !squash_guid(szComponent, szRegName) )
742         return ERROR_INVALID_PARAMETER;
743
744     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
745     if( r != ERROR_SUCCESS )
746         goto end;
747
748     r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
749     if( r != ERROR_SUCCESS )
750         goto end;
751
752     r = RegOpenKeyW(hkeyComponents, szRegName, &hkeyComp);
753     if( r != ERROR_SUCCESS )
754         goto end;
755
756     sz = GUID_SIZE;
757     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
758     if( r != ERROR_SUCCESS )
759         goto end;
760
761     unsquash_guid(szValName, szProduct);
762
763 end:
764     if( hkeyComp )
765         RegCloseKey(hkeyComp);
766     if( hkeyComponents )
767         RegCloseKey(hkeyComponents);
768     if( hkey )
769         RegCloseKey(hkey);
770
771     return r;
772 }
773
774 UINT WINAPI MsiEnumComponentQualifiersA(
775     LPSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
776 {
777 FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf);
778     return ERROR_CALL_NOT_IMPLEMENTED;
779 }
780
781 UINT WINAPI MsiEnumComponentQualifiersW(
782     LPWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
783 {
784 FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf);
785     return ERROR_CALL_NOT_IMPLEMENTED;
786 }
787
788 UINT WINAPI MsiProvideAssemblyA(
789     LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf) 
790 {
791     FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", 
792         debugstr_a(szAssemblyName),  debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf);
793     return ERROR_CALL_NOT_IMPLEMENTED;
794 }
795
796 UINT WINAPI MsiProvideAssemblyW(
797     LPCWSTR szAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, DWORD* pcchPathBuf) 
798 {
799     FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", 
800         debugstr_w(szAssemblyName),  debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf);
801     return ERROR_CALL_NOT_IMPLEMENTED;
802 }
803
804 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
805 {
806     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
807     return ERROR_CALL_NOT_IMPLEMENTED;
808 }
809
810 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
811 {
812     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
813     return ERROR_CALL_NOT_IMPLEMENTED;
814 }
815
816 HRESULT WINAPI MsiGetFileSignatureInformationA(
817   LPCSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData)
818 {
819     FIXME("%s 0x%08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData);
820     return ERROR_CALL_NOT_IMPLEMENTED;
821 }
822
823 HRESULT WINAPI MsiGetFileSignatureInformationW(
824   LPCWSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData)
825 {
826     FIXME("%s 0x%08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData);
827     return ERROR_CALL_NOT_IMPLEMENTED;
828 }
829
830 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
831                                     LPSTR szValue, DWORD *pccbValue )
832 {
833     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
834     return ERROR_CALL_NOT_IMPLEMENTED;
835 }
836
837 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
838                                     LPWSTR szValue, DWORD *pccbValue )
839 {
840     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
841     return ERROR_CALL_NOT_IMPLEMENTED;
842 }
843
844 UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage )
845 {
846     FIXME("%s\n", debugstr_a(szPackage) );
847     return ERROR_CALL_NOT_IMPLEMENTED;
848 }
849
850 UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage )
851 {
852     FIXME("%s\n", debugstr_w(szPackage) );
853     return ERROR_CALL_NOT_IMPLEMENTED;
854 }
855
856 HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi)
857 {
858     TRACE("%p\n",pdvi);
859
860     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
861         return E_INVALIDARG;
862
863     pdvi->dwMajorVersion = MSI_MAJORVERSION;
864     pdvi->dwMinorVersion = MSI_MINORVERSION;
865     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
866     pdvi->dwPlatformID = 1;
867
868     return S_OK;
869 }
870
871 BOOL WINAPI MSI_DllCanUnloadNow(void)
872 {
873     return FALSE;
874 }
875
876 HRESULT WINAPI MSI_DllRegisterServer(void)
877 {
878     FIXME("Stub!\n");
879     return S_OK;
880 }