msi: Remove a pointless wrapper of RegCreateKey.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #include "sddl.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43
44 /* 
45  * This module will be all the helper functions for registry access by the
46  * installer bits. 
47  */
48 static const WCHAR szUserFeatures_fmt[] = {
49 'S','o','f','t','w','a','r','e','\\',
50 'M','i','c','r','o','s','o','f','t','\\',
51 'I','n','s','t','a','l','l','e','r','\\',
52 'F','e','a','t','u','r','e','s','\\',
53 '%','s',0};
54
55 static const WCHAR szUserDataFeatures_fmt[] = {
56 'S','o','f','t','w','a','r','e','\\',
57 'M','i','c','r','o','s','o','f','t','\\',
58 'W','i','n','d','o','w','s','\\',
59 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
60 'I','n','s','t','a','l','l','e','r','\\',
61 'U','s','e','r','D','a','t','a','\\',
62 '%','s','\\','P','r','o','d','u','c','t','s','\\',
63 '%','s','\\','F','e','a','t','u','r','e','s',0};
64
65 static const WCHAR szInstaller_Features_fmt[] = {
66 'S','o','f','t','w','a','r','e','\\',
67 'M','i','c','r','o','s','o','f','t','\\',
68 'W','i','n','d','o','w','s','\\',
69 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
70 'I','n','s','t','a','l','l','e','r','\\',
71 'F','e','a','t','u','r','e','s','\\',
72 '%','s',0};
73
74 static const WCHAR szInstaller_Components[] = {
75 'S','o','f','t','w','a','r','e','\\',
76 'M','i','c','r','o','s','o','f','t','\\',
77 'W','i','n','d','o','w','s','\\',
78 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
79 'I','n','s','t','a','l','l','e','r','\\',
80 'C','o','m','p','o','n','e','n','t','s',0 };
81
82 static const WCHAR szUser_Components_fmt[] = {
83 'S','o','f','t','w','a','r','e','\\',
84 'M','i','c','r','o','s','o','f','t','\\',
85 'I','n','s','t','a','l','l','e','r','\\',
86 'C','o','m','p','o','n','e','n','t','s','\\',
87 '%','s',0};
88
89 static const WCHAR szUserDataComp_fmt[] = {
90 'S','o','f','t','w','a','r','e','\\',
91 'M','i','c','r','o','s','o','f','t','\\',
92 'W','i','n','d','o','w','s','\\',
93 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
94 'I','n','s','t','a','l','l','e','r','\\',
95 'U','s','e','r','D','a','t','a','\\',
96 '%','s','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
97
98 static const WCHAR szUninstall_fmt[] = {
99 'S','o','f','t','w','a','r','e','\\',
100 'M','i','c','r','o','s','o','f','t','\\',
101 'W','i','n','d','o','w','s','\\',
102 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
103 'U','n','i','n','s','t','a','l','l','\\',
104 '%','s',0 };
105
106 static const WCHAR szUserProduct_fmt[] = {
107 'S','o','f','t','w','a','r','e','\\',
108 'M','i','c','r','o','s','o','f','t','\\',
109 'I','n','s','t','a','l','l','e','r','\\',
110 'P','r','o','d','u','c','t','s','\\',
111 '%','s',0};
112
113 static const WCHAR szUserPatch_fmt[] = {
114 'S','o','f','t','w','a','r','e','\\',
115 'M','i','c','r','o','s','o','f','t','\\',
116 'I','n','s','t','a','l','l','e','r','\\',
117 'P','a','t','c','h','e','s','\\',
118 '%','s',0};
119
120 static const WCHAR szInstaller_Products[] = {
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 'P','r','o','d','u','c','t','s',0};
127
128 static const WCHAR szInstaller_Products_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 'P','r','o','d','u','c','t','s','\\',
135 '%','s',0};
136
137 static const WCHAR szInstaller_Patches_fmt[] = {
138 'S','o','f','t','w','a','r','e','\\',
139 'M','i','c','r','o','s','o','f','t','\\',
140 'W','i','n','d','o','w','s','\\',
141 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
142 'I','n','s','t','a','l','l','e','r','\\',
143 'P','a','t','c','h','e','s','\\',
144 '%','s',0};
145
146 static const WCHAR szInstaller_UpgradeCodes_fmt[] = {
147 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'I','n','s','t','a','l','l','e','r','\\',
152 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
153 '%','s',0};
154
155 static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = {
156 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'I','n','s','t','a','l','l','e','r','\\',
159 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
160 '%','s',0};
161
162 static const WCHAR szUserDataProd_fmt[] = {
163 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'I','n','s','t','a','l','l','e','r','\\',
168 'U','s','e','r','D','a','t','a','\\',
169 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
170
171 static const WCHAR szInstallProperties_fmt[] = {
172 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'I','n','s','t','a','l','l','e','r','\\',
177 'U','s','e','r','D','a','t','a','\\',
178 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
179 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
180
181 static const WCHAR szInstaller_LocalSystemProductCodes_fmt[] = {
182 'S','o','f','t','w','a','r','e','\\',
183 'M','i','c','r','o','s','o','f','t','\\',
184 'W','i','n','d','o','w','s','\\',
185 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
186 'I','n','s','t','a','l','l','e','r','\\',
187 'U','s','e','r','D','a','t','a','\\',
188 'S','-','1','-','5','-','1','8','\\','P','r','o','d','u','c','t','s','\\',
189 '%','s','\\','I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
190
191 static const WCHAR szInstaller_LocalSystemComponent_fmt[] = {
192 'S','o','f','t','w','a','r','e','\\',
193 'M','i','c','r','o','s','o','f','t','\\',
194 'W','i','n','d','o','w','s','\\',
195 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
196 'I','n','s','t','a','l','l','e','r','\\',
197 'U','s','e','r','D','a','t','a','\\',
198 'S','-','1','-','5','-','1','8','\\',
199 'C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
200
201 static const WCHAR szInstaller_LocalClassesProd_fmt[] = {
202 'S','o','f','t','w','a','r','e','\\',
203 'C','l','a','s','s','e','s','\\',
204 'I','n','s','t','a','l','l','e','r','\\',
205 'P','r','o','d','u','c','t','s','\\','%','s',0};
206
207 static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
208 'S','o','f','t','w','a','r','e','\\',
209 'M','i','c','r','o','s','o','f','t','\\',
210 'W','i','n','d','o','w','s','\\',
211 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
212 'I','n','s','t','a','l','l','e','r','\\',
213 'M','a','n','a','g','e','d','\\','%','s','\\',
214 'I','n','s','t','a','l','l','e','r','\\',
215 'P','r','o','d','u','c','t','s','\\','%','s',0};
216
217 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
218 {
219     DWORD i,n=0;
220
221     out[n++]='{';
222     for(i=0; i<8; i++)
223         out[n++] = in[7-i];
224     out[n++]='-';
225     for(i=0; i<4; i++)
226         out[n++] = in[11-i];
227     out[n++]='-';
228     for(i=0; i<4; i++)
229         out[n++] = in[15-i];
230     out[n++]='-';
231     for(i=0; i<2; i++)
232     {
233         out[n++] = in[17+i*2];
234         out[n++] = in[16+i*2];
235     }
236     out[n++]='-';
237     for( ; i<8; i++)
238     {
239         out[n++] = in[17+i*2];
240         out[n++] = in[16+i*2];
241     }
242     out[n++]='}';
243     out[n]=0;
244     return TRUE;
245 }
246
247 BOOL squash_guid(LPCWSTR in, LPWSTR out)
248 {
249     DWORD i,n=1;
250     GUID guid;
251
252     out[0] = 0;
253
254     if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
255         return FALSE;
256
257     for(i=0; i<8; i++)
258         out[7-i] = in[n++];
259     n++;
260     for(i=0; i<4; i++)
261         out[11-i] = in[n++];
262     n++;
263     for(i=0; i<4; i++)
264         out[15-i] = in[n++];
265     n++;
266     for(i=0; i<2; i++)
267     {
268         out[17+i*2] = in[n++];
269         out[16+i*2] = in[n++];
270     }
271     n++;
272     for( ; i<8; i++)
273     {
274         out[17+i*2] = in[n++];
275         out[16+i*2] = in[n++];
276     }
277     out[32]=0;
278     return TRUE;
279 }
280
281
282 /* tables for encoding and decoding base85 */
283 static const unsigned char table_dec85[0x80] = {
284 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
285 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
286 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
287 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
288 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
289 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
290 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
291 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
292 };
293
294 static const char table_enc85[] =
295 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
296 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
297 "yz{}~";
298
299 /*
300  *  Converts a base85 encoded guid into a GUID pointer
301  *  Base85 encoded GUIDs should be 20 characters long.
302  *
303  *  returns TRUE if successful, FALSE if not
304  */
305 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
306 {
307     DWORD i, val = 0, base = 1, *p;
308
309     if (!str)
310         return FALSE;
311
312     p = (DWORD*) guid;
313     for( i=0; i<20; i++ )
314     {
315         if( (i%5) == 0 )
316         {
317             val = 0;
318             base = 1;
319         }
320         val += table_dec85[str[i]] * base;
321         if( str[i] >= 0x80 )
322             return FALSE;
323         if( table_dec85[str[i]] == 0xff )
324             return FALSE;
325         if( (i%5) == 4 )
326             p[i/5] = val;
327         base *= 85;
328     }
329     return TRUE;
330 }
331
332 /*
333  *  Encodes a base85 guid given a GUID pointer
334  *  Caller should provide a 21 character buffer for the encoded string.
335  *
336  *  returns TRUE if successful, FALSE if not
337  */
338 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
339 {
340     unsigned int x, *p, i;
341
342     p = (unsigned int*) guid;
343     for( i=0; i<4; i++ )
344     {
345         x = p[i];
346         *str++ = table_enc85[x%85];
347         x = x/85;
348         *str++ = table_enc85[x%85];
349         x = x/85;
350         *str++ = table_enc85[x%85];
351         x = x/85;
352         *str++ = table_enc85[x%85];
353         x = x/85;
354         *str++ = table_enc85[x%85];
355     }
356     *str = 0;
357
358     return TRUE;
359 }
360
361 DWORD msi_version_str_to_dword(LPCWSTR p)
362 {
363     DWORD major, minor = 0, build = 0, version = 0;
364
365     if (!p)
366         return version;
367
368     major = atoiW(p);
369
370     p = strchrW(p, '.');
371     if (p)
372     {
373         minor = atoiW(p+1);
374         p = strchrW(p+1, '.');
375         if (p)
376             build = atoiW(p+1);
377     }
378
379     return MAKELONG(build, MAKEWORD(minor, major));
380 }
381
382 LPWSTR msi_version_dword_to_str(DWORD version)
383 {
384     const WCHAR fmt[] = { '%','u','.','%','u','.','%','u',0 };
385     LPWSTR str = msi_alloc(20);
386     sprintfW(str, fmt,
387              (version&0xff000000)>>24,
388              (version&0x00ff0000)>>16,
389               version&0x0000ffff);
390     return str;
391 }
392
393 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
394 {
395     DWORD len = value ? (lstrlenW(value) + 1) * sizeof (WCHAR) : 0;
396     return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
397 }
398
399 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
400 {
401     LPCWSTR p = value;
402     while (*p) p += lstrlenW(p) + 1;
403     return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
404                            (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
405 }
406
407 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
408 {
409     return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
410 }
411
412 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
413 {
414     HKEY hsubkey = 0;
415     LONG r;
416
417     r = RegCreateKeyW( hkey, path, &hsubkey );
418     if (r != ERROR_SUCCESS)
419         return r;
420     r = msi_reg_set_val_str( hsubkey, name, val );
421     RegCloseKey( hsubkey );
422     return r;
423 }
424
425 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
426 {
427     DWORD len = 0;
428     LPWSTR val;
429     LONG r;
430
431     r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
432     if (r != ERROR_SUCCESS)
433         return NULL;
434
435     len += sizeof (WCHAR);
436     val = msi_alloc( len );
437     if (!val)
438         return NULL;
439     val[0] = 0;
440     RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
441     return val;
442 }
443
444 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
445 {
446     DWORD type, len = sizeof (DWORD);
447     LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
448     return r == ERROR_SUCCESS && type == REG_DWORD;
449 }
450
451 static UINT get_user_sid(LPWSTR *usersid)
452 {
453     HANDLE token;
454     BYTE buf[1024];
455     DWORD size;
456     PTOKEN_USER user;
457
458     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
459         return ERROR_FUNCTION_FAILED;
460
461     size = sizeof(buf);
462     if (!GetTokenInformation(token, TokenUser, (void *)buf, size, &size)) {
463         CloseHandle(token);
464         return ERROR_FUNCTION_FAILED;
465     }
466
467     user = (PTOKEN_USER)buf;
468     if (!ConvertSidToStringSidW(user->User.Sid, usersid)) {
469         CloseHandle(token);
470         return ERROR_FUNCTION_FAILED;
471     }
472     CloseHandle(token);
473     return ERROR_SUCCESS;
474 }
475
476 UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create)
477 {
478     UINT rc;
479     WCHAR keypath[0x200];
480     TRACE("%s\n",debugstr_w(szProduct));
481
482     sprintfW(keypath,szUninstall_fmt,szProduct);
483
484     if (create)
485         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
486     else
487         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
488
489     return rc;
490 }
491
492 UINT MSIREG_DeleteUninstallKey(LPCWSTR szProduct)
493 {
494     WCHAR keypath[0x200];
495     TRACE("%s\n",debugstr_w(szProduct));
496
497     sprintfW(keypath,szUninstall_fmt,szProduct);
498
499     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
500 }
501
502 UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
503 {
504     UINT rc;
505     WCHAR squished_pc[GUID_SIZE];
506     WCHAR keypath[0x200];
507
508     TRACE("%s\n",debugstr_w(szProduct));
509     if (!squash_guid(szProduct,squished_pc))
510         return ERROR_FUNCTION_FAILED;
511     TRACE("squished (%s)\n", debugstr_w(squished_pc));
512
513     sprintfW(keypath,szUserProduct_fmt,squished_pc);
514
515     if (create)
516         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
517     else
518         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
519
520     return rc;
521 }
522
523 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
524 {
525     WCHAR squished_pc[GUID_SIZE];
526     WCHAR keypath[0x200];
527
528     TRACE("%s\n",debugstr_w(szProduct));
529     if (!squash_guid(szProduct,squished_pc))
530         return ERROR_FUNCTION_FAILED;
531     TRACE("squished (%s)\n", debugstr_w(squished_pc));
532
533     sprintfW(keypath,szUserProduct_fmt,squished_pc);
534
535     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
536 }
537
538 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
539 {
540     UINT rc;
541     WCHAR squished_pc[GUID_SIZE];
542     WCHAR keypath[0x200];
543
544     TRACE("%s\n",debugstr_w(szPatch));
545     if (!squash_guid(szPatch,squished_pc))
546         return ERROR_FUNCTION_FAILED;
547     TRACE("squished (%s)\n", debugstr_w(squished_pc));
548
549     sprintfW(keypath,szUserPatch_fmt,squished_pc);
550
551     if (create)
552         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
553     else
554         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
555
556     return rc;
557 }
558
559 UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
560 {
561     UINT rc;
562     WCHAR squished_pc[GUID_SIZE];
563     WCHAR keypath[0x200];
564
565     TRACE("%s\n",debugstr_w(szProduct));
566     if (!squash_guid(szProduct,squished_pc))
567         return ERROR_FUNCTION_FAILED;
568     TRACE("squished (%s)\n", debugstr_w(squished_pc));
569
570     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
571
572     if (create)
573         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
574     else
575         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
576
577     return rc;
578 }
579
580 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
581 {
582     WCHAR squished_pc[GUID_SIZE];
583     WCHAR keypath[0x200];
584
585     TRACE("%s\n",debugstr_w(szProduct));
586     if (!squash_guid(szProduct,squished_pc))
587         return ERROR_FUNCTION_FAILED;
588     TRACE("squished (%s)\n", debugstr_w(squished_pc));
589
590     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
591     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
592 }
593
594 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
595 {
596     UINT rc;
597     WCHAR squished_pc[GUID_SIZE];
598     WCHAR keypath[0x200];
599
600     TRACE("%s\n",debugstr_w(szProduct));
601     if (!squash_guid(szProduct,squished_pc))
602         return ERROR_FUNCTION_FAILED;
603     TRACE("squished (%s)\n", debugstr_w(squished_pc));
604
605     sprintfW(keypath,szInstaller_Features_fmt,squished_pc);
606
607     if (create)
608         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
609     else
610         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
611
612     return rc;
613 }
614
615 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
616 {
617     UINT rc;
618     WCHAR squished_pc[GUID_SIZE];
619     WCHAR keypath[0x200];
620     LPWSTR usersid;
621
622     TRACE("%s\n", debugstr_w(szProduct));
623     if (!squash_guid(szProduct, squished_pc))
624         return ERROR_FUNCTION_FAILED;
625     TRACE("squished (%s)\n", debugstr_w(squished_pc));
626
627     rc = get_user_sid(&usersid);
628     if (rc != ERROR_SUCCESS || !usersid)
629     {
630         ERR("Failed to retrieve user SID: %d\n", rc);
631         return rc;
632     }
633
634     sprintfW(keypath, szUserDataFeatures_fmt, usersid, squished_pc);
635
636     if (create)
637         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
638     else
639         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
640
641     LocalFree(usersid);
642     return rc;
643 }
644
645 UINT MSIREG_OpenComponents(HKEY* key)
646 {
647     return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Components,key);
648 }
649
650 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
651 {
652     UINT rc;
653     WCHAR squished_cc[GUID_SIZE];
654     WCHAR keypath[0x200];
655
656     TRACE("%s\n",debugstr_w(szComponent));
657     if (!squash_guid(szComponent,squished_cc))
658         return ERROR_FUNCTION_FAILED;
659     TRACE("squished (%s)\n", debugstr_w(squished_cc));
660
661     sprintfW(keypath,szUser_Components_fmt,squished_cc);
662
663     if (create)
664         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
665     else
666         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
667
668     return rc;
669 }
670
671 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
672 {
673     UINT rc;
674     WCHAR comp[GUID_SIZE];
675     WCHAR keypath[0x200];
676     LPWSTR usersid;
677
678     TRACE("%s\n", debugstr_w(szComponent));
679     if (!squash_guid(szComponent, comp))
680         return ERROR_FUNCTION_FAILED;
681     TRACE("squished (%s)\n", debugstr_w(comp));
682
683     rc = get_user_sid(&usersid);
684     if (rc != ERROR_SUCCESS || !usersid)
685     {
686         ERR("Failed to retrieve user SID: %d\n", rc);
687         return rc;
688     }
689
690     sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
691
692     if (create)
693         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
694     else
695         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
696
697     LocalFree(usersid);
698     return rc;
699 }
700
701 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent)
702 {
703     UINT rc;
704     WCHAR comp[GUID_SIZE];
705     WCHAR keypath[0x200];
706     LPWSTR usersid;
707
708     TRACE("%s\n", debugstr_w(szComponent));
709     if (!squash_guid(szComponent, comp))
710         return ERROR_FUNCTION_FAILED;
711     TRACE("squished (%s)\n", debugstr_w(comp));
712
713     rc = get_user_sid(&usersid);
714     if (rc != ERROR_SUCCESS || !usersid)
715     {
716         ERR("Failed to retrieve user SID: %d\n", rc);
717         return rc;
718     }
719
720     sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
721
722     LocalFree(usersid);
723     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
724 }
725
726 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
727 {
728     UINT rc;
729     WCHAR squished_pc[GUID_SIZE];
730     WCHAR keypath[0x200];
731     LPWSTR usersid;
732
733     TRACE("%s\n", debugstr_w(szProduct));
734     if (!squash_guid(szProduct, squished_pc))
735         return ERROR_FUNCTION_FAILED;
736     TRACE("squished (%s)\n", debugstr_w(squished_pc));
737
738     rc = get_user_sid(&usersid);
739     if (rc != ERROR_SUCCESS || !usersid)
740     {
741         ERR("Failed to retrieve user SID: %d\n", rc);
742         return rc;
743     }
744
745     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
746
747     if (create)
748         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
749     else
750         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
751
752     LocalFree(usersid);
753     return rc;
754 }
755
756 UINT MSIREG_OpenInstallPropertiesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
757 {
758     UINT rc;
759     WCHAR squished_pc[GUID_SIZE];
760     WCHAR keypath[0x200];
761     LPWSTR usersid;
762
763     TRACE("%s\n", debugstr_w(szProduct));
764     if (!squash_guid(szProduct, squished_pc))
765         return ERROR_FUNCTION_FAILED;
766     TRACE("squished (%s)\n", debugstr_w(squished_pc));
767
768     rc = get_user_sid(&usersid);
769     if (rc != ERROR_SUCCESS || !usersid)
770     {
771         ERR("Failed to retrieve user SID: %d\n", rc);
772         return rc;
773     }
774
775     sprintfW(keypath, szInstallProperties_fmt, usersid, squished_pc);
776
777     if (create)
778         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
779     else
780         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
781
782     LocalFree(usersid);
783     return rc;
784 }
785
786 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
787 {
788     UINT rc;
789     WCHAR squished_pc[GUID_SIZE];
790     WCHAR keypath[0x200];
791     LPWSTR usersid;
792
793     TRACE("%s\n", debugstr_w(szProduct));
794     if (!squash_guid(szProduct, squished_pc))
795         return ERROR_FUNCTION_FAILED;
796     TRACE("squished (%s)\n", debugstr_w(squished_pc));
797
798     rc = get_user_sid(&usersid);
799     if (rc != ERROR_SUCCESS || !usersid)
800     {
801         ERR("Failed to retrieve user SID: %d\n", rc);
802         return rc;
803     }
804
805     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
806
807     LocalFree(usersid);
808     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
809 }
810
811 UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
812 {
813     UINT rc;
814     WCHAR squished_pc[GUID_SIZE];
815     WCHAR keypath[0x200];
816
817     TRACE("%s\n",debugstr_w(szProduct));
818     if (!squash_guid(szProduct,squished_pc))
819         return ERROR_FUNCTION_FAILED;
820     TRACE("squished (%s)\n", debugstr_w(squished_pc));
821
822     sprintfW(keypath,szInstaller_Products_fmt,squished_pc);
823
824     if (create)
825         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
826     else
827         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
828
829     return rc;
830 }
831
832 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
833 {
834     WCHAR squished_pc[GUID_SIZE];
835     WCHAR keypath[0x200];
836
837     TRACE("%s\n", debugstr_w(szProduct));
838     if (!squash_guid(szProduct, squished_pc))
839         return ERROR_FUNCTION_FAILED;
840     TRACE("squished (%s)\n", debugstr_w(squished_pc));
841
842     sprintfW(keypath, szInstaller_Products_fmt, squished_pc);
843
844     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
845 }
846
847 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
848 {
849     UINT rc;
850     WCHAR squished_pc[GUID_SIZE];
851     WCHAR keypath[0x200];
852
853     TRACE("%s\n",debugstr_w(szPatch));
854     if (!squash_guid(szPatch,squished_pc))
855         return ERROR_FUNCTION_FAILED;
856     TRACE("squished (%s)\n", debugstr_w(squished_pc));
857
858     sprintfW(keypath,szInstaller_Patches_fmt,squished_pc);
859
860     if (create)
861         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
862     else
863         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
864
865     return rc;
866 }
867
868 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
869 {
870     UINT rc;
871     WCHAR squished_pc[GUID_SIZE];
872     WCHAR keypath[0x200];
873
874     TRACE("%s\n",debugstr_w(szUpgradeCode));
875     if (!squash_guid(szUpgradeCode,squished_pc))
876         return ERROR_FUNCTION_FAILED;
877     TRACE("squished (%s)\n", debugstr_w(squished_pc));
878
879     sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
880
881     if (create)
882         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
883     else
884         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
885
886     return rc;
887 }
888
889 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
890 {
891     UINT rc;
892     WCHAR squished_pc[GUID_SIZE];
893     WCHAR keypath[0x200];
894
895     TRACE("%s\n",debugstr_w(szUpgradeCode));
896     if (!squash_guid(szUpgradeCode,squished_pc))
897         return ERROR_FUNCTION_FAILED;
898     TRACE("squished (%s)\n", debugstr_w(squished_pc));
899
900     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
901
902     if (create)
903         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
904     else
905         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
906
907     return rc;
908 }
909
910 UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
911 {
912     WCHAR squished_pc[GUID_SIZE];
913     WCHAR keypath[0x200];
914
915     TRACE("%s\n", debugstr_w(szProductCode));
916
917     if (!squash_guid(szProductCode, squished_pc))
918         return ERROR_FUNCTION_FAILED;
919
920     TRACE("squished (%s)\n", debugstr_w(squished_pc));
921
922     sprintfW(keypath, szInstaller_LocalSystemProductCodes_fmt, squished_pc);
923
924     if (create)
925         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
926
927     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
928 }
929
930 UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
931 {
932     WCHAR squished_pc[GUID_SIZE];
933     WCHAR keypath[0x200];
934
935     TRACE("%s\n", debugstr_w(szComponent));
936
937     if (!squash_guid(szComponent, squished_pc))
938         return ERROR_FUNCTION_FAILED;
939
940     TRACE("squished (%s)\n", debugstr_w(squished_pc));
941
942     sprintfW(keypath, szInstaller_LocalSystemComponent_fmt, squished_pc);
943
944     if (create)
945         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
946
947     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
948 }
949
950 UINT MSIREG_OpenLocalClassesProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
951 {
952     WCHAR squished_pc[GUID_SIZE];
953     WCHAR keypath[0x200];
954
955     TRACE("%s\n", debugstr_w(szProductCode));
956
957     if (!squash_guid(szProductCode, squished_pc))
958         return ERROR_FUNCTION_FAILED;
959
960     TRACE("squished (%s)\n", debugstr_w(squished_pc));
961
962     sprintfW(keypath, szInstaller_LocalClassesProd_fmt, squished_pc);
963
964     if (create)
965         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
966
967     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
968 }
969
970 UINT MSIREG_OpenLocalManagedProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
971 {
972     WCHAR squished_pc[GUID_SIZE];
973     WCHAR keypath[0x200];
974     LPWSTR usersid;
975     UINT r;
976
977     TRACE("%s\n", debugstr_w(szProductCode));
978
979     if (!squash_guid(szProductCode, squished_pc))
980         return ERROR_FUNCTION_FAILED;
981
982     TRACE("squished (%s)\n", debugstr_w(squished_pc));
983
984     r = get_user_sid(&usersid);
985     if (r != ERROR_SUCCESS || !usersid)
986     {
987         ERR("Failed to retrieve user SID: %d\n", r);
988         return r;
989     }
990
991     sprintfW(keypath, szInstaller_LocalManagedProd_fmt, usersid, squished_pc);
992     LocalFree(usersid);
993
994     if (create)
995         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
996
997     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
998 }
999
1000 /*************************************************************************
1001  *  MsiDecomposeDescriptorW   [MSI.@]
1002  *
1003  * Decomposes an MSI descriptor into product, feature and component parts.
1004  * An MSI descriptor is a string of the form:
1005  *   [base 85 guid] [feature code] '>' [base 85 guid]
1006  *
1007  * PARAMS
1008  *   szDescriptor  [I]  the descriptor to decompose
1009  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
1010  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
1011  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
1012  *   pUsed         [O]  the length of the descriptor
1013  *
1014  * RETURNS
1015  *   ERROR_SUCCESS             if everything worked correctly
1016  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
1017  *
1018  */
1019 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1020                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1021 {
1022     UINT r, len;
1023     LPWSTR p;
1024     GUID product, component;
1025
1026     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1027           szFeature, szComponent, pUsed);
1028
1029     r = decode_base85_guid( szDescriptor, &product );
1030     if( !r )
1031         return ERROR_INVALID_PARAMETER;
1032
1033     TRACE("product %s\n", debugstr_guid( &product ));
1034
1035     p = strchrW(&szDescriptor[20],'>');
1036     if( !p )
1037         return ERROR_INVALID_PARAMETER;
1038
1039     len = (p - &szDescriptor[20]);
1040     if( len > MAX_FEATURE_CHARS )
1041         return ERROR_INVALID_PARAMETER;
1042
1043     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1044
1045     r = decode_base85_guid( p+1, &component );
1046     if( !r )
1047         return ERROR_INVALID_PARAMETER;
1048
1049     TRACE("component %s\n", debugstr_guid( &component ));
1050
1051     if (szProduct)
1052         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1053     if (szComponent)
1054         StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1055     if (szFeature)
1056     {
1057         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1058         szFeature[len] = 0;
1059     }
1060     len = ( &p[21] - szDescriptor );
1061
1062     TRACE("length = %d\n", len);
1063     *pUsed = len;
1064
1065     return ERROR_SUCCESS;
1066 }
1067
1068 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1069                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1070 {
1071     WCHAR product[MAX_FEATURE_CHARS+1];
1072     WCHAR feature[MAX_FEATURE_CHARS+1];
1073     WCHAR component[MAX_FEATURE_CHARS+1];
1074     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1075     UINT r;
1076
1077     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1078           szFeature, szComponent, pUsed);
1079
1080     str = strdupAtoW( szDescriptor );
1081     if( szDescriptor && !str )
1082         return ERROR_OUTOFMEMORY;
1083
1084     if (szProduct)
1085         p = product;
1086     if (szFeature)
1087         f = feature;
1088     if (szComponent)
1089         c = component;
1090
1091     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1092
1093     if (r == ERROR_SUCCESS)
1094     {
1095         WideCharToMultiByte( CP_ACP, 0, p, -1,
1096                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1097         WideCharToMultiByte( CP_ACP, 0, f, -1,
1098                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1099         WideCharToMultiByte( CP_ACP, 0, c, -1,
1100                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1101     }
1102
1103     msi_free( str );
1104
1105     return r;
1106 }
1107
1108 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1109 {
1110     DWORD r;
1111     WCHAR szwGuid[GUID_SIZE];
1112
1113     TRACE("%d %p\n", index, lpguid);
1114
1115     if (NULL == lpguid)
1116         return ERROR_INVALID_PARAMETER;
1117     r = MsiEnumProductsW(index, szwGuid);
1118     if( r == ERROR_SUCCESS )
1119         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1120
1121     return r;
1122 }
1123
1124 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1125 {
1126     HKEY hkeyProducts = 0;
1127     DWORD r;
1128     WCHAR szKeyName[SQUISH_GUID_SIZE];
1129
1130     TRACE("%d %p\n", index, lpguid);
1131
1132     if (NULL == lpguid)
1133         return ERROR_INVALID_PARAMETER;
1134
1135     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Products, &hkeyProducts);
1136     if( r != ERROR_SUCCESS )
1137         return ERROR_NO_MORE_ITEMS;
1138
1139     r = RegEnumKeyW(hkeyProducts, index, szKeyName, SQUISH_GUID_SIZE);
1140     if( r == ERROR_SUCCESS )
1141         unsquash_guid(szKeyName, lpguid);
1142     RegCloseKey(hkeyProducts);
1143
1144     return r;
1145 }
1146
1147 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
1148       LPSTR szFeature, LPSTR szParent)
1149 {
1150     DWORD r;
1151     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1152     LPWSTR szwProduct = NULL;
1153
1154     TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1155
1156     if( szProduct )
1157     {
1158         szwProduct = strdupAtoW( szProduct );
1159         if( !szwProduct )
1160             return ERROR_OUTOFMEMORY;
1161     }
1162
1163     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1164     if( r == ERROR_SUCCESS )
1165     {
1166         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1167                             szFeature, GUID_SIZE, NULL, NULL);
1168         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1169                             szParent, GUID_SIZE, NULL, NULL);
1170     }
1171
1172     msi_free( szwProduct);
1173
1174     return r;
1175 }
1176
1177 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
1178       LPWSTR szFeature, LPWSTR szParent)
1179 {
1180     HKEY hkeyProduct = 0;
1181     DWORD r, sz;
1182
1183     TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1184
1185     if( !szProduct )
1186         return ERROR_INVALID_PARAMETER;
1187
1188     r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
1189     if( r != ERROR_SUCCESS )
1190         return ERROR_NO_MORE_ITEMS;
1191
1192     sz = GUID_SIZE;
1193     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1194     RegCloseKey(hkeyProduct);
1195
1196     return r;
1197 }
1198
1199 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1200 {
1201     DWORD r;
1202     WCHAR szwGuid[GUID_SIZE];
1203
1204     TRACE("%d %p\n", index, lpguid);
1205
1206     r = MsiEnumComponentsW(index, szwGuid);
1207     if( r == ERROR_SUCCESS )
1208         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1209
1210     return r;
1211 }
1212
1213 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1214 {
1215     HKEY hkeyComponents = 0;
1216     DWORD r;
1217     WCHAR szKeyName[SQUISH_GUID_SIZE];
1218
1219     TRACE("%d %p\n", index, lpguid);
1220
1221     r = MSIREG_OpenComponents(&hkeyComponents);
1222     if( r != ERROR_SUCCESS )
1223         return ERROR_NO_MORE_ITEMS;
1224
1225     r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
1226     if( r == ERROR_SUCCESS )
1227         unsquash_guid(szKeyName, lpguid);
1228     RegCloseKey(hkeyComponents);
1229
1230     return r;
1231 }
1232
1233 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1234 {
1235     DWORD r;
1236     WCHAR szwProduct[GUID_SIZE];
1237     LPWSTR szwComponent = NULL;
1238
1239     TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1240
1241     if ( !szProduct )
1242         return ERROR_INVALID_PARAMETER;
1243
1244     if( szComponent )
1245     {
1246         szwComponent = strdupAtoW( szComponent );
1247         if( !szwComponent )
1248             return ERROR_OUTOFMEMORY;
1249     }
1250
1251     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1252     if( r == ERROR_SUCCESS )
1253     {
1254         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1255                             szProduct, GUID_SIZE, NULL, NULL);
1256     }
1257
1258     msi_free( szwComponent);
1259
1260     return r;
1261 }
1262
1263 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1264 {
1265     HKEY hkeyComp = 0;
1266     DWORD r, sz;
1267     WCHAR szValName[SQUISH_GUID_SIZE];
1268
1269     TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1270
1271     if (!szComponent || !*szComponent || !szProduct)
1272         return ERROR_INVALID_PARAMETER;
1273
1274     if (MSIREG_OpenUserDataComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1275         MSIREG_OpenLocalSystemComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS)
1276         return ERROR_UNKNOWN_COMPONENT;
1277
1278     /* see if there are any products at all */
1279     sz = SQUISH_GUID_SIZE;
1280     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1281     if (r != ERROR_SUCCESS)
1282     {
1283         RegCloseKey(hkeyComp);
1284
1285         if (index != 0)
1286             return ERROR_INVALID_PARAMETER;
1287
1288         return ERROR_UNKNOWN_COMPONENT;
1289     }
1290
1291     sz = SQUISH_GUID_SIZE;
1292     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1293     if( r == ERROR_SUCCESS )
1294         unsquash_guid(szValName, szProduct);
1295
1296     RegCloseKey(hkeyComp);
1297
1298     return r;
1299 }
1300
1301 static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1302                 awstring *lpQualBuf, LPDWORD pcchQual,
1303                 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1304 {
1305     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1306     LPWSTR name = NULL, val = NULL;
1307     UINT r, r2;
1308     HKEY key;
1309
1310     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1311           lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1312
1313     if (!szComponent)
1314         return ERROR_INVALID_PARAMETER;
1315
1316     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1317     if (r != ERROR_SUCCESS)
1318         return ERROR_UNKNOWN_COMPONENT;
1319
1320     /* figure out how big the name is we want to return */
1321     name_max = 0x10;
1322     r = ERROR_OUTOFMEMORY;
1323     name = msi_alloc( name_max * sizeof(WCHAR) );
1324     if (!name)
1325         goto end;
1326
1327     val_max = 0x10;
1328     r = ERROR_OUTOFMEMORY;
1329     val = msi_alloc( val_max );
1330     if (!val)
1331         goto end;
1332
1333     /* loop until we allocate enough memory */
1334     while (1)
1335     {
1336         name_sz = name_max;
1337         val_sz = val_max;
1338         r = RegEnumValueW( key, iIndex, name, &name_sz,
1339                            NULL, &type, (LPBYTE)val, &val_sz );
1340         if (r == ERROR_SUCCESS)
1341             break;
1342         if (r != ERROR_MORE_DATA)
1343             goto end;
1344  
1345         if (type != REG_MULTI_SZ)
1346         {
1347             ERR("component data has wrong type (%d)\n", type);
1348             goto end;
1349         }
1350
1351         r = ERROR_OUTOFMEMORY;
1352         if ((name_sz+1) >= name_max)
1353         {
1354             name_max *= 2;
1355             msi_free( name );
1356             name = msi_alloc( name_max * sizeof (WCHAR) );
1357             if (!name)
1358                 goto end;
1359             continue;
1360         }
1361         if (val_sz > val_max)
1362         {
1363             val_max = val_sz + sizeof (WCHAR);
1364             msi_free( val );
1365             val = msi_alloc( val_max * sizeof (WCHAR) );
1366             if (!val)
1367                 goto end;
1368             continue;
1369         }
1370         ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1371         goto end;
1372     }
1373
1374     ofs = 0;
1375     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1376     if (r != ERROR_SUCCESS)
1377         goto end;
1378
1379     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1380
1381     r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1382     r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1383
1384     if (r2 != ERROR_SUCCESS)
1385         r = r2;
1386
1387 end:
1388     msi_free(val);
1389     msi_free(name);
1390     RegCloseKey(key);
1391
1392     return r;
1393 }
1394
1395 /*************************************************************************
1396  *  MsiEnumComponentQualifiersA [MSI.@]
1397  */
1398 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1399                 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1400                 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1401 {
1402     awstring qual, appdata;
1403     LPWSTR comp;
1404     UINT r;
1405
1406     TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1407           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1408           pcchApplicationDataBuf);
1409
1410     comp = strdupAtoW( szComponent );
1411     if (szComponent && !comp)
1412         return ERROR_OUTOFMEMORY;
1413
1414     qual.unicode = FALSE;
1415     qual.str.a = lpQualifierBuf;
1416
1417     appdata.unicode = FALSE;
1418     appdata.str.a = lpApplicationDataBuf;
1419
1420     r = MSI_EnumComponentQualifiers( comp, iIndex,
1421               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1422     msi_free( comp );
1423     return r;
1424 }
1425
1426 /*************************************************************************
1427  *  MsiEnumComponentQualifiersW [MSI.@]
1428  */
1429 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1430                 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1431                 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1432 {
1433     awstring qual, appdata;
1434
1435     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1436           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1437           pcchApplicationDataBuf);
1438
1439     qual.unicode = TRUE;
1440     qual.str.w = lpQualifierBuf;
1441
1442     appdata.unicode = TRUE;
1443     appdata.str.w = lpApplicationDataBuf;
1444
1445     return MSI_EnumComponentQualifiers( szComponent, iIndex,
1446                  &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1447 }
1448
1449 /*************************************************************************
1450  *  MsiEnumRelatedProductsW   [MSI.@]
1451  *
1452  */
1453 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1454                                     DWORD iProductIndex, LPWSTR lpProductBuf)
1455 {
1456     UINT r;
1457     HKEY hkey;
1458     DWORD dwSize = SQUISH_GUID_SIZE;
1459     WCHAR szKeyName[SQUISH_GUID_SIZE];
1460
1461     TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1462           iProductIndex, lpProductBuf);
1463
1464     if (NULL == szUpgradeCode)
1465         return ERROR_INVALID_PARAMETER;
1466     if (NULL == lpProductBuf)
1467         return ERROR_INVALID_PARAMETER;
1468
1469     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1470     if (r != ERROR_SUCCESS)
1471         return ERROR_NO_MORE_ITEMS;
1472
1473     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1474     if( r == ERROR_SUCCESS )
1475         unsquash_guid(szKeyName, lpProductBuf);
1476     RegCloseKey(hkey);
1477
1478     return r;
1479 }
1480
1481 /*************************************************************************
1482  *  MsiEnumRelatedProductsA   [MSI.@]
1483  *
1484  */
1485 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1486                                     DWORD iProductIndex, LPSTR lpProductBuf)
1487 {
1488     LPWSTR szwUpgradeCode = NULL;
1489     WCHAR productW[GUID_SIZE];
1490     UINT r;
1491
1492     TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1493           iProductIndex, lpProductBuf);
1494
1495     if (szUpgradeCode)
1496     {
1497         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1498         if( !szwUpgradeCode )
1499             return ERROR_OUTOFMEMORY;
1500     }
1501
1502     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1503                                  iProductIndex, productW );
1504     if (r == ERROR_SUCCESS)
1505     {
1506         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1507                              lpProductBuf, GUID_SIZE, NULL, NULL );
1508     }
1509     msi_free( szwUpgradeCode);
1510     return r;
1511 }
1512
1513 /***********************************************************************
1514  * MsiEnumPatchesA            [MSI.@]
1515  */
1516 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
1517         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1518 {
1519     FIXME("%s %d %p %p %p\n", debugstr_a(szProduct),
1520           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1521     return ERROR_NO_MORE_ITEMS;
1522 }
1523
1524 /***********************************************************************
1525  * MsiEnumPatchesW            [MSI.@]
1526  */
1527 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
1528         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1529 {
1530     FIXME("%s %d %p %p %p\n", debugstr_w(szProduct),
1531           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1532     return ERROR_NO_MORE_ITEMS;
1533 }
1534
1535 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
1536         DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
1537         MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
1538 {
1539     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
1540           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1541           szSid, pcchSid);
1542     return ERROR_NO_MORE_ITEMS;
1543 }
1544
1545 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
1546         DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
1547         MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
1548 {
1549     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1550           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1551           szSid, pcchSid);
1552     return ERROR_NO_MORE_ITEMS;
1553 }