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