msi: Handle the machine context in MsiQueryFeatureState.
[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_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
529 {
530     UINT rc;
531     WCHAR squished_pc[GUID_SIZE];
532     WCHAR keypath[0x200];
533
534     TRACE("%s\n",debugstr_w(szProduct));
535     if (!squash_guid(szProduct,squished_pc))
536         return ERROR_FUNCTION_FAILED;
537     TRACE("squished (%s)\n", debugstr_w(squished_pc));
538
539     sprintfW(keypath,szUserProduct_fmt,squished_pc);
540
541     if (create)
542         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
543     else
544         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
545
546     return rc;
547 }
548
549 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
550 {
551     WCHAR squished_pc[GUID_SIZE];
552     WCHAR keypath[0x200];
553
554     TRACE("%s\n",debugstr_w(szProduct));
555     if (!squash_guid(szProduct,squished_pc))
556         return ERROR_FUNCTION_FAILED;
557     TRACE("squished (%s)\n", debugstr_w(squished_pc));
558
559     sprintfW(keypath,szUserProduct_fmt,squished_pc);
560
561     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
562 }
563
564 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
565 {
566     UINT rc;
567     WCHAR squished_pc[GUID_SIZE];
568     WCHAR keypath[0x200];
569
570     TRACE("%s\n",debugstr_w(szPatch));
571     if (!squash_guid(szPatch,squished_pc))
572         return ERROR_FUNCTION_FAILED;
573     TRACE("squished (%s)\n", debugstr_w(squished_pc));
574
575     sprintfW(keypath,szUserPatch_fmt,squished_pc);
576
577     if (create)
578         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
579     else
580         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
581
582     return rc;
583 }
584
585 UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
586 {
587     UINT rc;
588     WCHAR squished_pc[GUID_SIZE];
589     WCHAR keypath[0x200];
590
591     TRACE("%s\n",debugstr_w(szProduct));
592     if (!squash_guid(szProduct,squished_pc))
593         return ERROR_FUNCTION_FAILED;
594     TRACE("squished (%s)\n", debugstr_w(squished_pc));
595
596     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
597
598     if (create)
599         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
600     else
601         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
602
603     return rc;
604 }
605
606 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
607 {
608     WCHAR squished_pc[GUID_SIZE];
609     WCHAR keypath[0x200];
610
611     TRACE("%s\n",debugstr_w(szProduct));
612     if (!squash_guid(szProduct,squished_pc))
613         return ERROR_FUNCTION_FAILED;
614     TRACE("squished (%s)\n", debugstr_w(squished_pc));
615
616     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
617     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
618 }
619
620 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
621 {
622     UINT rc;
623     WCHAR squished_pc[GUID_SIZE];
624     WCHAR keypath[0x200];
625
626     TRACE("%s\n",debugstr_w(szProduct));
627     if (!squash_guid(szProduct,squished_pc))
628         return ERROR_FUNCTION_FAILED;
629     TRACE("squished (%s)\n", debugstr_w(squished_pc));
630
631     sprintfW(keypath,szInstaller_Features_fmt,squished_pc);
632
633     if (create)
634         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
635     else
636         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
637
638     return rc;
639 }
640
641 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
642 {
643     UINT rc;
644     WCHAR squished_pc[GUID_SIZE];
645     WCHAR keypath[0x200];
646     LPWSTR usersid;
647
648     TRACE("%s\n", debugstr_w(szProduct));
649     if (!squash_guid(szProduct, squished_pc))
650         return ERROR_FUNCTION_FAILED;
651     TRACE("squished (%s)\n", debugstr_w(squished_pc));
652
653     rc = get_user_sid(&usersid);
654     if (rc != ERROR_SUCCESS || !usersid)
655     {
656         ERR("Failed to retrieve user SID: %d\n", rc);
657         return rc;
658     }
659
660     sprintfW(keypath, szUserDataFeatures_fmt, usersid, squished_pc);
661
662     if (create)
663         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
664     else
665         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
666
667     LocalFree(usersid);
668     return rc;
669 }
670
671 UINT MSIREG_OpenLocalUserDataFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
672 {
673     WCHAR squished_pc[GUID_SIZE];
674     WCHAR keypath[0x200];
675
676     TRACE("%s\n", debugstr_w(szProduct));
677     if (!squash_guid(szProduct, squished_pc))
678         return ERROR_FUNCTION_FAILED;
679     TRACE("squished (%s)\n", debugstr_w(squished_pc));
680
681     sprintfW(keypath, szUserDataFeatures_fmt, localsid, squished_pc);
682
683     if (create)
684         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
685
686     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
687 }
688
689 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
690 {
691     UINT rc;
692     WCHAR squished_cc[GUID_SIZE];
693     WCHAR keypath[0x200];
694
695     TRACE("%s\n",debugstr_w(szComponent));
696     if (!squash_guid(szComponent,squished_cc))
697         return ERROR_FUNCTION_FAILED;
698     TRACE("squished (%s)\n", debugstr_w(squished_cc));
699
700     sprintfW(keypath,szUser_Components_fmt,squished_cc);
701
702     if (create)
703         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
704     else
705         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
706
707     return rc;
708 }
709
710 UINT MSIREG_OpenLocalUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
711 {
712     WCHAR comp[GUID_SIZE];
713     WCHAR keypath[0x200];
714
715     TRACE("%s\n", debugstr_w(szComponent));
716     if (!squash_guid(szComponent, comp))
717         return ERROR_FUNCTION_FAILED;
718     TRACE("squished (%s)\n", debugstr_w(comp));
719
720     sprintfW(keypath, szUserDataComp_fmt, localsid, comp);
721
722     if (create)
723         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
724
725     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
726 }
727
728 UINT MSIREG_DeleteLocalUserDataComponentKey(LPCWSTR szComponent)
729 {
730     WCHAR comp[GUID_SIZE];
731     WCHAR keypath[0x200];
732
733     TRACE("%s\n", debugstr_w(szComponent));
734     if (!squash_guid(szComponent, comp))
735         return ERROR_FUNCTION_FAILED;
736     TRACE("squished (%s)\n", debugstr_w(comp));
737
738     sprintfW(keypath, szUserDataComp_fmt, localsid, comp);
739     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
740 }
741
742 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
743 {
744     UINT rc;
745     WCHAR comp[GUID_SIZE];
746     WCHAR keypath[0x200];
747     LPWSTR usersid;
748
749     TRACE("%s\n", debugstr_w(szComponent));
750     if (!squash_guid(szComponent, comp))
751         return ERROR_FUNCTION_FAILED;
752     TRACE("squished (%s)\n", debugstr_w(comp));
753
754     rc = get_user_sid(&usersid);
755     if (rc != ERROR_SUCCESS || !usersid)
756     {
757         ERR("Failed to retrieve user SID: %d\n", rc);
758         return rc;
759     }
760
761     sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
762
763     if (create)
764         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
765     else
766         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
767
768     LocalFree(usersid);
769     return rc;
770 }
771
772 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent)
773 {
774     UINT rc;
775     WCHAR comp[GUID_SIZE];
776     WCHAR keypath[0x200];
777     LPWSTR usersid;
778
779     TRACE("%s\n", debugstr_w(szComponent));
780     if (!squash_guid(szComponent, comp))
781         return ERROR_FUNCTION_FAILED;
782     TRACE("squished (%s)\n", debugstr_w(comp));
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     sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
792
793     LocalFree(usersid);
794     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
795 }
796
797 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
798 {
799     UINT rc;
800     WCHAR squished_pc[GUID_SIZE];
801     WCHAR keypath[0x200];
802     LPWSTR usersid;
803
804     TRACE("%s\n", debugstr_w(szProduct));
805     if (!squash_guid(szProduct, squished_pc))
806         return ERROR_FUNCTION_FAILED;
807     TRACE("squished (%s)\n", debugstr_w(squished_pc));
808
809     rc = get_user_sid(&usersid);
810     if (rc != ERROR_SUCCESS || !usersid)
811     {
812         ERR("Failed to retrieve user SID: %d\n", rc);
813         return rc;
814     }
815
816     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
817
818     if (create)
819         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
820     else
821         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
822
823     LocalFree(usersid);
824     return rc;
825 }
826
827 UINT MSIREG_OpenLocalUserDataProductKey(LPCWSTR szProduct, HKEY *key, BOOL create)
828 {
829     WCHAR squished_pc[GUID_SIZE];
830     WCHAR keypath[0x200];
831
832     TRACE("%s\n", debugstr_w(szProduct));
833     if (!squash_guid(szProduct, squished_pc))
834         return ERROR_FUNCTION_FAILED;
835     TRACE("squished (%s)\n", debugstr_w(squished_pc));
836
837     sprintfW(keypath, szUserDataProd_fmt, localsid, squished_pc);
838
839     if (create)
840         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
841
842     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
843 }
844
845 static UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, LPCWSTR szUserSID,
846                                     HKEY *key, BOOL create)
847 {
848     UINT rc;
849     WCHAR squished_pc[GUID_SIZE];
850     WCHAR keypath[0x200];
851
852     TRACE("%s\n", debugstr_w(szProduct));
853     if (!squash_guid(szProduct, squished_pc))
854         return ERROR_FUNCTION_FAILED;
855     TRACE("squished (%s)\n", debugstr_w(squished_pc));
856
857     sprintfW(keypath, szInstallProperties_fmt, szUserSID, squished_pc);
858
859     if (create)
860         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
861     else
862         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
863
864     return rc;
865 }
866
867 UINT MSIREG_OpenCurrentUserInstallProps(LPCWSTR szProduct, HKEY *key,
868                                                BOOL create)
869 {
870     UINT rc;
871     LPWSTR usersid;
872
873     rc = get_user_sid(&usersid);
874     if (rc != ERROR_SUCCESS || !usersid)
875     {
876         ERR("Failed to retrieve user SID: %d\n", rc);
877         return rc;
878     }
879
880     rc = MSIREG_OpenInstallProps(szProduct, usersid, key, create);
881
882     LocalFree(usersid);
883     return rc;
884 }
885
886 UINT MSIREG_OpenLocalSystemInstallProps(LPCWSTR szProduct, HKEY *key,
887                                         BOOL create)
888 {
889     return MSIREG_OpenInstallProps(szProduct, localsid, key, create);
890 }
891
892 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
893 {
894     UINT rc;
895     WCHAR squished_pc[GUID_SIZE];
896     WCHAR keypath[0x200];
897     LPWSTR usersid;
898
899     TRACE("%s\n", debugstr_w(szProduct));
900     if (!squash_guid(szProduct, squished_pc))
901         return ERROR_FUNCTION_FAILED;
902     TRACE("squished (%s)\n", debugstr_w(squished_pc));
903
904     rc = get_user_sid(&usersid);
905     if (rc != ERROR_SUCCESS || !usersid)
906     {
907         ERR("Failed to retrieve user SID: %d\n", rc);
908         return rc;
909     }
910
911     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
912
913     LocalFree(usersid);
914     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
915 }
916
917 UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create)
918 {
919     UINT rc;
920     WCHAR squished_pc[GUID_SIZE];
921     WCHAR keypath[0x200];
922
923     TRACE("%s\n",debugstr_w(szProduct));
924     if (!squash_guid(szProduct,squished_pc))
925         return ERROR_FUNCTION_FAILED;
926     TRACE("squished (%s)\n", debugstr_w(squished_pc));
927
928     sprintfW(keypath,szInstaller_Products_fmt,squished_pc);
929
930     if (create)
931         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
932     else
933         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
934
935     return rc;
936 }
937
938 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
939 {
940     WCHAR squished_pc[GUID_SIZE];
941     WCHAR keypath[0x200];
942
943     TRACE("%s\n", debugstr_w(szProduct));
944     if (!squash_guid(szProduct, squished_pc))
945         return ERROR_FUNCTION_FAILED;
946     TRACE("squished (%s)\n", debugstr_w(squished_pc));
947
948     sprintfW(keypath, szInstaller_Products_fmt, squished_pc);
949
950     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
951 }
952
953 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
954 {
955     UINT rc;
956     WCHAR squished_pc[GUID_SIZE];
957     WCHAR keypath[0x200];
958
959     TRACE("%s\n",debugstr_w(szPatch));
960     if (!squash_guid(szPatch,squished_pc))
961         return ERROR_FUNCTION_FAILED;
962     TRACE("squished (%s)\n", debugstr_w(squished_pc));
963
964     sprintfW(keypath,szInstaller_Patches_fmt,squished_pc);
965
966     if (create)
967         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
968     else
969         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
970
971     return rc;
972 }
973
974 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
975 {
976     UINT rc;
977     WCHAR squished_pc[GUID_SIZE];
978     WCHAR keypath[0x200];
979
980     TRACE("%s\n",debugstr_w(szUpgradeCode));
981     if (!squash_guid(szUpgradeCode,squished_pc))
982         return ERROR_FUNCTION_FAILED;
983     TRACE("squished (%s)\n", debugstr_w(squished_pc));
984
985     sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
986
987     if (create)
988         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
989     else
990         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
991
992     return rc;
993 }
994
995 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
996 {
997     UINT rc;
998     WCHAR squished_pc[GUID_SIZE];
999     WCHAR keypath[0x200];
1000
1001     TRACE("%s\n",debugstr_w(szUpgradeCode));
1002     if (!squash_guid(szUpgradeCode,squished_pc))
1003         return ERROR_FUNCTION_FAILED;
1004     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1005
1006     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
1007
1008     if (create)
1009         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
1010     else
1011         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
1012
1013     return rc;
1014 }
1015
1016 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
1017 {
1018     WCHAR squished_pc[GUID_SIZE];
1019     WCHAR keypath[0x200];
1020
1021     TRACE("%s\n",debugstr_w(szUpgradeCode));
1022     if (!squash_guid(szUpgradeCode,squished_pc))
1023         return ERROR_FUNCTION_FAILED;
1024     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1025
1026     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
1027
1028     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
1029 }
1030
1031 UINT MSIREG_OpenLocalSystemProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
1032 {
1033     WCHAR squished_pc[GUID_SIZE];
1034     WCHAR keypath[0x200];
1035
1036     TRACE("%s\n", debugstr_w(szProductCode));
1037
1038     if (!squash_guid(szProductCode, squished_pc))
1039         return ERROR_FUNCTION_FAILED;
1040
1041     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1042
1043     sprintfW(keypath, szInstaller_LocalSystemProductCodes_fmt, squished_pc);
1044
1045     if (create)
1046         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1047
1048     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1049 }
1050
1051 UINT MSIREG_OpenLocalSystemComponentKey(LPCWSTR szComponent, HKEY *key, BOOL create)
1052 {
1053     WCHAR squished_pc[GUID_SIZE];
1054     WCHAR keypath[0x200];
1055
1056     TRACE("%s\n", debugstr_w(szComponent));
1057
1058     if (!squash_guid(szComponent, squished_pc))
1059         return ERROR_FUNCTION_FAILED;
1060
1061     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1062
1063     sprintfW(keypath, szInstaller_LocalSystemComponent_fmt, squished_pc);
1064
1065     if (create)
1066         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1067
1068     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1069 }
1070
1071 UINT MSIREG_OpenLocalClassesProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
1072 {
1073     WCHAR squished_pc[GUID_SIZE];
1074     WCHAR keypath[0x200];
1075
1076     TRACE("%s\n", debugstr_w(szProductCode));
1077
1078     if (!squash_guid(szProductCode, squished_pc))
1079         return ERROR_FUNCTION_FAILED;
1080
1081     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1082
1083     sprintfW(keypath, szInstaller_LocalClassesProd_fmt, squished_pc);
1084
1085     if (create)
1086         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1087
1088     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1089 }
1090
1091 UINT MSIREG_OpenLocalClassesFeaturesKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
1092 {
1093     WCHAR squished_pc[GUID_SIZE];
1094     WCHAR keypath[0x200];
1095
1096     TRACE("%s\n", debugstr_w(szProductCode));
1097
1098     if (!squash_guid(szProductCode, squished_pc))
1099         return ERROR_FUNCTION_FAILED;
1100
1101     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1102
1103     sprintfW(keypath, szInstaller_LocalClassesFeat_fmt, squished_pc);
1104
1105     if (create)
1106         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1107
1108     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1109 }
1110
1111 UINT MSIREG_OpenLocalManagedProductKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
1112 {
1113     WCHAR squished_pc[GUID_SIZE];
1114     WCHAR keypath[0x200];
1115     LPWSTR usersid;
1116     UINT r;
1117
1118     TRACE("%s\n", debugstr_w(szProductCode));
1119
1120     if (!squash_guid(szProductCode, squished_pc))
1121         return ERROR_FUNCTION_FAILED;
1122
1123     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1124
1125     r = get_user_sid(&usersid);
1126     if (r != ERROR_SUCCESS || !usersid)
1127     {
1128         ERR("Failed to retrieve user SID: %d\n", r);
1129         return r;
1130     }
1131
1132     sprintfW(keypath, szInstaller_LocalManagedProd_fmt, usersid, squished_pc);
1133     LocalFree(usersid);
1134
1135     if (create)
1136         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1137
1138     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1139 }
1140
1141 UINT MSIREG_OpenManagedFeaturesKey(LPCWSTR szProductCode, HKEY *key, BOOL create)
1142 {
1143     WCHAR squished_pc[GUID_SIZE];
1144     WCHAR keypath[0x200];
1145     LPWSTR usersid;
1146     UINT r;
1147
1148     TRACE("%s\n", debugstr_w(szProductCode));
1149
1150     if (!squash_guid(szProductCode, squished_pc))
1151         return ERROR_FUNCTION_FAILED;
1152
1153     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1154
1155     r = get_user_sid(&usersid);
1156     if (r != ERROR_SUCCESS || !usersid)
1157     {
1158         ERR("Failed to retrieve user SID: %d\n", r);
1159         return r;
1160     }
1161
1162     sprintfW(keypath, szInstaller_LocalManagedFeat_fmt, usersid, squished_pc);
1163     LocalFree(usersid);
1164
1165     if (create)
1166         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1167
1168     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1169 }
1170
1171 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
1172 {
1173     WCHAR squished_pc[GUID_SIZE];
1174     WCHAR keypath[0x200];
1175
1176     TRACE("%s\n", debugstr_w(szUpgradeCode));
1177     if (!squash_guid(szUpgradeCode, squished_pc))
1178         return ERROR_FUNCTION_FAILED;
1179     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1180
1181     sprintfW(keypath, szInstaller_ClassesUpgrade_fmt, squished_pc);
1182
1183     if (create)
1184         return RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, key);
1185
1186     return RegOpenKeyW(HKEY_CLASSES_ROOT, keypath, key);
1187 }
1188
1189 /*************************************************************************
1190  *  MsiDecomposeDescriptorW   [MSI.@]
1191  *
1192  * Decomposes an MSI descriptor into product, feature and component parts.
1193  * An MSI descriptor is a string of the form:
1194  *   [base 85 guid] [feature code] '>' [base 85 guid]
1195  *
1196  * PARAMS
1197  *   szDescriptor  [I]  the descriptor to decompose
1198  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
1199  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
1200  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
1201  *   pUsed         [O]  the length of the descriptor
1202  *
1203  * RETURNS
1204  *   ERROR_SUCCESS             if everything worked correctly
1205  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
1206  *
1207  */
1208 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1209                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1210 {
1211     UINT r, len;
1212     LPWSTR p;
1213     GUID product, component;
1214
1215     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1216           szFeature, szComponent, pUsed);
1217
1218     r = decode_base85_guid( szDescriptor, &product );
1219     if( !r )
1220         return ERROR_INVALID_PARAMETER;
1221
1222     TRACE("product %s\n", debugstr_guid( &product ));
1223
1224     p = strchrW(&szDescriptor[20],'>');
1225     if( !p )
1226         return ERROR_INVALID_PARAMETER;
1227
1228     len = (p - &szDescriptor[20]);
1229     if( len > MAX_FEATURE_CHARS )
1230         return ERROR_INVALID_PARAMETER;
1231
1232     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1233
1234     r = decode_base85_guid( p+1, &component );
1235     if( !r )
1236         return ERROR_INVALID_PARAMETER;
1237
1238     TRACE("component %s\n", debugstr_guid( &component ));
1239
1240     if (szProduct)
1241         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1242     if (szComponent)
1243         StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1244     if (szFeature)
1245     {
1246         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1247         szFeature[len] = 0;
1248     }
1249     len = ( &p[21] - szDescriptor );
1250
1251     TRACE("length = %d\n", len);
1252     *pUsed = len;
1253
1254     return ERROR_SUCCESS;
1255 }
1256
1257 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1258                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1259 {
1260     WCHAR product[MAX_FEATURE_CHARS+1];
1261     WCHAR feature[MAX_FEATURE_CHARS+1];
1262     WCHAR component[MAX_FEATURE_CHARS+1];
1263     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1264     UINT r;
1265
1266     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1267           szFeature, szComponent, pUsed);
1268
1269     str = strdupAtoW( szDescriptor );
1270     if( szDescriptor && !str )
1271         return ERROR_OUTOFMEMORY;
1272
1273     if (szProduct)
1274         p = product;
1275     if (szFeature)
1276         f = feature;
1277     if (szComponent)
1278         c = component;
1279
1280     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1281
1282     if (r == ERROR_SUCCESS)
1283     {
1284         WideCharToMultiByte( CP_ACP, 0, p, -1,
1285                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1286         WideCharToMultiByte( CP_ACP, 0, f, -1,
1287                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1288         WideCharToMultiByte( CP_ACP, 0, c, -1,
1289                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1290     }
1291
1292     msi_free( str );
1293
1294     return r;
1295 }
1296
1297 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1298 {
1299     DWORD r;
1300     WCHAR szwGuid[GUID_SIZE];
1301
1302     TRACE("%d %p\n", index, lpguid);
1303
1304     if (NULL == lpguid)
1305         return ERROR_INVALID_PARAMETER;
1306     r = MsiEnumProductsW(index, szwGuid);
1307     if( r == ERROR_SUCCESS )
1308         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1309
1310     return r;
1311 }
1312
1313 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1314 {
1315     HKEY hkeyProducts = 0;
1316     DWORD r;
1317     WCHAR szKeyName[SQUISH_GUID_SIZE];
1318
1319     TRACE("%d %p\n", index, lpguid);
1320
1321     if (NULL == lpguid)
1322         return ERROR_INVALID_PARAMETER;
1323
1324     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Products, &hkeyProducts);
1325     if( r != ERROR_SUCCESS )
1326         return ERROR_NO_MORE_ITEMS;
1327
1328     r = RegEnumKeyW(hkeyProducts, index, szKeyName, SQUISH_GUID_SIZE);
1329     if( r == ERROR_SUCCESS )
1330         unsquash_guid(szKeyName, lpguid);
1331     RegCloseKey(hkeyProducts);
1332
1333     return r;
1334 }
1335
1336 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
1337       LPSTR szFeature, LPSTR szParent)
1338 {
1339     DWORD r;
1340     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1341     LPWSTR szwProduct = NULL;
1342
1343     TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1344
1345     if( szProduct )
1346     {
1347         szwProduct = strdupAtoW( szProduct );
1348         if( !szwProduct )
1349             return ERROR_OUTOFMEMORY;
1350     }
1351
1352     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1353     if( r == ERROR_SUCCESS )
1354     {
1355         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1356                             szFeature, GUID_SIZE, NULL, NULL);
1357         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1358                             szParent, GUID_SIZE, NULL, NULL);
1359     }
1360
1361     msi_free( szwProduct);
1362
1363     return r;
1364 }
1365
1366 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
1367       LPWSTR szFeature, LPWSTR szParent)
1368 {
1369     HKEY hkeyProduct = 0;
1370     DWORD r, sz;
1371
1372     TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1373
1374     if( !szProduct )
1375         return ERROR_INVALID_PARAMETER;
1376
1377     r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE);
1378     if( r != ERROR_SUCCESS )
1379         return ERROR_NO_MORE_ITEMS;
1380
1381     sz = GUID_SIZE;
1382     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1383     RegCloseKey(hkeyProduct);
1384
1385     return r;
1386 }
1387
1388 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1389 {
1390     DWORD r;
1391     WCHAR szwGuid[GUID_SIZE];
1392
1393     TRACE("%d %p\n", index, lpguid);
1394
1395     r = MsiEnumComponentsW(index, szwGuid);
1396     if( r == ERROR_SUCCESS )
1397         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1398
1399     return r;
1400 }
1401
1402 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1403 {
1404     HKEY hkeyComponents = 0;
1405     DWORD r;
1406     WCHAR szKeyName[SQUISH_GUID_SIZE];
1407
1408     TRACE("%d %p\n", index, lpguid);
1409
1410     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Components, &hkeyComponents);
1411     if( r != ERROR_SUCCESS )
1412         return ERROR_NO_MORE_ITEMS;
1413
1414     r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
1415     if( r == ERROR_SUCCESS )
1416         unsquash_guid(szKeyName, lpguid);
1417     RegCloseKey(hkeyComponents);
1418
1419     return r;
1420 }
1421
1422 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1423 {
1424     DWORD r;
1425     WCHAR szwProduct[GUID_SIZE];
1426     LPWSTR szwComponent = NULL;
1427
1428     TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1429
1430     if ( !szProduct )
1431         return ERROR_INVALID_PARAMETER;
1432
1433     if( szComponent )
1434     {
1435         szwComponent = strdupAtoW( szComponent );
1436         if( !szwComponent )
1437             return ERROR_OUTOFMEMORY;
1438     }
1439
1440     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1441     if( r == ERROR_SUCCESS )
1442     {
1443         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1444                             szProduct, GUID_SIZE, NULL, NULL);
1445     }
1446
1447     msi_free( szwComponent);
1448
1449     return r;
1450 }
1451
1452 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1453 {
1454     HKEY hkeyComp = 0;
1455     DWORD r, sz;
1456     WCHAR szValName[SQUISH_GUID_SIZE];
1457
1458     TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1459
1460     if (!szComponent || !*szComponent || !szProduct)
1461         return ERROR_INVALID_PARAMETER;
1462
1463     if (MSIREG_OpenUserDataComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1464         MSIREG_OpenLocalSystemComponentKey(szComponent, &hkeyComp, FALSE) != ERROR_SUCCESS)
1465         return ERROR_UNKNOWN_COMPONENT;
1466
1467     /* see if there are any products at all */
1468     sz = SQUISH_GUID_SIZE;
1469     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1470     if (r != ERROR_SUCCESS)
1471     {
1472         RegCloseKey(hkeyComp);
1473
1474         if (index != 0)
1475             return ERROR_INVALID_PARAMETER;
1476
1477         return ERROR_UNKNOWN_COMPONENT;
1478     }
1479
1480     sz = SQUISH_GUID_SIZE;
1481     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1482     if( r == ERROR_SUCCESS )
1483         unsquash_guid(szValName, szProduct);
1484
1485     RegCloseKey(hkeyComp);
1486
1487     return r;
1488 }
1489
1490 static UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1491                 awstring *lpQualBuf, LPDWORD pcchQual,
1492                 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1493 {
1494     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1495     LPWSTR name = NULL, val = NULL;
1496     UINT r, r2;
1497     HKEY key;
1498
1499     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1500           lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1501
1502     if (!szComponent)
1503         return ERROR_INVALID_PARAMETER;
1504
1505     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1506     if (r != ERROR_SUCCESS)
1507         return ERROR_UNKNOWN_COMPONENT;
1508
1509     /* figure out how big the name is we want to return */
1510     name_max = 0x10;
1511     r = ERROR_OUTOFMEMORY;
1512     name = msi_alloc( name_max * sizeof(WCHAR) );
1513     if (!name)
1514         goto end;
1515
1516     val_max = 0x10;
1517     r = ERROR_OUTOFMEMORY;
1518     val = msi_alloc( val_max );
1519     if (!val)
1520         goto end;
1521
1522     /* loop until we allocate enough memory */
1523     while (1)
1524     {
1525         name_sz = name_max;
1526         val_sz = val_max;
1527         r = RegEnumValueW( key, iIndex, name, &name_sz,
1528                            NULL, &type, (LPBYTE)val, &val_sz );
1529         if (r == ERROR_SUCCESS)
1530             break;
1531         if (r != ERROR_MORE_DATA)
1532             goto end;
1533  
1534         if (type != REG_MULTI_SZ)
1535         {
1536             ERR("component data has wrong type (%d)\n", type);
1537             goto end;
1538         }
1539
1540         r = ERROR_OUTOFMEMORY;
1541         if ((name_sz+1) >= name_max)
1542         {
1543             name_max *= 2;
1544             msi_free( name );
1545             name = msi_alloc( name_max * sizeof (WCHAR) );
1546             if (!name)
1547                 goto end;
1548             continue;
1549         }
1550         if (val_sz > val_max)
1551         {
1552             val_max = val_sz + sizeof (WCHAR);
1553             msi_free( val );
1554             val = msi_alloc( val_max * sizeof (WCHAR) );
1555             if (!val)
1556                 goto end;
1557             continue;
1558         }
1559         ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1560         goto end;
1561     }
1562
1563     ofs = 0;
1564     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1565     if (r != ERROR_SUCCESS)
1566         goto end;
1567
1568     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1569
1570     r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1571     r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1572
1573     if (r2 != ERROR_SUCCESS)
1574         r = r2;
1575
1576 end:
1577     msi_free(val);
1578     msi_free(name);
1579     RegCloseKey(key);
1580
1581     return r;
1582 }
1583
1584 /*************************************************************************
1585  *  MsiEnumComponentQualifiersA [MSI.@]
1586  */
1587 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1588                 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1589                 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1590 {
1591     awstring qual, appdata;
1592     LPWSTR comp;
1593     UINT r;
1594
1595     TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1596           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1597           pcchApplicationDataBuf);
1598
1599     comp = strdupAtoW( szComponent );
1600     if (szComponent && !comp)
1601         return ERROR_OUTOFMEMORY;
1602
1603     qual.unicode = FALSE;
1604     qual.str.a = lpQualifierBuf;
1605
1606     appdata.unicode = FALSE;
1607     appdata.str.a = lpApplicationDataBuf;
1608
1609     r = MSI_EnumComponentQualifiers( comp, iIndex,
1610               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1611     msi_free( comp );
1612     return r;
1613 }
1614
1615 /*************************************************************************
1616  *  MsiEnumComponentQualifiersW [MSI.@]
1617  */
1618 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1619                 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1620                 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1621 {
1622     awstring qual, appdata;
1623
1624     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1625           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1626           pcchApplicationDataBuf);
1627
1628     qual.unicode = TRUE;
1629     qual.str.w = lpQualifierBuf;
1630
1631     appdata.unicode = TRUE;
1632     appdata.str.w = lpApplicationDataBuf;
1633
1634     return MSI_EnumComponentQualifiers( szComponent, iIndex,
1635                  &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1636 }
1637
1638 /*************************************************************************
1639  *  MsiEnumRelatedProductsW   [MSI.@]
1640  *
1641  */
1642 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1643                                     DWORD iProductIndex, LPWSTR lpProductBuf)
1644 {
1645     UINT r;
1646     HKEY hkey;
1647     DWORD dwSize = SQUISH_GUID_SIZE;
1648     WCHAR szKeyName[SQUISH_GUID_SIZE];
1649
1650     TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1651           iProductIndex, lpProductBuf);
1652
1653     if (NULL == szUpgradeCode)
1654         return ERROR_INVALID_PARAMETER;
1655     if (NULL == lpProductBuf)
1656         return ERROR_INVALID_PARAMETER;
1657
1658     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1659     if (r != ERROR_SUCCESS)
1660         return ERROR_NO_MORE_ITEMS;
1661
1662     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1663     if( r == ERROR_SUCCESS )
1664         unsquash_guid(szKeyName, lpProductBuf);
1665     RegCloseKey(hkey);
1666
1667     return r;
1668 }
1669
1670 /*************************************************************************
1671  *  MsiEnumRelatedProductsA   [MSI.@]
1672  *
1673  */
1674 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1675                                     DWORD iProductIndex, LPSTR lpProductBuf)
1676 {
1677     LPWSTR szwUpgradeCode = NULL;
1678     WCHAR productW[GUID_SIZE];
1679     UINT r;
1680
1681     TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1682           iProductIndex, lpProductBuf);
1683
1684     if (szUpgradeCode)
1685     {
1686         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1687         if( !szwUpgradeCode )
1688             return ERROR_OUTOFMEMORY;
1689     }
1690
1691     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1692                                  iProductIndex, productW );
1693     if (r == ERROR_SUCCESS)
1694     {
1695         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1696                              lpProductBuf, GUID_SIZE, NULL, NULL );
1697     }
1698     msi_free( szwUpgradeCode);
1699     return r;
1700 }
1701
1702 /***********************************************************************
1703  * MsiEnumPatchesA            [MSI.@]
1704  */
1705 UINT WINAPI MsiEnumPatchesA( LPCSTR szProduct, DWORD iPatchIndex,
1706         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1707 {
1708     FIXME("%s %d %p %p %p\n", debugstr_a(szProduct),
1709           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1710     return ERROR_NO_MORE_ITEMS;
1711 }
1712
1713 /***********************************************************************
1714  * MsiEnumPatchesW            [MSI.@]
1715  */
1716 UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
1717         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
1718 {
1719     FIXME("%s %d %p %p %p\n", debugstr_w(szProduct),
1720           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
1721     return ERROR_NO_MORE_ITEMS;
1722 }
1723
1724 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
1725         DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
1726         MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
1727 {
1728     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
1729           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1730           szSid, pcchSid);
1731     return ERROR_NO_MORE_ITEMS;
1732 }
1733
1734 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
1735         DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
1736         MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
1737 {
1738     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
1739           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
1740           szSid, pcchSid);
1741     return ERROR_NO_MORE_ITEMS;
1742 }