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