- Fix scaling when converting MF -> EMF.
[wine] / dlls / msi / registry.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Mike McCormack for CodeWeavers
5  * Copyright 2005 Aric Stewart for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winnls.h"
31 #include "shlwapi.h"
32 #include "wine/debug.h"
33 #include "msi.h"
34 #include "msipriv.h"
35 #include "wincrypt.h"
36 #include "wine/unicode.h"
37 #include "winver.h"
38 #include "winuser.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
42
43 /* 
44  * This module will be all the helper functions for registry access by the
45  * installer bits. 
46  */
47 static const WCHAR szUserFeatures_fmt[] = {
48 'S','o','f','t','w','a','r','e','\\',
49 'M','i','c','r','o','s','o','f','t','\\',
50 'I','n','s','t','a','l','l','e','r','\\',
51 'F','e','a','t','u','r','e','s','\\',
52 '%','s',0};
53
54 static const WCHAR szInstaller_Features[] = {
55 'S','o','f','t','w','a','r','e','\\',
56 'M','i','c','r','o','s','o','f','t','\\',
57 'W','i','n','d','o','w','s','\\',
58 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
59 'I','n','s','t','a','l','l','e','r','\\',
60 'F','e','a','t','u','r','e','s',0 };
61
62 static const WCHAR szInstaller_Features_fmt[] = {
63 'S','o','f','t','w','a','r','e','\\',
64 'M','i','c','r','o','s','o','f','t','\\',
65 'W','i','n','d','o','w','s','\\',
66 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
67 'I','n','s','t','a','l','l','e','r','\\',
68 'F','e','a','t','u','r','e','s','\\',
69 '%','s',0};
70
71 static const WCHAR szInstaller_Components[] = {
72 'S','o','f','t','w','a','r','e','\\',
73 'M','i','c','r','o','s','o','f','t','\\',
74 'W','i','n','d','o','w','s','\\',
75 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
76 'I','n','s','t','a','l','l','e','r','\\',
77 'C','o','m','p','o','n','e','n','t','s',0 };
78
79 static const WCHAR szInstaller_Components_fmt[] = {
80 'S','o','f','t','w','a','r','e','\\',
81 'M','i','c','r','o','s','o','f','t','\\',
82 'W','i','n','d','o','w','s','\\',
83 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
84 'I','n','s','t','a','l','l','e','r','\\',
85 'C','o','m','p','o','n','e','n','t','s','\\',
86 '%','s',0};
87
88 static const WCHAR szUninstall_fmt[] = {
89 'S','o','f','t','w','a','r','e','\\',
90 'M','i','c','r','o','s','o','f','t','\\',
91 'W','i','n','d','o','w','s','\\',
92 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
93 'U','n','i','n','s','t','a','l','l','\\',
94 '%','s',0 };
95
96 static const WCHAR szUserProduct_fmt[] = {
97 'S','o','f','t','w','a','r','e','\\',
98 'M','i','c','r','o','s','o','f','t','\\',
99 'I','n','s','t','a','l','l','e','r','\\',
100 'P','r','o','d','u','c','t','s','\\',
101 '%','s',0};
102
103 static const WCHAR szInstaller_Products[] = {
104 'S','o','f','t','w','a','r','e','\\',
105 'M','i','c','r','o','s','o','f','t','\\',
106 'W','i','n','d','o','w','s','\\',
107 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
108 'I','n','s','t','a','l','l','e','r','\\',
109 'P','r','o','d','u','c','t','s',0};
110
111 static const WCHAR szInstaller_Products_fmt[] = {
112 'S','o','f','t','w','a','r','e','\\',
113 'M','i','c','r','o','s','o','f','t','\\',
114 'W','i','n','d','o','w','s','\\',
115 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
116 'I','n','s','t','a','l','l','e','r','\\',
117 'P','r','o','d','u','c','t','s','\\',
118 '%','s',0};
119
120 static const WCHAR szInstaller_UpgradeCodes[] = {
121 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'I','n','s','t','a','l','l','e','r','\\',
126 'U','p','g','r','a','d','e','C','o','d','e','s',0};
127
128 static const WCHAR szInstaller_UpgradeCodes_fmt[] = {
129 'S','o','f','t','w','a','r','e','\\',
130 'M','i','c','r','o','s','o','f','t','\\',
131 'W','i','n','d','o','w','s','\\',
132 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
133 'I','n','s','t','a','l','l','e','r','\\',
134 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
135 '%','s',0};
136
137 #define SQUISH_GUID_SIZE 33
138
139 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
140 {
141     DWORD i,n=0;
142
143     out[n++]='{';
144     for(i=0; i<8; i++)
145         out[n++] = in[7-i];
146     out[n++]='-';
147     for(i=0; i<4; i++)
148         out[n++] = in[11-i];
149     out[n++]='-';
150     for(i=0; i<4; i++)
151         out[n++] = in[15-i];
152     out[n++]='-';
153     for(i=0; i<2; i++)
154     {
155         out[n++] = in[17+i*2];
156         out[n++] = in[16+i*2];
157     }
158     out[n++]='-';
159     for( ; i<8; i++)
160     {
161         out[n++] = in[17+i*2];
162         out[n++] = in[16+i*2];
163     }
164     out[n++]='}';
165     out[n]=0;
166     return TRUE;
167 }
168
169 BOOL squash_guid(LPCWSTR in, LPWSTR out)
170 {
171     DWORD i,n=0;
172
173     if(in[n++] != '{')
174         return FALSE;
175     for(i=0; i<8; i++)
176         out[7-i] = in[n++];
177     if(in[n++] != '-')
178         return FALSE;
179     for(i=0; i<4; i++)
180         out[11-i] = in[n++];
181     if(in[n++] != '-')
182         return FALSE;
183     for(i=0; i<4; i++)
184         out[15-i] = in[n++];
185     if(in[n++] != '-')
186         return FALSE;
187     for(i=0; i<2; i++)
188     {
189         out[17+i*2] = in[n++];
190         out[16+i*2] = in[n++];
191     }
192     if(in[n++] != '-')
193         return FALSE;
194     for( ; i<8; i++)
195     {
196         out[17+i*2] = in[n++];
197         out[16+i*2] = in[n++];
198     }
199     out[32]=0;
200     if(in[n++] != '}')
201         return FALSE;
202     if(in[n])
203         return FALSE;
204     return TRUE;
205 }
206
207
208 /* tables for encoding and decoding base85 */
209 static const unsigned char table_dec85[0x80] = {
210 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
211 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
212 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
213 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
214 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
215 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
216 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
217 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
218 };
219
220 static const char table_enc85[] =
221 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
222 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
223 "yz{}~";
224
225 /*
226  *  Converts a base85 encoded guid into a GUID pointer
227  *  Base85 encoded GUIDs should be 20 characters long.
228  *
229  *  returns TRUE if successful, FALSE if not
230  */
231 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
232 {
233     DWORD i, val = 0, base = 1, *p;
234
235     p = (DWORD*) guid;
236     for( i=0; i<20; i++ )
237     {
238         if( (i%5) == 0 )
239         {
240             val = 0;
241             base = 1;
242         }
243         val += table_dec85[str[i]] * base;
244         if( str[i] >= 0x80 )
245             return FALSE;
246         if( table_dec85[str[i]] == 0xff )
247             return FALSE;
248         if( (i%5) == 4 )
249             p[i/5] = val;
250         base *= 85;
251     }
252     return TRUE;
253 }
254
255 /*
256  *  Encodes a base85 guid given a GUID pointer
257  *  Caller should provide a 21 character buffer for the encoded string.
258  *
259  *  returns TRUE if successful, FALSE if not
260  */
261 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
262 {
263     unsigned int x, *p, i;
264
265     p = (unsigned int*) guid;
266     for( i=0; i<4; i++ )
267     {
268         x = p[i];
269         *str++ = table_enc85[x%85];
270         x = x/85;
271         *str++ = table_enc85[x%85];
272         x = x/85;
273         *str++ = table_enc85[x%85];
274         x = x/85;
275         *str++ = table_enc85[x%85];
276         x = x/85;
277         *str++ = table_enc85[x%85];
278     }
279     *str = 0;
280
281     return TRUE;
282 }
283
284
285 UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create)
286 {
287     UINT rc;
288     WCHAR keypath[0x200];
289     TRACE("%s\n",debugstr_w(szProduct));
290
291     sprintfW(keypath,szUninstall_fmt,szProduct);
292
293     if (create)
294         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
295     else
296         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
297
298     return rc;
299 }
300
301 UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
302 {
303     UINT rc;
304     WCHAR squished_pc[GUID_SIZE];
305     WCHAR keypath[0x200];
306
307     TRACE("%s\n",debugstr_w(szProduct));
308     squash_guid(szProduct,squished_pc);
309     TRACE("squished (%s)\n", debugstr_w(squished_pc));
310
311     sprintfW(keypath,szUserProduct_fmt,squished_pc);
312
313     if (create)
314         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
315     else
316         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
317
318     return rc;
319 }
320
321 UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
322 {
323     UINT rc;
324     WCHAR squished_pc[GUID_SIZE];
325     WCHAR keypath[0x200];
326
327     TRACE("%s\n",debugstr_w(szProduct));
328     squash_guid(szProduct,squished_pc);
329     TRACE("squished (%s)\n", debugstr_w(squished_pc));
330
331     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
332
333     if (create)
334         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
335     else
336         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
337
338     return rc;
339 }
340
341 UINT MSIREG_OpenFeatures(HKEY* key)
342 {
343     return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Features,key);
344 }
345
346 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
347 {
348     UINT rc;
349     WCHAR squished_pc[GUID_SIZE];
350     WCHAR keypath[0x200];
351
352     TRACE("%s\n",debugstr_w(szProduct));
353     squash_guid(szProduct,squished_pc);
354     TRACE("squished (%s)\n", debugstr_w(squished_pc));
355
356     sprintfW(keypath,szInstaller_Features_fmt,squished_pc);
357
358     if (create)
359         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
360     else
361         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
362
363     return rc;
364 }
365
366 UINT MSIREG_OpenComponents(HKEY* key)
367 {
368     return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Components,key);
369 }
370
371 UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
372 {
373     UINT rc;
374     WCHAR squished_cc[GUID_SIZE];
375     WCHAR keypath[0x200];
376
377     TRACE("%s\n",debugstr_w(szComponent));
378     squash_guid(szComponent,squished_cc);
379     TRACE("squished (%s)\n", debugstr_w(squished_cc));
380
381     sprintfW(keypath,szInstaller_Components_fmt,squished_cc);
382
383     if (create)
384         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
385     else
386         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
387
388     return rc;
389 }
390
391 UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
392 {
393     UINT rc;
394     WCHAR squished_pc[GUID_SIZE];
395     WCHAR keypath[0x200];
396
397     TRACE("%s\n",debugstr_w(szProduct));
398     squash_guid(szProduct,squished_pc);
399     TRACE("squished (%s)\n", debugstr_w(squished_pc));
400
401     sprintfW(keypath,szInstaller_Products_fmt,squished_pc);
402
403     if (create)
404         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
405     else
406         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
407
408     return rc;
409 }
410
411 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
412 {
413     UINT rc;
414     WCHAR squished_pc[GUID_SIZE];
415     WCHAR keypath[0x200];
416
417     TRACE("%s\n",debugstr_w(szUpgradeCode));
418     squash_guid(szUpgradeCode,squished_pc);
419     TRACE("squished (%s)\n", debugstr_w(squished_pc));
420
421     sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
422
423     if (create)
424         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
425     else
426         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
427
428     return rc;
429 }
430
431 /*************************************************************************
432  *  MsiDecomposeDescriptorW   [MSI.@]
433  *
434  * Decomposes an MSI descriptor into product, feature and component parts.
435  * An MSI descriptor is a string of the form:
436  *   [base 85 guid] [feature code] '>' [base 85 guid]
437  *
438  * PARAMS
439  *   szDescriptor  [I]  the descriptor to decompose
440  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS for the product guid
441  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS for the feature code
442  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS for the component guid
443  *   pUsed         [O]  the length of the descriptor
444  *
445  * RETURNS
446  *   ERROR_SUCCESS             if everything worked correctly
447  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
448  *
449  */
450 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
451                 LPWSTR szFeature, LPWSTR szComponent, DWORD *pUsed )
452 {
453     UINT r, len;
454     LPWSTR p;
455     GUID product, component;
456
457     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
458           szFeature, szComponent, pUsed);
459
460     r = decode_base85_guid( szDescriptor, &product );
461     if( !r )
462         return ERROR_INVALID_PARAMETER;
463
464     TRACE("product %s\n", debugstr_guid( &product ));
465
466     p = strchrW(&szDescriptor[20],'>');
467     if( !p )
468         return ERROR_INVALID_PARAMETER;
469
470     len = (p - &szDescriptor[20]);
471     if( len > MAX_FEATURE_CHARS )
472         return ERROR_INVALID_PARAMETER;
473     memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
474     szFeature[len] = 0;
475
476     TRACE("feature %s\n", debugstr_w( szFeature ));
477
478     r = decode_base85_guid( p+1, &component );
479     if( !r )
480         return ERROR_INVALID_PARAMETER;
481
482     TRACE("component %s\n", debugstr_guid( &component ));
483
484     StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
485     StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
486     len = ( &p[21] - szDescriptor );
487
488     TRACE("length = %d\n", len);
489     *pUsed = len;
490
491     return ERROR_SUCCESS;
492 }
493
494 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
495                 LPSTR szFeature, LPSTR szComponent, DWORD *pUsed )
496 {
497     WCHAR product[MAX_FEATURE_CHARS+1];
498     WCHAR feature[MAX_FEATURE_CHARS+1];
499     WCHAR component[MAX_FEATURE_CHARS+1];
500     LPWSTR str = NULL;
501     UINT r;
502
503     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
504           szFeature, szComponent, pUsed);
505
506     if( szDescriptor )
507     {
508         str = strdupAtoW( szDescriptor );
509         if( !str )
510             return ERROR_OUTOFMEMORY;
511     }
512
513     r = MsiDecomposeDescriptorW( str, product, feature, component, pUsed );
514
515     WideCharToMultiByte( CP_ACP, 0, product, MAX_FEATURE_CHARS+1,
516                          szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
517     WideCharToMultiByte( CP_ACP, 0, feature, MAX_FEATURE_CHARS+1,
518                          szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
519     WideCharToMultiByte( CP_ACP, 0, component, MAX_FEATURE_CHARS+1,
520                          szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
521
522     HeapFree( GetProcessHeap(), 0, str );
523
524     return r;
525 }
526
527 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
528 {
529     DWORD r;
530     WCHAR szwGuid[GUID_SIZE];
531
532     TRACE("%ld %p\n",index,lpguid);
533     
534     if (NULL == lpguid)
535         return ERROR_INVALID_PARAMETER;
536     r = MsiEnumProductsW(index, szwGuid);
537     if( r == ERROR_SUCCESS )
538         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
539
540     return r;
541 }
542
543 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
544 {
545     HKEY hkeyFeatures = 0;
546     DWORD r;
547     WCHAR szKeyName[SQUISH_GUID_SIZE];
548
549     TRACE("%ld %p\n",index,lpguid);
550
551     if (NULL == lpguid)
552         return ERROR_INVALID_PARAMETER;
553
554     r = MSIREG_OpenFeatures(&hkeyFeatures);
555     if( r != ERROR_SUCCESS )
556         return ERROR_NO_MORE_ITEMS;
557
558     r = RegEnumKeyW(hkeyFeatures, index, szKeyName, SQUISH_GUID_SIZE);
559     if( r == ERROR_SUCCESS )
560         unsquash_guid(szKeyName, lpguid);
561     RegCloseKey(hkeyFeatures);
562
563     return r;
564 }
565
566 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
567       LPSTR szFeature, LPSTR szParent)
568 {
569     DWORD r;
570     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
571     LPWSTR szwProduct = NULL;
572
573     TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent);
574
575     if( szProduct )
576     {
577         szwProduct = strdupAtoW( szProduct );
578         if( !szwProduct )
579             return ERROR_OUTOFMEMORY;
580     }
581
582     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
583     if( r == ERROR_SUCCESS )
584     {
585         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
586                             szFeature, GUID_SIZE, NULL, NULL);
587         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
588                             szParent, GUID_SIZE, NULL, NULL);
589     }
590
591     HeapFree( GetProcessHeap(), 0, szwProduct);
592
593     return r;
594 }
595
596 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
597       LPWSTR szFeature, LPWSTR szParent)
598 {
599     HKEY hkeyProduct = 0;
600     DWORD r, sz;
601
602     TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
603
604     r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
605     if( r != ERROR_SUCCESS )
606         return ERROR_NO_MORE_ITEMS;
607
608     sz = GUID_SIZE;
609     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
610     RegCloseKey(hkeyProduct);
611
612     return r;
613 }
614
615 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
616 {
617     DWORD r;
618     WCHAR szwGuid[GUID_SIZE];
619
620     TRACE("%ld %p\n",index,lpguid);
621
622     r = MsiEnumComponentsW(index, szwGuid);
623     if( r == ERROR_SUCCESS )
624         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
625
626     return r;
627 }
628
629 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
630 {
631     HKEY hkeyComponents = 0;
632     DWORD r;
633     WCHAR szKeyName[SQUISH_GUID_SIZE];
634
635     TRACE("%ld %p\n",index,lpguid);
636
637     r = MSIREG_OpenComponents(&hkeyComponents);
638     if( r != ERROR_SUCCESS )
639         return ERROR_NO_MORE_ITEMS;
640
641     r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
642     if( r == ERROR_SUCCESS )
643         unsquash_guid(szKeyName, lpguid);
644     RegCloseKey(hkeyComponents);
645
646     return r;
647 }
648
649 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
650 {
651     DWORD r;
652     WCHAR szwProduct[GUID_SIZE];
653     LPWSTR szwComponent = NULL;
654
655     TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct);
656
657     if( szComponent )
658     {
659         szwComponent = strdupAtoW( szComponent );
660         if( !szwComponent )
661             return ERROR_OUTOFMEMORY;
662     }
663
664     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
665     if( r == ERROR_SUCCESS )
666     {
667         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
668                             szProduct, GUID_SIZE, NULL, NULL);
669     }
670
671     HeapFree( GetProcessHeap(), 0, szwComponent);
672
673     return r;
674 }
675
676 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
677 {
678     HKEY hkeyComp = 0;
679     DWORD r, sz;
680     WCHAR szValName[SQUISH_GUID_SIZE];
681
682     TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct);
683
684     r = MSIREG_OpenComponentsKey(szComponent,&hkeyComp,FALSE);
685     if( r != ERROR_SUCCESS )
686         return ERROR_NO_MORE_ITEMS;
687
688     sz = SQUISH_GUID_SIZE;
689     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
690     if( r == ERROR_SUCCESS )
691         unsquash_guid(szValName, szProduct);
692
693     RegCloseKey(hkeyComp);
694
695     return r;
696 }
697
698 UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex,
699                 LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
700                 LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
701 {
702     FIXME("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex,
703           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
704           pcchApplicationDataBuf);
705     return ERROR_CALL_NOT_IMPLEMENTED;
706 }
707
708 UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex,
709                 LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
710                 LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
711 {
712     FIXME("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex,
713           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
714           pcchApplicationDataBuf);
715     return ERROR_CALL_NOT_IMPLEMENTED;
716 }
717
718 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
719                                     DWORD iProductIndex, LPWSTR lpProductBuf)
720 {
721     UINT r;
722     HKEY hkey;
723     WCHAR szKeyName[SQUISH_GUID_SIZE];
724
725     TRACE("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved,
726           iProductIndex, lpProductBuf);
727
728     if (NULL == szUpgradeCode)
729         return ERROR_INVALID_PARAMETER;
730     if (NULL == lpProductBuf)
731         return ERROR_INVALID_PARAMETER;
732
733     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
734     if (r != ERROR_SUCCESS)
735         return ERROR_NO_MORE_ITEMS;
736
737     r = RegEnumKeyW(hkey, iProductIndex, szKeyName, SQUISH_GUID_SIZE);
738     if( r == ERROR_SUCCESS )
739         unsquash_guid(szKeyName, lpProductBuf);
740     RegCloseKey(hkey);
741
742     return r;
743 }
744
745 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
746                                     DWORD iProductIndex, LPSTR lpProductBuf)
747 {
748     LPWSTR szwUpgradeCode = NULL;
749     WCHAR productW[GUID_SIZE];
750     UINT r;
751
752     TRACE("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved,
753           iProductIndex, lpProductBuf);
754
755     if (szUpgradeCode)
756     {
757         szwUpgradeCode = strdupAtoW( szUpgradeCode );
758         if( !szwUpgradeCode )
759             return ERROR_OUTOFMEMORY;
760     }
761
762     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
763                                  iProductIndex, productW );
764     if (r == ERROR_SUCCESS)
765     {
766         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
767                              lpProductBuf, GUID_SIZE, NULL, NULL );
768     }
769     HeapFree(GetProcessHeap(), 0, szwUpgradeCode);
770     return r;
771 }