quartz: Fix discontinuities in wave parser.
[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 static UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, LPCWSTR szUserSID,
757                                     HKEY *key, BOOL create)
758 {
759     UINT rc;
760     WCHAR squished_pc[GUID_SIZE];
761     WCHAR keypath[0x200];
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     sprintfW(keypath, szInstallProperties_fmt, szUserSID, squished_pc);
769
770     if (create)
771         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
772     else
773         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
774
775     return rc;
776 }
777
778 UINT MSIREG_OpenCurrentUserInstallProps(LPCWSTR szProduct, HKEY *key,
779                                                BOOL create)
780 {
781     UINT rc;
782     LPWSTR usersid;
783
784     rc = get_user_sid(&usersid);
785     if (rc != ERROR_SUCCESS || !usersid)
786     {
787         ERR("Failed to retrieve user SID: %d\n", rc);
788         return rc;
789     }
790
791     rc = MSIREG_OpenInstallProps(szProduct, usersid, key, create);
792
793     LocalFree(usersid);
794     return rc;
795 }
796
797 UINT MSIREG_OpenLocalSystemInstallProps(LPCWSTR szProduct, HKEY *key,
798                                         BOOL create)
799 {
800     static const WCHAR localsid[] = {'S','-','1','-','5','-','1','8',0};
801
802     return MSIREG_OpenInstallProps(szProduct, localsid, key, create);
803 }
804
805 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
806 {
807     UINT rc;
808     WCHAR squished_pc[GUID_SIZE];
809     WCHAR keypath[0x200];
810     LPWSTR usersid;
811
812     TRACE("%s\n", debugstr_w(szProduct));
813     if (!squash_guid(szProduct, squished_pc))
814         return ERROR_FUNCTION_FAILED;
815     TRACE("squished (%s)\n", debugstr_w(squished_pc));
816
817     rc = get_user_sid(&usersid);
818     if (rc != ERROR_SUCCESS || !usersid)
819     {
820         ERR("Failed to retrieve user SID: %d\n", rc);
821         return rc;
822     }
823
824     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
825
826     LocalFree(usersid);
827     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
828 }
829
830 UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
831 {
832     UINT rc;
833     WCHAR squished_pc[GUID_SIZE];
834     WCHAR keypath[0x200];
835
836     TRACE("%s\n",debugstr_w(szProduct));
837     if (!squash_guid(szProduct,squished_pc))
838         return ERROR_FUNCTION_FAILED;
839     TRACE("squished (%s)\n", debugstr_w(squished_pc));
840
841     sprintfW(keypath,szInstaller_Products_fmt,squished_pc);
842
843     if (create)
844         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
845     else
846         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
847
848     return rc;
849 }
850
851 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
852 {
853     WCHAR squished_pc[GUID_SIZE];
854     WCHAR keypath[0x200];
855
856     TRACE("%s\n", debugstr_w(szProduct));
857     if (!squash_guid(szProduct, squished_pc))
858         return ERROR_FUNCTION_FAILED;
859     TRACE("squished (%s)\n", debugstr_w(squished_pc));
860
861     sprintfW(keypath, szInstaller_Products_fmt, squished_pc);
862
863     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
864 }
865
866 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
867 {
868     UINT rc;
869     WCHAR squished_pc[GUID_SIZE];
870     WCHAR keypath[0x200];
871
872     TRACE("%s\n",debugstr_w(szPatch));
873     if (!squash_guid(szPatch,squished_pc))
874         return ERROR_FUNCTION_FAILED;
875     TRACE("squished (%s)\n", debugstr_w(squished_pc));
876
877     sprintfW(keypath,szInstaller_Patches_fmt,squished_pc);
878
879     if (create)
880         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
881     else
882         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
883
884     return rc;
885 }
886
887 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
888 {
889     UINT rc;
890     WCHAR squished_pc[GUID_SIZE];
891     WCHAR keypath[0x200];
892
893     TRACE("%s\n",debugstr_w(szUpgradeCode));
894     if (!squash_guid(szUpgradeCode,squished_pc))
895         return ERROR_FUNCTION_FAILED;
896     TRACE("squished (%s)\n", debugstr_w(squished_pc));
897
898     sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
899
900     if (create)
901         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
902     else
903         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
904
905     return rc;
906 }
907
908 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
909 {
910     UINT rc;
911     WCHAR squished_pc[GUID_SIZE];
912     WCHAR keypath[0x200];
913
914     TRACE("%s\n",debugstr_w(szUpgradeCode));
915     if (!squash_guid(szUpgradeCode,squished_pc))
916         return ERROR_FUNCTION_FAILED;
917     TRACE("squished (%s)\n", debugstr_w(squished_pc));
918
919     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
920
921     if (create)
922         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
923     else
924         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
925
926     return rc;
927 }
928
929 UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
930 {
931     WCHAR squished_pc[GUID_SIZE];
932     WCHAR keypath[0x200];
933
934     TRACE("%s\n", debugstr_w(szProductCode));
935
936     if (!squash_guid(szProductCode, squished_pc))
937         return ERROR_FUNCTION_FAILED;
938
939     TRACE("squished (%s)\n", debugstr_w(squished_pc));
940
941     sprintfW(keypath, szInstaller_LocalSystemProductCodes_fmt, squished_pc);
942
943     if (create)
944         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
945
946     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
947 }
948
949 UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
950 {
951     WCHAR squished_pc[GUID_SIZE];
952     WCHAR keypath[0x200];
953
954     TRACE("%s\n", debugstr_w(szComponent));
955
956     if (!squash_guid(szComponent, squished_pc))
957         return ERROR_FUNCTION_FAILED;
958
959     TRACE("squished (%s)\n", debugstr_w(squished_pc));
960
961     sprintfW(keypath, szInstaller_LocalSystemComponent_fmt, squished_pc);
962
963     if (create)
964         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
965
966     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
967 }
968
969 UINT MSIREG_OpenLocalClassesProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
970 {
971     WCHAR squished_pc[GUID_SIZE];
972     WCHAR keypath[0x200];
973
974     TRACE("%s\n", debugstr_w(szProductCode));
975
976     if (!squash_guid(szProductCode, squished_pc))
977         return ERROR_FUNCTION_FAILED;
978
979     TRACE("squished (%s)\n", debugstr_w(squished_pc));
980
981     sprintfW(keypath, szInstaller_LocalClassesProd_fmt, squished_pc);
982
983     if (create)
984         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
985
986     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
987 }
988
989 UINT MSIREG_OpenLocalManagedProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
990 {
991     WCHAR squished_pc[GUID_SIZE];
992     WCHAR keypath[0x200];
993     LPWSTR usersid;
994     UINT r;
995
996     TRACE("%s\n", debugstr_w(szProductCode));
997
998     if (!squash_guid(szProductCode, squished_pc))
999         return ERROR_FUNCTION_FAILED;
1000
1001     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1002
1003     r = get_user_sid(&usersid);
1004     if (r != ERROR_SUCCESS || !usersid)
1005     {
1006         ERR("Failed to retrieve user SID: %d\n", r);
1007         return r;
1008     }
1009
1010     sprintfW(keypath, szInstaller_LocalManagedProd_fmt, usersid, squished_pc);
1011     LocalFree(usersid);
1012
1013     if (create)
1014         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1015
1016     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1017 }
1018
1019 /*************************************************************************
1020  *  MsiDecomposeDescriptorW   [MSI.@]
1021  *
1022  * Decomposes an MSI descriptor into product, feature and component parts.
1023  * An MSI descriptor is a string of the form:
1024  *   [base 85 guid] [feature code] '>' [base 85 guid]
1025  *
1026  * PARAMS
1027  *   szDescriptor  [I]  the descriptor to decompose
1028  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
1029  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
1030  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
1031  *   pUsed         [O]  the length of the descriptor
1032  *
1033  * RETURNS
1034  *   ERROR_SUCCESS             if everything worked correctly
1035  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
1036  *
1037  */
1038 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1039                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1040 {
1041     UINT r, len;
1042     LPWSTR p;
1043     GUID product, component;
1044
1045     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1046           szFeature, szComponent, pUsed);
1047
1048     r = decode_base85_guid( szDescriptor, &product );
1049     if( !r )
1050         return ERROR_INVALID_PARAMETER;
1051
1052     TRACE("product %s\n", debugstr_guid( &product ));
1053
1054     p = strchrW(&szDescriptor[20],'>');
1055     if( !p )
1056         return ERROR_INVALID_PARAMETER;
1057
1058     len = (p - &szDescriptor[20]);
1059     if( len > MAX_FEATURE_CHARS )
1060         return ERROR_INVALID_PARAMETER;
1061
1062     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1063
1064     r = decode_base85_guid( p+1, &component );
1065     if( !r )
1066         return ERROR_INVALID_PARAMETER;
1067
1068     TRACE("component %s\n", debugstr_guid( &component ));
1069
1070     if (szProduct)
1071         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1072     if (szComponent)
1073         StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1074     if (szFeature)
1075     {
1076         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1077         szFeature[len] = 0;
1078     }
1079     len = ( &p[21] - szDescriptor );
1080
1081     TRACE("length = %d\n", len);
1082     *pUsed = len;
1083
1084     return ERROR_SUCCESS;
1085 }
1086
1087 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1088                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1089 {
1090     WCHAR product[MAX_FEATURE_CHARS+1];
1091     WCHAR feature[MAX_FEATURE_CHARS+1];
1092     WCHAR component[MAX_FEATURE_CHARS+1];
1093     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1094     UINT r;
1095
1096     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1097           szFeature, szComponent, pUsed);
1098
1099     str = strdupAtoW( szDescriptor );
1100     if( szDescriptor && !str )
1101         return ERROR_OUTOFMEMORY;
1102
1103     if (szProduct)
1104         p = product;
1105     if (szFeature)
1106         f = feature;
1107     if (szComponent)
1108         c = component;
1109
1110     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1111
1112     if (r == ERROR_SUCCESS)
1113     {
1114         WideCharToMultiByte( CP_ACP, 0, p, -1,
1115                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1116         WideCharToMultiByte( CP_ACP, 0, f, -1,
1117                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1118         WideCharToMultiByte( CP_ACP, 0, c, -1,
1119                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1120     }
1121
1122     msi_free( str );
1123
1124     return r;
1125 }
1126
1127 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1128 {
1129     DWORD r;
1130     WCHAR szwGuid[GUID_SIZE];
1131
1132     TRACE("%d %p\n", index, lpguid);
1133
1134     if (NULL == lpguid)
1135         return ERROR_INVALID_PARAMETER;
1136     r = MsiEnumProductsW(index, szwGuid);
1137     if( r == ERROR_SUCCESS )
1138         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1139
1140     return r;
1141 }
1142
1143 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1144 {
1145     HKEY hkeyProducts = 0;
1146     DWORD r;
1147     WCHAR szKeyName[SQUISH_GUID_SIZE];
1148
1149     TRACE("%d %p\n", index, lpguid);
1150
1151     if (NULL == lpguid)
1152         return ERROR_INVALID_PARAMETER;
1153
1154     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Products, &hkeyProducts);
1155     if( r != ERROR_SUCCESS )
1156         return ERROR_NO_MORE_ITEMS;
1157
1158     r = RegEnumKeyW(hkeyProducts, index, szKeyName, SQUISH_GUID_SIZE);
1159     if( r == ERROR_SUCCESS )
1160         unsquash_guid(szKeyName, lpguid);
1161     RegCloseKey(hkeyProducts);
1162
1163     return r;
1164 }
1165
1166 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
1167       LPSTR szFeature, LPSTR szParent)
1168 {
1169     DWORD r;
1170     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1171     LPWSTR szwProduct = NULL;
1172
1173     TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1174
1175     if( szProduct )
1176     {
1177         szwProduct = strdupAtoW( szProduct );
1178         if( !szwProduct )
1179             return ERROR_OUTOFMEMORY;
1180     }
1181
1182     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1183     if( r == ERROR_SUCCESS )
1184     {
1185         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1186                             szFeature, GUID_SIZE, NULL, NULL);
1187         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1188                             szParent, GUID_SIZE, NULL, NULL);
1189     }
1190
1191     msi_free( szwProduct);
1192
1193     return r;
1194 }
1195
1196 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
1197       LPWSTR szFeature, LPWSTR szParent)
1198 {
1199     HKEY hkeyProduct = 0;
1200     DWORD r, sz;
1201
1202     TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1203
1204     if( !szProduct )
1205         return ERROR_INVALID_PARAMETER;
1206
1207     r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
1208     if( r != ERROR_SUCCESS )
1209         return ERROR_NO_MORE_ITEMS;
1210
1211     sz = GUID_SIZE;
1212     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1213     RegCloseKey(hkeyProduct);
1214
1215     return r;
1216 }
1217
1218 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1219 {
1220     DWORD r;
1221     WCHAR szwGuid[GUID_SIZE];
1222
1223     TRACE("%d %p\n", index, lpguid);
1224
1225     r = MsiEnumComponentsW(index, szwGuid);
1226     if( r == ERROR_SUCCESS )
1227         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1228
1229     return r;
1230 }
1231
1232 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1233 {
1234     HKEY hkeyComponents = 0;
1235     DWORD r;
1236     WCHAR szKeyName[SQUISH_GUID_SIZE];
1237
1238     TRACE("%d %p\n", index, lpguid);
1239
1240     r = MSIREG_OpenComponents(&hkeyComponents);
1241     if( r != ERROR_SUCCESS )
1242         return ERROR_NO_MORE_ITEMS;
1243
1244     r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
1245     if( r == ERROR_SUCCESS )
1246         unsquash_guid(szKeyName, lpguid);
1247     RegCloseKey(hkeyComponents);
1248
1249     return r;
1250 }
1251
1252 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1253 {
1254     DWORD r;
1255     WCHAR szwProduct[GUID_SIZE];
1256     LPWSTR szwComponent = NULL;
1257
1258     TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1259
1260     if ( !szProduct )
1261         return ERROR_INVALID_PARAMETER;
1262
1263     if( szComponent )
1264     {
1265         szwComponent = strdupAtoW( szComponent );
1266         if( !szwComponent )
1267             return ERROR_OUTOFMEMORY;
1268     }
1269
1270     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1271     if( r == ERROR_SUCCESS )
1272     {
1273         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1274                             szProduct, GUID_SIZE, NULL, NULL);
1275     }
1276
1277     msi_free( szwComponent);
1278
1279     return r;
1280 }
1281
1282 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1283 {
1284     HKEY hkeyComp = 0;
1285     DWORD r, sz;
1286     WCHAR szValName[SQUISH_GUID_SIZE];
1287
1288     TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1289
1290     if (!szComponent || !*szComponent || !szProduct)
1291         return ERROR_INVALID_PARAMETER;
1292
1293     if (MSIREG_OpenUserDataComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1294         MSIREG_OpenLocalSystemComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS)
1295         return ERROR_UNKNOWN_COMPONENT;
1296
1297     /* see if there are any products at all */
1298     sz = SQUISH_GUID_SIZE;
1299     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1300     if (r != ERROR_SUCCESS)
1301     {
1302         RegCloseKey(hkeyComp);
1303
1304         if (index != 0)
1305             return ERROR_INVALID_PARAMETER;
1306
1307         return ERROR_UNKNOWN_COMPONENT;
1308     }
1309
1310     sz = SQUISH_GUID_SIZE;
1311     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1312     if( r == ERROR_SUCCESS )
1313         unsquash_guid(szValName, szProduct);
1314
1315     RegCloseKey(hkeyComp);
1316
1317     return r;
1318 }
1319
1320 static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1321                 awstring *lpQualBuf, LPDWORD pcchQual,
1322                 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1323 {
1324     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1325     LPWSTR name = NULL, val = NULL;
1326     UINT r, r2;
1327     HKEY key;
1328
1329     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1330           lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1331
1332     if (!szComponent)
1333         return ERROR_INVALID_PARAMETER;
1334
1335     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1336     if (r != ERROR_SUCCESS)
1337         return ERROR_UNKNOWN_COMPONENT;
1338
1339     /* figure out how big the name is we want to return */
1340     name_max = 0x10;
1341     r = ERROR_OUTOFMEMORY;
1342     name = msi_alloc( name_max * sizeof(WCHAR) );
1343     if (!name)
1344         goto end;
1345
1346     val_max = 0x10;
1347     r = ERROR_OUTOFMEMORY;
1348     val = msi_alloc( val_max );
1349     if (!val)
1350         goto end;
1351
1352     /* loop until we allocate enough memory */
1353     while (1)
1354     {
1355         name_sz = name_max;
1356         val_sz = val_max;
1357         r = RegEnumValueW( key, iIndex, name, &name_sz,
1358                            NULL, &type, (LPBYTE)val, &val_sz );
1359         if (r == ERROR_SUCCESS)
1360             break;
1361         if (r != ERROR_MORE_DATA)
1362             goto end;
1363  
1364         if (type != REG_MULTI_SZ)
1365         {
1366             ERR("component data has wrong type (%d)\n", type);
1367             goto end;
1368         }
1369
1370         r = ERROR_OUTOFMEMORY;
1371         if ((name_sz+1) >= name_max)
1372         {
1373             name_max *= 2;
1374             msi_free( name );
1375             name = msi_alloc( name_max * sizeof (WCHAR) );
1376             if (!name)
1377                 goto end;
1378             continue;
1379         }
1380         if (val_sz > val_max)
1381         {
1382             val_max = val_sz + sizeof (WCHAR);
1383             msi_free( val );
1384             val = msi_alloc( val_max * sizeof (WCHAR) );
1385             if (!val)
1386                 goto end;
1387             continue;
1388         }
1389         ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1390         goto end;
1391     }
1392
1393     ofs = 0;
1394     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1395     if (r != ERROR_SUCCESS)
1396         goto end;
1397
1398     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1399
1400     r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1401     r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1402
1403     if (r2 != ERROR_SUCCESS)
1404         r = r2;
1405
1406 end:
1407     msi_free(val);
1408     msi_free(name);
1409     RegCloseKey(key);
1410
1411     return r;
1412 }
1413
1414 /*************************************************************************
1415  *  MsiEnumComponentQualifiersA [MSI.@]
1416  */
1417 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1418                 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1419                 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1420 {
1421     awstring qual, appdata;
1422     LPWSTR comp;
1423     UINT r;
1424
1425     TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1426           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1427           pcchApplicationDataBuf);
1428
1429     comp = strdupAtoW( szComponent );
1430     if (szComponent && !comp)
1431         return ERROR_OUTOFMEMORY;
1432
1433     qual.unicode = FALSE;
1434     qual.str.a = lpQualifierBuf;
1435
1436     appdata.unicode = FALSE;
1437     appdata.str.a = lpApplicationDataBuf;
1438
1439     r = MSI_EnumComponentQualifiers( comp, iIndex,
1440               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1441     msi_free( comp );
1442     return r;
1443 }
1444
1445 /*************************************************************************
1446  *  MsiEnumComponentQualifiersW [MSI.@]
1447  */
1448 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1449                 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1450                 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1451 {
1452     awstring qual, appdata;
1453
1454     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1455           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1456           pcchApplicationDataBuf);
1457
1458     qual.unicode = TRUE;
1459     qual.str.w = lpQualifierBuf;
1460
1461     appdata.unicode = TRUE;
1462     appdata.str.w = lpApplicationDataBuf;
1463
1464     return MSI_EnumComponentQualifiers( szComponent, iIndex,
1465                  &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1466 }
1467
1468 /*************************************************************************
1469  *  MsiEnumRelatedProductsW   [MSI.@]
1470  *
1471  */
1472 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1473                                     DWORD iProductIndex, LPWSTR lpProductBuf)
1474 {
1475     UINT r;
1476     HKEY hkey;
1477     DWORD dwSize = SQUISH_GUID_SIZE;
1478     WCHAR szKeyName[SQUISH_GUID_SIZE];
1479
1480     TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1481           iProductIndex, lpProductBuf);
1482
1483     if (NULL == szUpgradeCode)
1484         return ERROR_INVALID_PARAMETER;
1485     if (NULL == lpProductBuf)
1486         return ERROR_INVALID_PARAMETER;
1487
1488     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1489     if (r != ERROR_SUCCESS)
1490         return ERROR_NO_MORE_ITEMS;
1491
1492     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1493     if( r == ERROR_SUCCESS )
1494         unsquash_guid(szKeyName, lpProductBuf);
1495     RegCloseKey(hkey);
1496
1497     return r;
1498 }
1499
1500 /*************************************************************************
1501  *  MsiEnumRelatedProductsA   [MSI.@]
1502  *
1503  */
1504 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1505                                     DWORD iProductIndex, LPSTR lpProductBuf)
1506 {
1507     LPWSTR szwUpgradeCode = NULL;
1508     WCHAR productW[GUID_SIZE];
1509     UINT r;
1510
1511     TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1512           iProductIndex, lpProductBuf);
1513
1514     if (szUpgradeCode)
1515     {
1516         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1517         if( !szwUpgradeCode )
1518             return ERROR_OUTOFMEMORY;
1519     }
1520
1521     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1522                                  iProductIndex, productW );
1523     if (r == ERROR_SUCCESS)
1524     {
1525         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1526                              lpProductBuf, GUID_SIZE, NULL, NULL );
1527     }
1528     msi_free( szwUpgradeCode);
1529     return r;
1530 }
1531
1532 /***********************************************************************
1533  * MsiEnumPatchesA            [MSI.@]
1534  */
1535 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
1536         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1537 {
1538     FIXME("%s %d %p %p %p\n", debugstr_a(szProduct),
1539           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1540     return ERROR_NO_MORE_ITEMS;
1541 }
1542
1543 /***********************************************************************
1544  * MsiEnumPatchesW            [MSI.@]
1545  */
1546 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
1547         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1548 {
1549     FIXME("%s %d %p %p %p\n", debugstr_w(szProduct),
1550           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1551     return ERROR_NO_MORE_ITEMS;
1552 }
1553
1554 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
1555         DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
1556         MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
1557 {
1558     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
1559           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1560           szSid, pcchSid);
1561     return ERROR_NO_MORE_ITEMS;
1562 }
1563
1564 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
1565         DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
1566         MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
1567 {
1568     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1569           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1570           szSid, pcchSid);
1571     return ERROR_NO_MORE_ITEMS;
1572 }