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