Some stub implementations.
[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( 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
161     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
162
163 end:
164     if( szwPersist )
165         HeapFree( GetProcessHeap(), 0, szwPersist );
166     if( szwDBPath )
167         HeapFree( GetProcessHeap(), 0, szwDBPath );
168
169     return r;
170 }
171
172 UINT WINAPI MsiOpenDatabaseW(
173               LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
174 {
175     IStorage *stg = NULL;
176     HRESULT r;
177     MSIHANDLE handle;
178     MSIDATABASE *db;
179     UINT ret;
180
181     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
182
183     if( !phDB )
184         return ERROR_INVALID_PARAMETER;
185
186     r = StgOpenStorage( szDBPath, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
187     if( FAILED( r ) )
188     {
189         FIXME("open failed r = %08lx!\n",r);
190         return ERROR_FUNCTION_FAILED;
191     }
192
193     handle = alloc_msihandle(MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE), MSI_CloseDatabase );
194     if( !handle )
195     {
196         FIXME("Failed to allocate a handle\n");
197         ret = ERROR_FUNCTION_FAILED;
198         goto end;
199     }
200
201     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
202     if( !db )
203     {
204         FIXME("Failed to get handle pointer \n");
205         ret = ERROR_FUNCTION_FAILED;
206         goto end;
207     }
208     db->storage = stg;
209     ret = load_string_table( db, &db->strings);
210     if( ret != ERROR_SUCCESS )
211         goto end;
212
213     *phDB = handle;
214
215     IStorage_AddRef( stg );
216 end:
217     if( stg )
218         IStorage_Release( stg );
219
220     return ret;
221 }
222
223 UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
224 {
225     UINT len, ret;
226     LPWSTR szwProd = NULL;
227
228     TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
229
230     if( szProduct )
231     {
232         len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
233         szwProd = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
234         if( szwProd )
235             MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProd, len );
236     }
237
238     ret = MsiOpenProductW( szwProd, phProduct );
239
240     if( szwProd )
241         HeapFree( GetProcessHeap(), 0, szwProd );
242
243     return ret;
244 }
245
246 UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
247 {
248     FIXME("%s %p\n",debugstr_w(szProduct), phProduct);
249     return ERROR_CALL_NOT_IMPLEMENTED;
250 }
251
252 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
253 {
254     FIXME("%s %p\n",debugstr_a(szPackage), phPackage);
255     return ERROR_CALL_NOT_IMPLEMENTED;
256 }
257
258 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
259 {
260     FIXME("%s %p\n",debugstr_w(szPackage), phPackage);
261     return ERROR_CALL_NOT_IMPLEMENTED;
262 }
263
264 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
265 {
266     FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
267     return ERROR_CALL_NOT_IMPLEMENTED;
268 }
269
270 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
271 {
272     FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
273     return ERROR_CALL_NOT_IMPLEMENTED;
274 }
275
276 UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage)
277 {
278     FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
279     return ERROR_CALL_NOT_IMPLEMENTED;
280 }
281
282 UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage)
283 {
284     FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
285     return ERROR_CALL_NOT_IMPLEMENTED;
286 }
287
288 UINT WINAPI MsiAdvertiseProductExA(
289     LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
290 {
291     FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
292         debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions);
293     return ERROR_CALL_NOT_IMPLEMENTED;
294 }
295
296 UINT WINAPI MsiAdvertiseProductExW(
297     LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
298 {
299     FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
300         debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions);
301     return ERROR_CALL_NOT_IMPLEMENTED;
302 }
303
304 UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
305 {
306     LPWSTR szwPath = NULL, szwCommand = NULL;
307     UINT r = ERROR_FUNCTION_FAILED; /* FIXME: check return code */
308
309     TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
310
311     if( szPackagePath )
312     {
313         UINT len = MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, NULL, 0 );
314         szwPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
315         if( !szwPath )
316             goto end;
317         MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, szwPath, len );
318     }
319
320     if( szCommandLine )
321     {
322         UINT len = MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, NULL, 0 );
323         szwCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
324         if( !szwCommand )
325             goto end;
326         MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, szwCommand, len );
327     }
328  
329     r = MsiInstallProductW( szwPath, szwCommand );
330
331 end:
332     if( szwPath )
333         HeapFree( GetProcessHeap(), 0, szwPath );
334     
335     if( szwCommand )
336         HeapFree( GetProcessHeap(), 0, szwCommand );
337
338     return r;
339 }
340
341 UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
342 {
343     FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
344
345     return ERROR_CALL_NOT_IMPLEMENTED;
346 }
347
348 UINT WINAPI MsiConfigureProductA(
349               LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
350 {
351     FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
352     return ERROR_CALL_NOT_IMPLEMENTED;
353 }
354
355 UINT WINAPI MsiConfigureProductW(
356               LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
357 {
358     FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState);
359     return ERROR_CALL_NOT_IMPLEMENTED;
360 }
361
362 UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
363 {
364     FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
365     return ERROR_CALL_NOT_IMPLEMENTED;
366 }
367
368 UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
369 {
370     FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer));
371     return ERROR_CALL_NOT_IMPLEMENTED;
372 }
373
374 UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf)
375 {
376     FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf);
377     return ERROR_CALL_NOT_IMPLEMENTED;
378 }
379
380 UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf)
381 {
382     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf);
383     return ERROR_CALL_NOT_IMPLEMENTED;
384 }
385
386 UINT WINAPI MsiDatabaseImportA(LPCSTR szFolderPath, LPCSTR szFilename)
387 {
388     FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename));
389     return ERROR_CALL_NOT_IMPLEMENTED;
390 }
391
392 UINT WINAPI MsiDatabaseImportW(LPCWSTR szFolderPath, LPCWSTR szFilename)
393 {
394     FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename));
395     return ERROR_CALL_NOT_IMPLEMENTED;
396 }
397
398 UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, BOOL fAppend)
399 {
400     FIXME("%08lx %s %d\n", dwLogMode, debugstr_a(szLogFile), fAppend);
401     return ERROR_SUCCESS;
402     /* return ERROR_CALL_NOT_IMPLEMENTED; */
403 }
404
405 UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, BOOL fAppend)
406 {
407     FIXME("%08lx %s %d\n", dwLogMode, debugstr_w(szLogFile), fAppend);
408     return ERROR_CALL_NOT_IMPLEMENTED;
409 }
410
411 INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
412 {
413     FIXME("%s\n", debugstr_a(szProduct));
414     return 0;
415 }
416
417 INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
418 {
419     FIXME("%s\n", debugstr_w(szProduct));
420     return 0;
421 }
422
423 INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
424 {
425     FIXME("%08x %p\n", dwUILevel, phWnd);
426     return dwUILevel;
427 }
428
429 UINT WINAPI MsiLoadStringA(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
430 {
431     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
432     return ERROR_CALL_NOT_IMPLEMENTED;
433 }
434
435 UINT WINAPI MsiLoadStringW(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
436 {
437     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
438     return ERROR_CALL_NOT_IMPLEMENTED;
439 }
440
441 UINT WINAPI MsiMessageBoxA(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
442 {
443     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
444     return ERROR_CALL_NOT_IMPLEMENTED;
445 }
446
447 UINT WINAPI MsiMessageBoxW(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
448 {
449     FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
450     return ERROR_CALL_NOT_IMPLEMENTED;
451 }
452
453 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
454 {
455     DWORD r;
456     WCHAR szwGuid[GUID_SIZE];
457
458     TRACE("%ld %p\n",index,lpguid);
459
460     r = MsiEnumProductsW(index, szwGuid);
461     if( r == ERROR_SUCCESS )
462         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
463
464     return r;
465 }
466
467 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
468 {
469     HKEY hkey = 0, hkeyFeatures = 0;
470     DWORD r;
471     WCHAR szKeyName[33];
472
473     TRACE("%ld %p\n",index,lpguid);
474
475     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
476     if( r != ERROR_SUCCESS )
477         goto end;
478
479     r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
480     if( r != ERROR_SUCCESS )
481         goto end;
482
483     r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE);
484
485     unsquash_guid(szKeyName, lpguid);
486
487 end:
488
489     if( hkeyFeatures )
490         RegCloseKey(hkeyFeatures);
491     if( hkey )
492         RegCloseKey(hkey);
493
494     return r;
495 }
496
497 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
498       LPSTR szFeature, LPSTR szParent)
499 {
500     DWORD r;
501     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
502     LPWSTR szwProduct = NULL;
503
504     TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent);
505
506     if( szProduct )
507     {
508         UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
509         szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
510         if( szwProduct )
511             MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
512         else
513             return ERROR_FUNCTION_FAILED;
514     }
515
516     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
517     if( r == ERROR_SUCCESS )
518     {
519         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
520                             szFeature, GUID_SIZE, NULL, NULL);
521         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
522                             szParent, GUID_SIZE, NULL, NULL);
523     }
524
525     if( szwProduct )
526         HeapFree( GetProcessHeap(), 0, szwProduct);
527
528     return r;
529 }
530
531 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
532       LPWSTR szFeature, LPWSTR szParent)
533 {
534     HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0;
535     DWORD r, sz;
536     WCHAR szRegName[GUID_SIZE];
537
538     TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
539
540     if( !squash_guid(szProduct, szRegName) )
541         return ERROR_INVALID_PARAMETER;
542
543     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
544     if( r != ERROR_SUCCESS )
545         goto end;
546
547     r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
548     if( r != ERROR_SUCCESS )
549         goto end;
550
551     r = RegOpenKeyW(hkeyFeatures, szRegName, &hkeyProduct);
552     if( r != ERROR_SUCCESS )
553         goto end;
554
555     sz = GUID_SIZE;
556     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
557
558 end:
559     if( hkeyProduct )
560         RegCloseKey(hkeyProduct);
561     if( hkeyFeatures )
562         RegCloseKey(hkeyFeatures);
563     if( hkey )
564         RegCloseKey(hkey);
565
566     return r;
567 }
568
569 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
570 {
571     DWORD r;
572     WCHAR szwGuid[GUID_SIZE];
573
574     TRACE("%ld %p\n",index,lpguid);
575
576     r = MsiEnumComponentsW(index, szwGuid);
577     if( r == ERROR_SUCCESS )
578         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
579
580     return r;
581 }
582
583 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
584 {
585     HKEY hkey = 0, hkeyComponents = 0;
586     DWORD r;
587     WCHAR szKeyName[33];
588
589     TRACE("%ld %p\n",index,lpguid);
590
591     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
592     if( r != ERROR_SUCCESS )
593         goto end;
594
595     r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
596     if( r != ERROR_SUCCESS )
597         goto end;
598
599     r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE);
600
601     unsquash_guid(szKeyName, lpguid);
602
603 end:
604
605     if( hkeyComponents )
606         RegCloseKey(hkeyComponents);
607     if( hkey )
608         RegCloseKey(hkey);
609
610     return r;
611 }
612
613 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
614 {
615     DWORD r;
616     WCHAR szwProduct[GUID_SIZE];
617     LPWSTR szwComponent = NULL;
618
619     TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct);
620
621     if( szComponent )
622     {
623         UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 );
624         szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
625         if( szwComponent )
626             MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len );
627         else
628             return ERROR_FUNCTION_FAILED;
629     }
630
631     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
632     if( r == ERROR_SUCCESS )
633     {
634         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
635                             szProduct, GUID_SIZE, NULL, NULL);
636     }
637
638     if( szwComponent )
639         HeapFree( GetProcessHeap(), 0, szwComponent);
640
641     return r;
642 }
643
644 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
645 {
646     HKEY hkey = 0, hkeyComponents = 0, hkeyComp = 0;
647     DWORD r, sz;
648     WCHAR szRegName[GUID_SIZE], szValName[GUID_SIZE];
649
650     TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct);
651
652     if( !squash_guid(szComponent, szRegName) )
653         return ERROR_INVALID_PARAMETER;
654
655     r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
656     if( r != ERROR_SUCCESS )
657         goto end;
658
659     r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
660     if( r != ERROR_SUCCESS )
661         goto end;
662
663     r = RegOpenKeyW(hkeyComponents, szRegName, &hkeyComp);
664     if( r != ERROR_SUCCESS )
665         goto end;
666
667     sz = GUID_SIZE;
668     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
669     if( r != ERROR_SUCCESS )
670         goto end;
671
672     unsquash_guid(szValName, szProduct);
673
674 end:
675     if( hkeyComp )
676         RegCloseKey(hkeyComp);
677     if( hkeyComponents )
678         RegCloseKey(hkeyComponents);
679     if( hkey )
680         RegCloseKey(hkey);
681
682     return r;
683 }
684
685 UINT WINAPI MsiEnumComponentQualifiersA(
686     LPSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
687 {
688 FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf);
689     return ERROR_CALL_NOT_IMPLEMENTED;
690 }
691
692 UINT WINAPI MsiEnumComponentQualifiersW(
693     LPWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
694 {
695 FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf);
696     return ERROR_CALL_NOT_IMPLEMENTED;
697 }
698
699 UINT WINAPI MsiProvideAssemblyA(
700     LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf) 
701 {
702     FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", 
703         debugstr_a(szAssemblyName),  debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf);
704     return ERROR_CALL_NOT_IMPLEMENTED;
705 }
706
707 UINT WINAPI MsiProvideAssemblyW(
708     LPCWSTR szAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, DWORD* pcchPathBuf) 
709 {
710     FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", 
711         debugstr_w(szAssemblyName),  debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf);
712     return ERROR_CALL_NOT_IMPLEMENTED;
713 }
714
715 UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
716 {
717     FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
718     return ERROR_CALL_NOT_IMPLEMENTED;
719 }
720
721 UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
722 {
723     FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
724     return ERROR_CALL_NOT_IMPLEMENTED;
725 }
726
727 HRESULT WINAPI MsiGetFileSignatureInformationA(
728   LPCSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData)
729 {
730     FIXME("%s 0x%08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData);
731     return ERROR_CALL_NOT_IMPLEMENTED;
732 }
733
734 HRESULT WINAPI MsiGetFileSignatureInformationW(
735   LPCWSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData)
736 {
737     FIXME("%s 0x%08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData);
738     return ERROR_CALL_NOT_IMPLEMENTED;
739 }
740
741 UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty,
742                                     LPSTR szValue, DWORD *pccbValue )
743 {
744     FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue);
745     return ERROR_CALL_NOT_IMPLEMENTED;
746 }
747
748 UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty,
749                                     LPWSTR szValue, DWORD *pccbValue )
750 {
751     FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue);
752     return ERROR_CALL_NOT_IMPLEMENTED;
753 }
754
755 HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi)
756 {
757     TRACE("%p\n",pdvi);
758
759     if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
760         return E_INVALIDARG;
761
762     pdvi->dwMajorVersion = MSI_MAJORVERSION;
763     pdvi->dwMinorVersion = MSI_MINORVERSION;
764     pdvi->dwBuildNumber = MSI_BUILDNUMBER;
765     pdvi->dwPlatformID = 1;
766
767     return S_OK;
768 }
769
770 BOOL WINAPI MSI_DllCanUnloadNow(void)
771 {
772     return FALSE;
773 }