mshtml: COM cleanup for the IHTMLDOMNode iface.
[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  * This module will be all the helper functions for registry access by the
45  * installer bits. 
46  */
47 static const WCHAR szUserFeatures_fmt[] = {
48 'S','o','f','t','w','a','r','e','\\',
49 'M','i','c','r','o','s','o','f','t','\\',
50 'I','n','s','t','a','l','l','e','r','\\',
51 'F','e','a','t','u','r','e','s','\\',
52 '%','s',0};
53
54 static const WCHAR szUserDataFeatures_fmt[] = {
55 'S','o','f','t','w','a','r','e','\\',
56 'M','i','c','r','o','s','o','f','t','\\',
57 'W','i','n','d','o','w','s','\\',
58 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
59 'I','n','s','t','a','l','l','e','r','\\',
60 'U','s','e','r','D','a','t','a','\\',
61 '%','s','\\','P','r','o','d','u','c','t','s','\\',
62 '%','s','\\','F','e','a','t','u','r','e','s',0};
63
64 static const WCHAR szInstaller_Features_fmt[] = {
65 'S','o','f','t','w','a','r','e','\\',
66 'M','i','c','r','o','s','o','f','t','\\',
67 'W','i','n','d','o','w','s','\\',
68 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
69 'I','n','s','t','a','l','l','e','r','\\',
70 'F','e','a','t','u','r','e','s','\\',
71 '%','s',0};
72
73 static const WCHAR szInstaller_Components[] = {
74 'S','o','f','t','w','a','r','e','\\',
75 'M','i','c','r','o','s','o','f','t','\\',
76 'W','i','n','d','o','w','s','\\',
77 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
78 'I','n','s','t','a','l','l','e','r','\\',
79 'C','o','m','p','o','n','e','n','t','s',0 };
80
81 static const WCHAR szUser_Components_fmt[] = {
82 'S','o','f','t','w','a','r','e','\\',
83 'M','i','c','r','o','s','o','f','t','\\',
84 'I','n','s','t','a','l','l','e','r','\\',
85 'C','o','m','p','o','n','e','n','t','s','\\',
86 '%','s',0};
87
88 static const WCHAR szUserDataComp_fmt[] = {
89 'S','o','f','t','w','a','r','e','\\',
90 'M','i','c','r','o','s','o','f','t','\\',
91 'W','i','n','d','o','w','s','\\',
92 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
93 'I','n','s','t','a','l','l','e','r','\\',
94 'U','s','e','r','D','a','t','a','\\',
95 '%','s','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
96
97 static const WCHAR szUninstall_fmt[] = {
98 'S','o','f','t','w','a','r','e','\\',
99 'M','i','c','r','o','s','o','f','t','\\',
100 'W','i','n','d','o','w','s','\\',
101 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
102 'U','n','i','n','s','t','a','l','l','\\',
103 '%','s',0 };
104
105 static const WCHAR szUninstall_32node_fmt[] = {
106 'S','o','f','t','w','a','r','e','\\',
107 'W','o','w','6','4','3','2','N','o','d','e','\\',
108 'M','i','c','r','o','s','o','f','t','\\',
109 'W','i','n','d','o','w','s','\\',
110 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
111 'U','n','i','n','s','t','a','l','l','\\',
112 '%','s',0 };
113
114 static const WCHAR szUserProduct[] = {
115 'S','o','f','t','w','a','r','e','\\',
116 'M','i','c','r','o','s','o','f','t','\\',
117 'I','n','s','t','a','l','l','e','r','\\',
118 'P','r','o','d','u','c','t','s',0};
119
120 static const WCHAR szUserProduct_fmt[] = {
121 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'I','n','s','t','a','l','l','e','r','\\',
124 'P','r','o','d','u','c','t','s','\\',
125 '%','s',0};
126
127 static const WCHAR szUserPatch_fmt[] = {
128 'S','o','f','t','w','a','r','e','\\',
129 'M','i','c','r','o','s','o','f','t','\\',
130 'I','n','s','t','a','l','l','e','r','\\',
131 'P','a','t','c','h','e','s','\\',
132 '%','s',0};
133
134 static const WCHAR szInstaller_Products[] = {
135 'S','o','f','t','w','a','r','e','\\',
136 'M','i','c','r','o','s','o','f','t','\\',
137 'W','i','n','d','o','w','s','\\',
138 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
139 'I','n','s','t','a','l','l','e','r','\\',
140 'P','r','o','d','u','c','t','s',0};
141
142 static const WCHAR szInstaller_Products_fmt[] = {
143 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'I','n','s','t','a','l','l','e','r','\\',
148 'P','r','o','d','u','c','t','s','\\',
149 '%','s',0};
150
151 static const WCHAR szInstaller_Patches_fmt[] = {
152 'S','o','f','t','w','a','r','e','\\',
153 'M','i','c','r','o','s','o','f','t','\\',
154 'W','i','n','d','o','w','s','\\',
155 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
156 'I','n','s','t','a','l','l','e','r','\\',
157 'P','a','t','c','h','e','s','\\',
158 '%','s',0};
159
160 static const WCHAR szInstaller_UpgradeCodes_fmt[] = {
161 'S','o','f','t','w','a','r','e','\\',
162 'M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s','\\',
164 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'I','n','s','t','a','l','l','e','r','\\',
166 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
167 '%','s',0};
168
169 static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = {
170 'S','o','f','t','w','a','r','e','\\',
171 'M','i','c','r','o','s','o','f','t','\\',
172 'I','n','s','t','a','l','l','e','r','\\',
173 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
174 '%','s',0};
175
176 static const WCHAR szUserDataProd_fmt[] = {
177 'S','o','f','t','w','a','r','e','\\',
178 'M','i','c','r','o','s','o','f','t','\\',
179 'W','i','n','d','o','w','s','\\',
180 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181 'I','n','s','t','a','l','l','e','r','\\',
182 'U','s','e','r','D','a','t','a','\\',
183 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
184
185 static const WCHAR szUserDataPatch_fmt[] = {
186 'S','o','f','t','w','a','r','e','\\',
187 'M','i','c','r','o','s','o','f','t','\\',
188 'W','i','n','d','o','w','s','\\',
189 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
190 'I','n','s','t','a','l','l','e','r','\\',
191 'U','s','e','r','D','a','t','a','\\',
192 '%','s','\\','P','a','t','c','h','e','s','\\','%','s',0};
193
194 static const WCHAR szUserDataProductPatches_fmt[] = {
195 'S','o','f','t','w','a','r','e','\\',
196 'M','i','c','r','o','s','o','f','t','\\',
197 'W','i','n','d','o','w','s','\\',
198 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
199 'I','n','s','t','a','l','l','e','r','\\',
200 'U','s','e','r','D','a','t','a','\\',
201 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
202 'P','a','t','c','h','e','s',0};
203
204 static const WCHAR szInstallProperties_fmt[] = {
205 'S','o','f','t','w','a','r','e','\\',
206 'M','i','c','r','o','s','o','f','t','\\',
207 'W','i','n','d','o','w','s','\\',
208 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
209 'I','n','s','t','a','l','l','e','r','\\',
210 'U','s','e','r','D','a','t','a','\\',
211 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
212 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
213
214 static const WCHAR szInstaller_LocalClassesProd[] = {
215 'S','o','f','t','w','a','r','e','\\',
216 'C','l','a','s','s','e','s','\\',
217 'I','n','s','t','a','l','l','e','r','\\',
218 'P','r','o','d','u','c','t','s',0};
219
220 static const WCHAR szInstaller_LocalClassesProd_fmt[] = {
221 'S','o','f','t','w','a','r','e','\\',
222 'C','l','a','s','s','e','s','\\',
223 'I','n','s','t','a','l','l','e','r','\\',
224 'P','r','o','d','u','c','t','s','\\','%','s',0};
225
226 static const WCHAR szInstaller_LocalClassesFeat_fmt[] = {
227 'S','o','f','t','w','a','r','e','\\',
228 'C','l','a','s','s','e','s','\\',
229 'I','n','s','t','a','l','l','e','r','\\',
230 'F','e','a','t','u','r','e','s','\\','%','s',0};
231
232 static const WCHAR szInstaller_LocalManaged_fmt[] = {
233 'S','o','f','t','w','a','r','e','\\',
234 'M','i','c','r','o','s','o','f','t','\\',
235 'W','i','n','d','o','w','s','\\',
236 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
237 'I','n','s','t','a','l','l','e','r','\\',
238 'M','a','n','a','g','e','d','\\','%','s','\\',
239 'I','n','s','t','a','l','l','e','r','\\',
240 'P','r','o','d','u','c','t','s',0};
241
242 static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
243 'S','o','f','t','w','a','r','e','\\',
244 'M','i','c','r','o','s','o','f','t','\\',
245 'W','i','n','d','o','w','s','\\',
246 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
247 'I','n','s','t','a','l','l','e','r','\\',
248 'M','a','n','a','g','e','d','\\','%','s','\\',
249 'I','n','s','t','a','l','l','e','r','\\',
250 'P','r','o','d','u','c','t','s','\\','%','s',0};
251
252 static const WCHAR szInstaller_LocalManagedFeat_fmt[] = {
253 'S','o','f','t','w','a','r','e','\\',
254 'M','i','c','r','o','s','o','f','t','\\',
255 'W','i','n','d','o','w','s','\\',
256 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
257 'I','n','s','t','a','l','l','e','r','\\',
258 'M','a','n','a','g','e','d','\\','%','s','\\',
259 'I','n','s','t','a','l','l','e','r','\\',
260 'F','e','a','t','u','r','e','s','\\','%','s',0};
261
262 static const WCHAR szInstaller_ClassesUpgrade_fmt[] = {
263 'I','n','s','t','a','l','l','e','r','\\',
264 'U','p','g','r','a','d','e','C','o','d','e','s','\\',
265 '%','s',0};
266
267 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
268 {
269     DWORD i,n=0;
270
271     if (lstrlenW(in) != 32)
272         return FALSE;
273
274     out[n++]='{';
275     for(i=0; i<8; i++)
276         out[n++] = in[7-i];
277     out[n++]='-';
278     for(i=0; i<4; i++)
279         out[n++] = in[11-i];
280     out[n++]='-';
281     for(i=0; i<4; i++)
282         out[n++] = in[15-i];
283     out[n++]='-';
284     for(i=0; i<2; i++)
285     {
286         out[n++] = in[17+i*2];
287         out[n++] = in[16+i*2];
288     }
289     out[n++]='-';
290     for( ; i<8; i++)
291     {
292         out[n++] = in[17+i*2];
293         out[n++] = in[16+i*2];
294     }
295     out[n++]='}';
296     out[n]=0;
297     return TRUE;
298 }
299
300 BOOL squash_guid(LPCWSTR in, LPWSTR out)
301 {
302     DWORD i,n=1;
303     GUID guid;
304
305     out[0] = 0;
306
307     if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
308         return FALSE;
309
310     for(i=0; i<8; i++)
311         out[7-i] = in[n++];
312     n++;
313     for(i=0; i<4; i++)
314         out[11-i] = in[n++];
315     n++;
316     for(i=0; i<4; i++)
317         out[15-i] = in[n++];
318     n++;
319     for(i=0; i<2; i++)
320     {
321         out[17+i*2] = in[n++];
322         out[16+i*2] = in[n++];
323     }
324     n++;
325     for( ; i<8; i++)
326     {
327         out[17+i*2] = in[n++];
328         out[16+i*2] = in[n++];
329     }
330     out[32]=0;
331     return TRUE;
332 }
333
334
335 /* tables for encoding and decoding base85 */
336 static const unsigned char table_dec85[0x80] = {
337 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
338 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
339 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
340 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
341 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
342 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
343 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
344 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
345 };
346
347 static const char table_enc85[] =
348 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
349 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
350 "yz{}~";
351
352 /*
353  *  Converts a base85 encoded guid into a GUID pointer
354  *  Base85 encoded GUIDs should be 20 characters long.
355  *
356  *  returns TRUE if successful, FALSE if not
357  */
358 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
359 {
360     DWORD i, val = 0, base = 1, *p;
361
362     if (!str)
363         return FALSE;
364
365     p = (DWORD*) guid;
366     for( i=0; i<20; i++ )
367     {
368         if( (i%5) == 0 )
369         {
370             val = 0;
371             base = 1;
372         }
373         val += table_dec85[str[i]] * base;
374         if( str[i] >= 0x80 )
375             return FALSE;
376         if( table_dec85[str[i]] == 0xff )
377             return FALSE;
378         if( (i%5) == 4 )
379             p[i/5] = val;
380         base *= 85;
381     }
382     return TRUE;
383 }
384
385 /*
386  *  Encodes a base85 guid given a GUID pointer
387  *  Caller should provide a 21 character buffer for the encoded string.
388  *
389  *  returns TRUE if successful, FALSE if not
390  */
391 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
392 {
393     unsigned int x, *p, i;
394
395     p = (unsigned int*) guid;
396     for( i=0; i<4; i++ )
397     {
398         x = p[i];
399         *str++ = table_enc85[x%85];
400         x = x/85;
401         *str++ = table_enc85[x%85];
402         x = x/85;
403         *str++ = table_enc85[x%85];
404         x = x/85;
405         *str++ = table_enc85[x%85];
406         x = x/85;
407         *str++ = table_enc85[x%85];
408     }
409     *str = 0;
410
411     return TRUE;
412 }
413
414 DWORD msi_version_str_to_dword(LPCWSTR p)
415 {
416     DWORD major, minor = 0, build = 0, version = 0;
417
418     if (!p)
419         return version;
420
421     major = atoiW(p);
422
423     p = strchrW(p, '.');
424     if (p)
425     {
426         minor = atoiW(p+1);
427         p = strchrW(p+1, '.');
428         if (p)
429             build = atoiW(p+1);
430     }
431
432     return MAKELONG(build, MAKEWORD(minor, major));
433 }
434
435 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
436 {
437     DWORD len;
438     if (!value) value = szEmpty;
439     len = (lstrlenW(value) + 1) * sizeof (WCHAR);
440     return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
441 }
442
443 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
444 {
445     LPCWSTR p = value;
446     while (*p) p += lstrlenW(p) + 1;
447     return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
448                            (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
449 }
450
451 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
452 {
453     return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
454 }
455
456 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
457 {
458     HKEY hsubkey = 0;
459     LONG r;
460
461     r = RegCreateKeyW( hkey, path, &hsubkey );
462     if (r != ERROR_SUCCESS)
463         return r;
464     r = msi_reg_set_val_str( hsubkey, name, val );
465     RegCloseKey( hsubkey );
466     return r;
467 }
468
469 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
470 {
471     DWORD len = 0;
472     LPWSTR val;
473     LONG r;
474
475     r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
476     if (r != ERROR_SUCCESS)
477         return NULL;
478
479     len += sizeof (WCHAR);
480     val = msi_alloc( len );
481     if (!val)
482         return NULL;
483     val[0] = 0;
484     RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
485     return val;
486 }
487
488 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
489 {
490     DWORD type, len = sizeof (DWORD);
491     LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
492     return r == ERROR_SUCCESS && type == REG_DWORD;
493 }
494
495 static UINT get_user_sid(LPWSTR *usersid)
496 {
497     HANDLE token;
498     BYTE buf[1024];
499     DWORD size;
500     PTOKEN_USER user;
501
502     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
503         return ERROR_FUNCTION_FAILED;
504
505     size = sizeof(buf);
506     if (!GetTokenInformation(token, TokenUser, buf, size, &size)) {
507         CloseHandle(token);
508         return ERROR_FUNCTION_FAILED;
509     }
510
511     user = (PTOKEN_USER)buf;
512     if (!ConvertSidToStringSidW(user->User.Sid, usersid)) {
513         CloseHandle(token);
514         return ERROR_FUNCTION_FAILED;
515     }
516     CloseHandle(token);
517     return ERROR_SUCCESS;
518 }
519
520 UINT MSIREG_OpenUninstallKey(MSIPACKAGE *package, HKEY *key, BOOL create)
521 {
522     UINT rc;
523     WCHAR keypath[0x200];
524
525     TRACE("%s\n", debugstr_w(package->ProductCode));
526
527     if (is_64bit && package->platform == PLATFORM_INTEL)
528         sprintfW(keypath, szUninstall_32node_fmt, package->ProductCode);
529     else
530         sprintfW(keypath, szUninstall_fmt, package->ProductCode);
531
532     if (create)
533         rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, KEY_ALL_ACCESS, NULL, key, NULL);
534     else
535         rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, KEY_ALL_ACCESS, key);
536
537     return rc;
538 }
539
540 UINT MSIREG_DeleteUninstallKey(MSIPACKAGE *package)
541 {
542     WCHAR keypath[0x200];
543
544     TRACE("%s\n", debugstr_w(package->ProductCode));
545
546     if (is_64bit && package->platform == PLATFORM_INTEL)
547         sprintfW(keypath, szUninstall_32node_fmt, package->ProductCode);
548     else
549         sprintfW(keypath, szUninstall_fmt, package->ProductCode);
550
551     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
552 }
553
554 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid,
555                            MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
556 {
557     UINT r;
558     LPWSTR usersid = NULL;
559     HKEY root = HKEY_LOCAL_MACHINE;
560     WCHAR squished_pc[GUID_SIZE];
561     WCHAR keypath[MAX_PATH];
562
563     TRACE("(%s, %d, %d)\n", debugstr_w(szProduct), context, create);
564
565     if (!squash_guid(szProduct, squished_pc))
566         return ERROR_FUNCTION_FAILED;
567
568     TRACE("squished (%s)\n", debugstr_w(squished_pc));
569
570     if (context == MSIINSTALLCONTEXT_MACHINE)
571     {
572         sprintfW(keypath, szInstaller_LocalClassesProd_fmt, squished_pc);
573     }
574     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
575     {
576         root = HKEY_CURRENT_USER;
577         sprintfW(keypath, szUserProduct_fmt, squished_pc);
578     }
579     else
580     {
581         if (!szUserSid)
582         {
583             r = get_user_sid(&usersid);
584             if (r != ERROR_SUCCESS || !usersid)
585             {
586                 ERR("Failed to retrieve user SID: %d\n", r);
587                 return r;
588             }
589
590             szUserSid = usersid;
591         }
592
593         sprintfW(keypath, szInstaller_LocalManagedProd_fmt,
594                  szUserSid, squished_pc);
595         LocalFree(usersid);
596     }
597
598     if (create)
599         return RegCreateKeyW(root, keypath, key);
600
601     return RegOpenKeyW(root, keypath, key);
602 }
603
604 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
605 {
606     WCHAR squished_pc[GUID_SIZE];
607     WCHAR keypath[0x200];
608
609     TRACE("%s\n",debugstr_w(szProduct));
610     if (!squash_guid(szProduct,squished_pc))
611         return ERROR_FUNCTION_FAILED;
612     TRACE("squished (%s)\n", debugstr_w(squished_pc));
613
614     sprintfW(keypath,szUserProduct_fmt,squished_pc);
615
616     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
617 }
618
619 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
620 {
621     UINT rc;
622     WCHAR squished_pc[GUID_SIZE];
623     WCHAR keypath[0x200];
624
625     TRACE("%s\n",debugstr_w(szPatch));
626     if (!squash_guid(szPatch,squished_pc))
627         return ERROR_FUNCTION_FAILED;
628     TRACE("squished (%s)\n", debugstr_w(squished_pc));
629
630     sprintfW(keypath,szUserPatch_fmt,squished_pc);
631
632     if (create)
633         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
634     else
635         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
636
637     return rc;
638 }
639
640 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context,
641                             HKEY *key, BOOL create)
642 {
643     UINT r;
644     LPWSTR usersid;
645     HKEY root = HKEY_LOCAL_MACHINE;
646     WCHAR squished_pc[GUID_SIZE];
647     WCHAR keypath[MAX_PATH];
648
649     TRACE("(%s, %d, %d)\n", debugstr_w(szProduct), context, create);
650
651     if (!squash_guid(szProduct, squished_pc))
652         return ERROR_FUNCTION_FAILED;
653
654     TRACE("squished (%s)\n", debugstr_w(squished_pc));
655
656     if (context == MSIINSTALLCONTEXT_MACHINE)
657     {
658         sprintfW(keypath, szInstaller_LocalClassesFeat_fmt, squished_pc);
659     }
660     else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
661     {
662         root = HKEY_CURRENT_USER;
663         sprintfW(keypath, szUserFeatures_fmt, squished_pc);
664     }
665     else
666     {
667         r = get_user_sid(&usersid);
668         if (r != ERROR_SUCCESS || !usersid)
669         {
670             ERR("Failed to retrieve user SID: %d\n", r);
671             return r;
672         }
673
674         sprintfW(keypath, szInstaller_LocalManagedFeat_fmt, usersid, squished_pc);
675         LocalFree(usersid);
676     }
677
678     if (create)
679         return RegCreateKeyW(root, keypath, key);
680
681     return RegOpenKeyW(root, keypath, key);
682 }
683
684 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
685 {
686     WCHAR squished_pc[GUID_SIZE];
687     WCHAR keypath[0x200];
688
689     TRACE("%s\n",debugstr_w(szProduct));
690     if (!squash_guid(szProduct,squished_pc))
691         return ERROR_FUNCTION_FAILED;
692     TRACE("squished (%s)\n", debugstr_w(squished_pc));
693
694     sprintfW(keypath,szUserFeatures_fmt,squished_pc);
695     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
696 }
697
698 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create)
699 {
700     UINT rc;
701     WCHAR squished_pc[GUID_SIZE];
702     WCHAR keypath[0x200];
703
704     TRACE("%s\n",debugstr_w(szProduct));
705     if (!squash_guid(szProduct,squished_pc))
706         return ERROR_FUNCTION_FAILED;
707     TRACE("squished (%s)\n", debugstr_w(squished_pc));
708
709     sprintfW(keypath,szInstaller_Features_fmt,squished_pc);
710
711     if (create)
712         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
713     else
714         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
715
716     return rc;
717 }
718
719 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context,
720                                     HKEY *key, BOOL create)
721 {
722     UINT r;
723     LPWSTR usersid;
724     WCHAR squished_pc[GUID_SIZE];
725     WCHAR keypath[0x200];
726
727     TRACE("(%s, %d, %d)\n", debugstr_w(szProduct), context, create);
728
729     if (!squash_guid(szProduct, squished_pc))
730         return ERROR_FUNCTION_FAILED;
731
732     TRACE("squished (%s)\n", debugstr_w(squished_pc));
733
734     if (context == MSIINSTALLCONTEXT_MACHINE)
735     {
736         sprintfW(keypath, szUserDataFeatures_fmt, szLocalSid, squished_pc);
737     }
738     else
739     {
740         r = get_user_sid(&usersid);
741         if (r != ERROR_SUCCESS || !usersid)
742         {
743             ERR("Failed to retrieve user SID: %d\n", r);
744             return r;
745         }
746
747         sprintfW(keypath, szUserDataFeatures_fmt, usersid, squished_pc);
748         LocalFree(usersid);
749     }
750
751     if (create)
752         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
753
754     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
755 }
756
757 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create)
758 {
759     UINT rc;
760     WCHAR squished_cc[GUID_SIZE];
761     WCHAR keypath[0x200];
762
763     TRACE("%s\n",debugstr_w(szComponent));
764     if (!squash_guid(szComponent,squished_cc))
765         return ERROR_FUNCTION_FAILED;
766     TRACE("squished (%s)\n", debugstr_w(squished_cc));
767
768     sprintfW(keypath,szUser_Components_fmt,squished_cc);
769
770     if (create)
771         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
772     else
773         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
774
775     return rc;
776 }
777
778 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid,
779                                      HKEY *key, BOOL create)
780 {
781     UINT rc;
782     WCHAR comp[GUID_SIZE];
783     WCHAR keypath[0x200];
784     LPWSTR usersid;
785
786     TRACE("%s\n", debugstr_w(szComponent));
787     if (!squash_guid(szComponent, comp))
788         return ERROR_FUNCTION_FAILED;
789     TRACE("squished (%s)\n", debugstr_w(comp));
790
791     if (!szUserSid)
792     {
793         rc = get_user_sid(&usersid);
794         if (rc != ERROR_SUCCESS || !usersid)
795         {
796             ERR("Failed to retrieve user SID: %d\n", rc);
797             return rc;
798         }
799
800         sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
801         LocalFree(usersid);
802     }
803     else
804         sprintfW(keypath, szUserDataComp_fmt, szUserSid, comp);
805
806     if (create)
807         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
808     else
809         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
810
811     return rc;
812 }
813
814 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
815 {
816     UINT rc;
817     WCHAR comp[GUID_SIZE];
818     WCHAR keypath[0x200];
819     LPWSTR usersid;
820
821     TRACE("%s\n", debugstr_w(szComponent));
822     if (!squash_guid(szComponent, comp))
823         return ERROR_FUNCTION_FAILED;
824     TRACE("squished (%s)\n", debugstr_w(comp));
825
826     if (!szUserSid)
827     {
828         rc = get_user_sid(&usersid);
829         if (rc != ERROR_SUCCESS || !usersid)
830         {
831             ERR("Failed to retrieve user SID: %d\n", rc);
832             return rc;
833         }
834
835         sprintfW(keypath, szUserDataComp_fmt, usersid, comp);
836         LocalFree(usersid);
837     }
838     else
839         sprintfW(keypath, szUserDataComp_fmt, szUserSid, comp);
840
841     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
842 }
843
844 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext,
845                                    LPCWSTR szUserSid, HKEY *key, BOOL create)
846 {
847     UINT rc;
848     WCHAR squished_pc[GUID_SIZE];
849     WCHAR keypath[0x200];
850     LPWSTR usersid;
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     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
858         sprintfW(keypath, szUserDataProd_fmt, szLocalSid, squished_pc);
859     else if (szUserSid)
860         sprintfW(keypath, szUserDataProd_fmt, szUserSid, squished_pc);
861     else
862     {
863         rc = get_user_sid(&usersid);
864         if (rc != ERROR_SUCCESS || !usersid)
865         {
866             ERR("Failed to retrieve user SID: %d\n", rc);
867             return rc;
868         }
869
870         sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
871         LocalFree(usersid);
872     }
873
874     if (create)
875         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
876     else
877         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
878
879     return rc;
880 }
881
882 UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext,
883                                  HKEY *key, BOOL create)
884 {
885     UINT rc;
886     WCHAR squished_patch[GUID_SIZE];
887     WCHAR keypath[0x200];
888     LPWSTR usersid;
889
890     TRACE("%s\n", debugstr_w(szPatch));
891     if (!squash_guid(szPatch, squished_patch))
892         return ERROR_FUNCTION_FAILED;
893     TRACE("squished (%s)\n", debugstr_w(squished_patch));
894
895     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
896         sprintfW(keypath, szUserDataPatch_fmt, szLocalSid, squished_patch);
897     else
898     {
899         rc = get_user_sid(&usersid);
900         if (rc != ERROR_SUCCESS || !usersid)
901         {
902             ERR("Failed to retrieve user SID: %d\n", rc);
903             return rc;
904         }
905
906         sprintfW(keypath, szUserDataPatch_fmt, usersid, squished_patch);
907         LocalFree(usersid);
908     }
909
910     if (create)
911         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
912
913     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
914 }
915
916 UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
917 {
918     UINT r;
919     WCHAR squished_patch[GUID_SIZE];
920     WCHAR keypath[0x200];
921     LPWSTR usersid;
922
923     TRACE("%s\n", debugstr_w(patch));
924     if (!squash_guid(patch, squished_patch))
925         return ERROR_FUNCTION_FAILED;
926     TRACE("squished (%s)\n", debugstr_w(squished_patch));
927
928     if (context == MSIINSTALLCONTEXT_MACHINE)
929         sprintfW(keypath, szUserDataPatch_fmt, szLocalSid, squished_patch);
930     else
931     {
932         r = get_user_sid(&usersid);
933         if (r != ERROR_SUCCESS || !usersid)
934         {
935             ERR("Failed to retrieve user SID: %d\n", r);
936             return r;
937         }
938
939         sprintfW(keypath, szUserDataPatch_fmt, usersid, squished_patch);
940         LocalFree(usersid);
941     }
942
943     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
944 }
945
946 UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context,
947                                           HKEY *key, BOOL create)
948 {
949     UINT rc;
950     WCHAR squished_product[GUID_SIZE];
951     WCHAR keypath[0x200];
952     LPWSTR usersid;
953
954     TRACE("%s\n", debugstr_w(product));
955     if (!squash_guid(product, squished_product))
956         return ERROR_FUNCTION_FAILED;
957
958     if (context == MSIINSTALLCONTEXT_MACHINE)
959         sprintfW(keypath, szUserDataProductPatches_fmt, szLocalSid, squished_product);
960     else
961     {
962         rc = get_user_sid(&usersid);
963         if (rc != ERROR_SUCCESS || !usersid)
964         {
965             ERR("Failed to retrieve user SID: %d\n", rc);
966             return rc;
967         }
968
969         sprintfW(keypath, szUserDataProductPatches_fmt, usersid, squished_product);
970         LocalFree(usersid);
971     }
972
973     if (create)
974         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
975
976     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
977 }
978
979 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext,
980                              LPCWSTR szUserSid, HKEY *key, BOOL create)
981 {
982     UINT rc;
983     LPWSTR usersid;
984     WCHAR squished_pc[GUID_SIZE];
985     WCHAR keypath[0x200];
986
987     TRACE("%s\n", debugstr_w(szProduct));
988     if (!squash_guid(szProduct, squished_pc))
989         return ERROR_FUNCTION_FAILED;
990     TRACE("squished (%s)\n", debugstr_w(squished_pc));
991
992     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
993         sprintfW(keypath, szInstallProperties_fmt, szLocalSid, squished_pc);
994     else if (szUserSid)
995         sprintfW(keypath, szInstallProperties_fmt, szUserSid, squished_pc);
996     else
997     {
998         rc = get_user_sid(&usersid);
999         if (rc != ERROR_SUCCESS || !usersid)
1000         {
1001             ERR("Failed to retrieve user SID: %d\n", rc);
1002             return rc;
1003         }
1004
1005         sprintfW(keypath, szInstallProperties_fmt, usersid, squished_pc);
1006         LocalFree(usersid);
1007     }
1008
1009     if (create)
1010         return RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1011
1012     return RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key);
1013 }
1014
1015 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct)
1016 {
1017     UINT rc;
1018     WCHAR squished_pc[GUID_SIZE];
1019     WCHAR keypath[0x200];
1020     LPWSTR usersid;
1021
1022     TRACE("%s\n", debugstr_w(szProduct));
1023     if (!squash_guid(szProduct, squished_pc))
1024         return ERROR_FUNCTION_FAILED;
1025     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1026
1027     rc = get_user_sid(&usersid);
1028     if (rc != ERROR_SUCCESS || !usersid)
1029     {
1030         ERR("Failed to retrieve user SID: %d\n", rc);
1031         return rc;
1032     }
1033
1034     sprintfW(keypath, szUserDataProd_fmt, usersid, squished_pc);
1035
1036     LocalFree(usersid);
1037     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
1038 }
1039
1040 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
1041 {
1042     WCHAR squished_pc[GUID_SIZE];
1043     WCHAR keypath[0x200];
1044
1045     TRACE("%s\n", debugstr_w(szProduct));
1046     if (!squash_guid(szProduct, squished_pc))
1047         return ERROR_FUNCTION_FAILED;
1048     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1049
1050     sprintfW(keypath, szInstaller_Products_fmt, squished_pc);
1051
1052     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
1053 }
1054
1055 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY* key, BOOL create)
1056 {
1057     UINT rc;
1058     WCHAR squished_pc[GUID_SIZE];
1059     WCHAR keypath[0x200];
1060
1061     TRACE("%s\n",debugstr_w(szPatch));
1062     if (!squash_guid(szPatch,squished_pc))
1063         return ERROR_FUNCTION_FAILED;
1064     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1065
1066     sprintfW(keypath,szInstaller_Patches_fmt,squished_pc);
1067
1068     if (create)
1069         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
1070     else
1071         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
1072
1073     return rc;
1074 }
1075
1076 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
1077 {
1078     UINT rc;
1079     WCHAR squished_pc[GUID_SIZE];
1080     WCHAR keypath[0x200];
1081
1082     TRACE("%s\n",debugstr_w(szUpgradeCode));
1083     if (!squash_guid(szUpgradeCode,squished_pc))
1084         return ERROR_FUNCTION_FAILED;
1085     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1086
1087     sprintfW(keypath,szInstaller_UpgradeCodes_fmt,squished_pc);
1088
1089     if (create)
1090         rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key);
1091     else
1092         rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key);
1093
1094     return rc;
1095 }
1096
1097 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
1098 {
1099     UINT rc;
1100     WCHAR squished_pc[GUID_SIZE];
1101     WCHAR keypath[0x200];
1102
1103     TRACE("%s\n",debugstr_w(szUpgradeCode));
1104     if (!squash_guid(szUpgradeCode,squished_pc))
1105         return ERROR_FUNCTION_FAILED;
1106     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1107
1108     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
1109
1110     if (create)
1111         rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
1112     else
1113         rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
1114
1115     return rc;
1116 }
1117
1118 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
1119 {
1120     WCHAR squished_pc[GUID_SIZE];
1121     WCHAR keypath[0x200];
1122
1123     TRACE("%s\n",debugstr_w(szUpgradeCode));
1124     if (!squash_guid(szUpgradeCode,squished_pc))
1125         return ERROR_FUNCTION_FAILED;
1126     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1127
1128     sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
1129
1130     return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
1131 }
1132
1133 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
1134 {
1135     WCHAR squished_pc[GUID_SIZE];
1136     WCHAR keypath[0x200];
1137
1138     TRACE("%s\n", debugstr_w(szProductCode));
1139
1140     if (!squash_guid(szProductCode, squished_pc))
1141         return ERROR_FUNCTION_FAILED;
1142
1143     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1144
1145     sprintfW(keypath, szInstaller_LocalClassesProd_fmt, squished_pc);
1146
1147     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
1148 }
1149
1150 UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
1151 {
1152     WCHAR squished_pc[GUID_SIZE];
1153     WCHAR keypath[0x200];
1154
1155     TRACE("%s\n", debugstr_w(szProductCode));
1156
1157     if (!squash_guid(szProductCode, squished_pc))
1158         return ERROR_FUNCTION_FAILED;
1159
1160     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1161
1162     sprintfW(keypath, szInstaller_LocalClassesFeat_fmt, squished_pc);
1163
1164     return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
1165 }
1166
1167 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
1168 {
1169     WCHAR squished_pc[GUID_SIZE];
1170     WCHAR keypath[0x200];
1171
1172     TRACE("%s\n", debugstr_w(szUpgradeCode));
1173     if (!squash_guid(szUpgradeCode, squished_pc))
1174         return ERROR_FUNCTION_FAILED;
1175     TRACE("squished (%s)\n", debugstr_w(squished_pc));
1176
1177     sprintfW(keypath, szInstaller_ClassesUpgrade_fmt, squished_pc);
1178
1179     if (create)
1180         return RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, key);
1181
1182     return RegOpenKeyW(HKEY_CLASSES_ROOT, keypath, key);
1183 }
1184
1185 /*************************************************************************
1186  *  MsiDecomposeDescriptorW   [MSI.@]
1187  *
1188  * Decomposes an MSI descriptor into product, feature and component parts.
1189  * An MSI descriptor is a string of the form:
1190  *   [base 85 guid] [feature code] '>' [base 85 guid]
1191  *
1192  * PARAMS
1193  *   szDescriptor  [I]  the descriptor to decompose
1194  *   szProduct     [O]  buffer of MAX_FEATURE_CHARS+1 for the product guid
1195  *   szFeature     [O]  buffer of MAX_FEATURE_CHARS+1 for the feature code
1196  *   szComponent   [O]  buffer of MAX_FEATURE_CHARS+1 for the component guid
1197  *   pUsed         [O]  the length of the descriptor
1198  *
1199  * RETURNS
1200  *   ERROR_SUCCESS             if everything worked correctly
1201  *   ERROR_INVALID_PARAMETER   if the descriptor was invalid
1202  *
1203  */
1204 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1205                 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1206 {
1207     UINT r, len;
1208     LPWSTR p;
1209     GUID product, component;
1210
1211     TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1212           szFeature, szComponent, pUsed);
1213
1214     r = decode_base85_guid( szDescriptor, &product );
1215     if( !r )
1216         return ERROR_INVALID_PARAMETER;
1217
1218     TRACE("product %s\n", debugstr_guid( &product ));
1219
1220     p = strchrW(&szDescriptor[20],'>');
1221     if( !p )
1222         return ERROR_INVALID_PARAMETER;
1223
1224     len = (p - &szDescriptor[20]);
1225     if( len > MAX_FEATURE_CHARS )
1226         return ERROR_INVALID_PARAMETER;
1227
1228     TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1229
1230     r = decode_base85_guid( p+1, &component );
1231     if( !r )
1232         return ERROR_INVALID_PARAMETER;
1233
1234     TRACE("component %s\n", debugstr_guid( &component ));
1235
1236     if (szProduct)
1237         StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1238     if (szComponent)
1239         StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1240     if (szFeature)
1241     {
1242         memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1243         szFeature[len] = 0;
1244     }
1245     len = ( &p[21] - szDescriptor );
1246
1247     TRACE("length = %d\n", len);
1248     if (pUsed) *pUsed = len;
1249
1250     return ERROR_SUCCESS;
1251 }
1252
1253 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1254                 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1255 {
1256     WCHAR product[MAX_FEATURE_CHARS+1];
1257     WCHAR feature[MAX_FEATURE_CHARS+1];
1258     WCHAR component[MAX_FEATURE_CHARS+1];
1259     LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1260     UINT r;
1261
1262     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1263           szFeature, szComponent, pUsed);
1264
1265     str = strdupAtoW( szDescriptor );
1266     if( szDescriptor && !str )
1267         return ERROR_OUTOFMEMORY;
1268
1269     if (szProduct)
1270         p = product;
1271     if (szFeature)
1272         f = feature;
1273     if (szComponent)
1274         c = component;
1275
1276     r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1277
1278     if (r == ERROR_SUCCESS)
1279     {
1280         WideCharToMultiByte( CP_ACP, 0, p, -1,
1281                              szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1282         WideCharToMultiByte( CP_ACP, 0, f, -1,
1283                              szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1284         WideCharToMultiByte( CP_ACP, 0, c, -1,
1285                              szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1286     }
1287
1288     msi_free( str );
1289
1290     return r;
1291 }
1292
1293 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1294 {
1295     DWORD r;
1296     WCHAR szwGuid[GUID_SIZE];
1297
1298     TRACE("%d %p\n", index, lpguid);
1299
1300     if (NULL == lpguid)
1301         return ERROR_INVALID_PARAMETER;
1302     r = MsiEnumProductsW(index, szwGuid);
1303     if( r == ERROR_SUCCESS )
1304         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1305
1306     return r;
1307 }
1308
1309 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1310 {
1311     UINT r;
1312     WCHAR szKeyName[SQUISH_GUID_SIZE];
1313     HKEY key;
1314     DWORD machine_count, managed_count, unmanaged_count;
1315     WCHAR keypath[MAX_PATH];
1316     LPWSTR usersid = NULL;
1317
1318     static DWORD last_index;
1319
1320     TRACE("%d %p\n", index, lpguid);
1321
1322     if (NULL == lpguid)
1323         return ERROR_INVALID_PARAMETER;
1324
1325     if (index && index - last_index != 1)
1326         return ERROR_INVALID_PARAMETER;
1327
1328     key = 0;
1329     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProd, &key);
1330     if( r != ERROR_SUCCESS ) goto failed;
1331
1332     r = RegQueryInfoKeyW(key, NULL, NULL, NULL, &machine_count, NULL, NULL,
1333                          NULL, NULL, NULL, NULL, NULL);
1334     if( r != ERROR_SUCCESS ) goto failed;
1335
1336     if (machine_count && index <= machine_count)
1337     {
1338         r = RegEnumKeyW(key, index, szKeyName, SQUISH_GUID_SIZE);
1339         if( r == ERROR_SUCCESS )
1340         {
1341             unsquash_guid(szKeyName, lpguid);
1342             last_index = index;
1343             RegCloseKey(key);
1344             return ERROR_SUCCESS;
1345         }
1346     }
1347     RegCloseKey(key);
1348
1349     key = 0;
1350     r = get_user_sid(&usersid);
1351     if (r != ERROR_SUCCESS || !usersid)
1352     {
1353         ERR("Failed to retrieve user SID: %d\n", r);
1354         last_index = 0;
1355         return r;
1356     }
1357     sprintfW(keypath, szInstaller_LocalManaged_fmt, usersid);
1358     LocalFree(usersid);
1359
1360     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, &key);
1361     if( r != ERROR_SUCCESS ) goto failed;
1362
1363     r = RegQueryInfoKeyW(key, NULL, NULL, NULL, &managed_count, NULL, NULL,
1364                          NULL, NULL, NULL, NULL, NULL);
1365     if( r != ERROR_SUCCESS ) goto failed;
1366
1367     if (managed_count && index <= machine_count + managed_count)
1368     {
1369         r = RegEnumKeyW(key, index - machine_count, szKeyName, SQUISH_GUID_SIZE);
1370         if( r == ERROR_SUCCESS )
1371         {
1372             unsquash_guid(szKeyName, lpguid);
1373             last_index = index;
1374             RegCloseKey(key);
1375             return ERROR_SUCCESS;
1376         }
1377     }
1378     RegCloseKey(key);
1379
1380     key = 0;
1381     r = RegCreateKeyW(HKEY_CURRENT_USER, szUserProduct, &key);
1382     if( r != ERROR_SUCCESS ) goto failed;
1383
1384     r = RegQueryInfoKeyW(key, NULL, NULL, NULL, &unmanaged_count, NULL, NULL,
1385                          NULL, NULL, NULL, NULL, NULL);
1386     if( r != ERROR_SUCCESS ) goto failed;
1387
1388     if (unmanaged_count && index <= machine_count + managed_count + unmanaged_count)
1389     {
1390         r = RegEnumKeyW(key, index - machine_count - managed_count, szKeyName, SQUISH_GUID_SIZE);
1391         if( r == ERROR_SUCCESS )
1392         {
1393             unsquash_guid(szKeyName, lpguid);
1394             last_index = index;
1395             RegCloseKey(key);
1396             return ERROR_SUCCESS;
1397         }
1398     }
1399 failed:
1400     RegCloseKey(key);
1401     last_index = 0;
1402     return ERROR_NO_MORE_ITEMS;
1403 }
1404
1405 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 
1406       LPSTR szFeature, LPSTR szParent)
1407 {
1408     DWORD r;
1409     WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1410     LPWSTR szwProduct = NULL;
1411
1412     TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1413
1414     if( szProduct )
1415     {
1416         szwProduct = strdupAtoW( szProduct );
1417         if( !szwProduct )
1418             return ERROR_OUTOFMEMORY;
1419     }
1420
1421     r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1422     if( r == ERROR_SUCCESS )
1423     {
1424         WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1425                             szFeature, GUID_SIZE, NULL, NULL);
1426         WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1427                             szParent, GUID_SIZE, NULL, NULL);
1428     }
1429
1430     msi_free( szwProduct);
1431
1432     return r;
1433 }
1434
1435 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 
1436       LPWSTR szFeature, LPWSTR szParent)
1437 {
1438     HKEY hkeyProduct = 0;
1439     DWORD r, sz;
1440
1441     TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1442
1443     if( !szProduct )
1444         return ERROR_INVALID_PARAMETER;
1445
1446     r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1447     if( r != ERROR_SUCCESS )
1448         return ERROR_NO_MORE_ITEMS;
1449
1450     sz = GUID_SIZE;
1451     r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1452     RegCloseKey(hkeyProduct);
1453
1454     return r;
1455 }
1456
1457 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1458 {
1459     DWORD r;
1460     WCHAR szwGuid[GUID_SIZE];
1461
1462     TRACE("%d %p\n", index, lpguid);
1463
1464     r = MsiEnumComponentsW(index, szwGuid);
1465     if( r == ERROR_SUCCESS )
1466         WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1467
1468     return r;
1469 }
1470
1471 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1472 {
1473     HKEY hkeyComponents = 0;
1474     DWORD r;
1475     WCHAR szKeyName[SQUISH_GUID_SIZE];
1476
1477     TRACE("%d %p\n", index, lpguid);
1478
1479     r = RegCreateKeyW(HKEY_LOCAL_MACHINE, szInstaller_Components, &hkeyComponents);
1480     if( r != ERROR_SUCCESS )
1481         return ERROR_NO_MORE_ITEMS;
1482
1483     r = RegEnumKeyW(hkeyComponents, index, szKeyName, SQUISH_GUID_SIZE);
1484     if( r == ERROR_SUCCESS )
1485         unsquash_guid(szKeyName, lpguid);
1486     RegCloseKey(hkeyComponents);
1487
1488     return r;
1489 }
1490
1491 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1492 {
1493     DWORD r;
1494     WCHAR szwProduct[GUID_SIZE];
1495     LPWSTR szwComponent = NULL;
1496
1497     TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1498
1499     if ( !szProduct )
1500         return ERROR_INVALID_PARAMETER;
1501
1502     if( szComponent )
1503     {
1504         szwComponent = strdupAtoW( szComponent );
1505         if( !szwComponent )
1506             return ERROR_OUTOFMEMORY;
1507     }
1508
1509     r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1510     if( r == ERROR_SUCCESS )
1511     {
1512         WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1513                             szProduct, GUID_SIZE, NULL, NULL);
1514     }
1515
1516     msi_free( szwComponent);
1517
1518     return r;
1519 }
1520
1521 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1522 {
1523     HKEY hkeyComp = 0;
1524     DWORD r, sz;
1525     WCHAR szValName[SQUISH_GUID_SIZE];
1526
1527     TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1528
1529     if (!szComponent || !*szComponent || !szProduct)
1530         return ERROR_INVALID_PARAMETER;
1531
1532     if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1533         MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkeyComp, FALSE) != ERROR_SUCCESS)
1534         return ERROR_UNKNOWN_COMPONENT;
1535
1536     /* see if there are any products at all */
1537     sz = SQUISH_GUID_SIZE;
1538     r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1539     if (r != ERROR_SUCCESS)
1540     {
1541         RegCloseKey(hkeyComp);
1542
1543         if (index != 0)
1544             return ERROR_INVALID_PARAMETER;
1545
1546         return ERROR_UNKNOWN_COMPONENT;
1547     }
1548
1549     sz = SQUISH_GUID_SIZE;
1550     r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1551     if( r == ERROR_SUCCESS )
1552     {
1553         unsquash_guid(szValName, szProduct);
1554         TRACE("-> %s\n", debugstr_w(szProduct));
1555     }
1556     RegCloseKey(hkeyComp);
1557     return r;
1558 }
1559
1560 static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1561                 awstring *lpQualBuf, LPDWORD pcchQual,
1562                 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1563 {
1564     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1565     LPWSTR name = NULL, val = NULL;
1566     UINT r, r2;
1567     HKEY key;
1568
1569     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1570           lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1571
1572     if (!szComponent)
1573         return ERROR_INVALID_PARAMETER;
1574
1575     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1576     if (r != ERROR_SUCCESS)
1577         return ERROR_UNKNOWN_COMPONENT;
1578
1579     /* figure out how big the name is we want to return */
1580     name_max = 0x10;
1581     r = ERROR_OUTOFMEMORY;
1582     name = msi_alloc( name_max * sizeof(WCHAR) );
1583     if (!name)
1584         goto end;
1585
1586     val_max = 0x10;
1587     r = ERROR_OUTOFMEMORY;
1588     val = msi_alloc( val_max );
1589     if (!val)
1590         goto end;
1591
1592     /* loop until we allocate enough memory */
1593     while (1)
1594     {
1595         name_sz = name_max;
1596         val_sz = val_max;
1597         r = RegEnumValueW( key, iIndex, name, &name_sz,
1598                            NULL, &type, (LPBYTE)val, &val_sz );
1599         if (r == ERROR_SUCCESS)
1600             break;
1601         if (r != ERROR_MORE_DATA)
1602             goto end;
1603  
1604         if (type != REG_MULTI_SZ)
1605         {
1606             ERR("component data has wrong type (%d)\n", type);
1607             goto end;
1608         }
1609
1610         r = ERROR_OUTOFMEMORY;
1611         if ((name_sz+1) >= name_max)
1612         {
1613             name_max *= 2;
1614             msi_free( name );
1615             name = msi_alloc( name_max * sizeof (WCHAR) );
1616             if (!name)
1617                 goto end;
1618             continue;
1619         }
1620         if (val_sz > val_max)
1621         {
1622             val_max = val_sz + sizeof (WCHAR);
1623             msi_free( val );
1624             val = msi_alloc( val_max * sizeof (WCHAR) );
1625             if (!val)
1626                 goto end;
1627             continue;
1628         }
1629         ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1630         goto end;
1631     }
1632
1633     ofs = 0;
1634     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1635     if (r != ERROR_SUCCESS)
1636         goto end;
1637
1638     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1639
1640     r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1641     r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1642
1643     if (r2 != ERROR_SUCCESS)
1644         r = r2;
1645
1646 end:
1647     msi_free(val);
1648     msi_free(name);
1649     RegCloseKey(key);
1650
1651     return r;
1652 }
1653
1654 /*************************************************************************
1655  *  MsiEnumComponentQualifiersA [MSI.@]
1656  */
1657 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1658                 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1659                 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1660 {
1661     awstring qual, appdata;
1662     LPWSTR comp;
1663     UINT r;
1664
1665     TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1666           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1667           pcchApplicationDataBuf);
1668
1669     comp = strdupAtoW( szComponent );
1670     if (szComponent && !comp)
1671         return ERROR_OUTOFMEMORY;
1672
1673     qual.unicode = FALSE;
1674     qual.str.a = lpQualifierBuf;
1675
1676     appdata.unicode = FALSE;
1677     appdata.str.a = lpApplicationDataBuf;
1678
1679     r = MSI_EnumComponentQualifiers( comp, iIndex,
1680               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1681     msi_free( comp );
1682     return r;
1683 }
1684
1685 /*************************************************************************
1686  *  MsiEnumComponentQualifiersW [MSI.@]
1687  */
1688 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1689                 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1690                 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1691 {
1692     awstring qual, appdata;
1693
1694     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1695           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1696           pcchApplicationDataBuf);
1697
1698     qual.unicode = TRUE;
1699     qual.str.w = lpQualifierBuf;
1700
1701     appdata.unicode = TRUE;
1702     appdata.str.w = lpApplicationDataBuf;
1703
1704     return MSI_EnumComponentQualifiers( szComponent, iIndex,
1705                  &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1706 }
1707
1708 /*************************************************************************
1709  *  MsiEnumRelatedProductsW   [MSI.@]
1710  *
1711  */
1712 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1713                                     DWORD iProductIndex, LPWSTR lpProductBuf)
1714 {
1715     UINT r;
1716     HKEY hkey;
1717     DWORD dwSize = SQUISH_GUID_SIZE;
1718     WCHAR szKeyName[SQUISH_GUID_SIZE];
1719
1720     TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1721           iProductIndex, lpProductBuf);
1722
1723     if (NULL == szUpgradeCode)
1724         return ERROR_INVALID_PARAMETER;
1725     if (NULL == lpProductBuf)
1726         return ERROR_INVALID_PARAMETER;
1727
1728     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1729     if (r != ERROR_SUCCESS)
1730         return ERROR_NO_MORE_ITEMS;
1731
1732     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1733     if( r == ERROR_SUCCESS )
1734         unsquash_guid(szKeyName, lpProductBuf);
1735     RegCloseKey(hkey);
1736
1737     return r;
1738 }
1739
1740 /*************************************************************************
1741  *  MsiEnumRelatedProductsA   [MSI.@]
1742  *
1743  */
1744 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1745                                     DWORD iProductIndex, LPSTR lpProductBuf)
1746 {
1747     LPWSTR szwUpgradeCode = NULL;
1748     WCHAR productW[GUID_SIZE];
1749     UINT r;
1750
1751     TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1752           iProductIndex, lpProductBuf);
1753
1754     if (szUpgradeCode)
1755     {
1756         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1757         if( !szwUpgradeCode )
1758             return ERROR_OUTOFMEMORY;
1759     }
1760
1761     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1762                                  iProductIndex, productW );
1763     if (r == ERROR_SUCCESS)
1764     {
1765         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1766                              lpProductBuf, GUID_SIZE, NULL, NULL );
1767     }
1768     msi_free( szwUpgradeCode);
1769     return r;
1770 }
1771
1772 /***********************************************************************
1773  * MsiEnumPatchesExA            [MSI.@]
1774  */
1775 UINT WINAPI MsiEnumPatchesExA(LPCSTR szProductCode, LPCSTR szUserSid,
1776         DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPSTR szPatchCode,
1777         LPSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
1778         LPSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
1779 {
1780     LPWSTR prodcode = NULL;
1781     LPWSTR usersid = NULL;
1782     LPWSTR targsid = NULL;
1783     WCHAR patch[GUID_SIZE];
1784     WCHAR targprod[GUID_SIZE];
1785     DWORD len;
1786     UINT r;
1787
1788     TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
1789           debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, dwFilter,
1790           dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
1791           szTargetUserSid, pcchTargetUserSid);
1792
1793     if (szTargetUserSid && !pcchTargetUserSid)
1794         return ERROR_INVALID_PARAMETER;
1795
1796     if (szProductCode) prodcode = strdupAtoW(szProductCode);
1797     if (szUserSid) usersid = strdupAtoW(szUserSid);
1798
1799     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1800                           patch, targprod, pdwTargetProductContext,
1801                           NULL, &len);
1802     if (r != ERROR_SUCCESS)
1803         goto done;
1804
1805     WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1806                         GUID_SIZE, NULL, NULL);
1807     WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1808                         GUID_SIZE, NULL, NULL);
1809
1810     if (!szTargetUserSid)
1811     {
1812         if (pcchTargetUserSid)
1813             *pcchTargetUserSid = len;
1814
1815         goto done;
1816     }
1817
1818     targsid = msi_alloc(++len * sizeof(WCHAR));
1819     if (!targsid)
1820     {
1821         r = ERROR_OUTOFMEMORY;
1822         goto done;
1823     }
1824
1825     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1826                           patch, targprod, pdwTargetProductContext,
1827                           targsid, &len);
1828     if (r != ERROR_SUCCESS || !szTargetUserSid)
1829         goto done;
1830
1831     WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1832                         *pcchTargetUserSid, NULL, NULL);
1833
1834     len = lstrlenW(targsid);
1835     if (*pcchTargetUserSid < len + 1)
1836     {
1837         r = ERROR_MORE_DATA;
1838         *pcchTargetUserSid = len * sizeof(WCHAR);
1839     }
1840     else
1841         *pcchTargetUserSid = len;
1842
1843 done:
1844     msi_free(prodcode);
1845     msi_free(usersid);
1846     msi_free(targsid);
1847
1848     return r;
1849 }
1850
1851 static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
1852                                 MSIINSTALLCONTEXT context,
1853                                 LPWSTR patch, MSIPATCHSTATE *state)
1854 {
1855     DWORD type, val, size;
1856     HKEY prod, hkey = 0;
1857     HKEY udpatch = 0;
1858     LONG res;
1859     UINT r = ERROR_NO_MORE_ITEMS;
1860
1861     *state = MSIPATCHSTATE_INVALID;
1862
1863     r = MSIREG_OpenUserDataProductKey(prodcode, context,
1864                                       usersid, &prod, FALSE);
1865     if (r != ERROR_SUCCESS)
1866         return ERROR_NO_MORE_ITEMS;
1867
1868     res = RegOpenKeyExW(prod, szPatches, 0, KEY_READ, &hkey);
1869     if (res != ERROR_SUCCESS)
1870         goto done;
1871
1872     res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1873     if (res != ERROR_SUCCESS)
1874         goto done;
1875
1876     size = sizeof(DWORD);
1877     res = RegGetValueW(udpatch, NULL, szState, RRF_RT_DWORD, &type, &val, &size);
1878     if (res != ERROR_SUCCESS ||
1879         val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1880     {
1881         r = ERROR_BAD_CONFIGURATION;
1882         goto done;
1883     }
1884
1885     *state = val;
1886     r = ERROR_SUCCESS;
1887
1888 done:
1889     RegCloseKey(udpatch);
1890     RegCloseKey(hkey);
1891     RegCloseKey(prod);
1892
1893     return r;
1894 }
1895
1896 static UINT msi_check_product_patches(LPCWSTR prodcode, LPCWSTR usersid,
1897         MSIINSTALLCONTEXT context, DWORD filter, DWORD index, DWORD *idx,
1898         LPWSTR patch, LPWSTR targetprod, MSIINSTALLCONTEXT *targetctx,
1899         LPWSTR targetsid, DWORD *sidsize, LPWSTR *transforms)
1900 {
1901     MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1902     LPWSTR ptr, patches = NULL;
1903     HKEY prod, patchkey = 0;
1904     HKEY localprod = 0, localpatch = 0;
1905     DWORD type, size;
1906     LONG res;
1907     UINT temp, r = ERROR_NO_MORE_ITEMS;
1908
1909     if (MSIREG_OpenProductKey(prodcode, usersid, context,
1910                               &prod, FALSE) != ERROR_SUCCESS)
1911         return ERROR_NO_MORE_ITEMS;
1912
1913     size = 0;
1914     res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, NULL,
1915                        &size);
1916     if (res != ERROR_SUCCESS)
1917         goto done;
1918
1919     if (type != REG_MULTI_SZ)
1920     {
1921         r = ERROR_BAD_CONFIGURATION;
1922         goto done;
1923     }
1924
1925     patches = msi_alloc(size);
1926     if (!patches)
1927     {
1928         r = ERROR_OUTOFMEMORY;
1929         goto done;
1930     }
1931
1932     res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type,
1933                        patches, &size);
1934     if (res != ERROR_SUCCESS)
1935         goto done;
1936
1937     ptr = patches;
1938     for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1939     {
1940         if (!unsquash_guid(ptr, patch))
1941         {
1942             r = ERROR_BAD_CONFIGURATION;
1943             goto done;
1944         }
1945
1946         size = 0;
1947         res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1948                            &type, NULL, &size);
1949         if (res != ERROR_SUCCESS)
1950             continue;
1951
1952         if (transforms)
1953         {
1954             *transforms = msi_alloc(size);
1955             if (!*transforms)
1956             {
1957                 r = ERROR_OUTOFMEMORY;
1958                 goto done;
1959             }
1960
1961             res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1962                                &type, *transforms, &size);
1963             if (res != ERROR_SUCCESS)
1964                 continue;
1965         }
1966
1967         if (context == MSIINSTALLCONTEXT_USERMANAGED)
1968         {
1969             if (!(filter & MSIPATCHSTATE_APPLIED))
1970             {
1971                 temp = msi_get_patch_state(prodcode, usersid, context,
1972                                            ptr, &state);
1973                 if (temp == ERROR_BAD_CONFIGURATION)
1974                 {
1975                     r = ERROR_BAD_CONFIGURATION;
1976                     goto done;
1977                 }
1978
1979                 if (temp != ERROR_SUCCESS || !(filter & state))
1980                     continue;
1981             }
1982         }
1983         else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1984         {
1985             if (!(filter & MSIPATCHSTATE_APPLIED))
1986             {
1987                 temp = msi_get_patch_state(prodcode, usersid, context,
1988                                            ptr, &state);
1989                 if (temp == ERROR_BAD_CONFIGURATION)
1990                 {
1991                     r = ERROR_BAD_CONFIGURATION;
1992                     goto done;
1993                 }
1994
1995                 if (temp != ERROR_SUCCESS || !(filter & state))
1996                     continue;
1997             }
1998             else
1999             {
2000                 temp = MSIREG_OpenUserDataPatchKey(patch, context,
2001                                                    &patchkey, FALSE);
2002                 RegCloseKey(patchkey);
2003                 if (temp != ERROR_SUCCESS)
2004                     continue;
2005             }
2006         }
2007         else if (context == MSIINSTALLCONTEXT_MACHINE)
2008         {
2009             usersid = szEmpty;
2010
2011             if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
2012                 RegOpenKeyExW(localprod, szPatches, 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
2013                 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
2014             {
2015                 res = RegGetValueW(patchkey, NULL, szState, RRF_RT_REG_DWORD,
2016                                    &type, &state, &size);
2017
2018                 if (!(filter & state))
2019                     res = ERROR_NO_MORE_ITEMS;
2020
2021                 RegCloseKey(patchkey);
2022             }
2023
2024             RegCloseKey(localpatch);
2025             RegCloseKey(localprod);
2026
2027             if (res != ERROR_SUCCESS)
2028                 continue;
2029         }
2030
2031         if (*idx < index)
2032         {
2033             (*idx)++;
2034             continue;
2035         }
2036
2037         r = ERROR_SUCCESS;
2038         if (targetprod)
2039             lstrcpyW(targetprod, prodcode);
2040
2041         if (targetctx)
2042             *targetctx = context;
2043
2044         if (targetsid)
2045         {
2046             lstrcpynW(targetsid, usersid, *sidsize);
2047             if (lstrlenW(usersid) >= *sidsize)
2048                 r = ERROR_MORE_DATA;
2049         }
2050
2051         if (sidsize)
2052         {
2053             *sidsize = lstrlenW(usersid);
2054             if (!targetsid)
2055                 *sidsize *= sizeof(WCHAR);
2056         }
2057     }
2058
2059 done:
2060     RegCloseKey(prod);
2061     msi_free(patches);
2062
2063     return r;
2064 }
2065
2066 static UINT msi_enum_patches(LPCWSTR szProductCode, LPCWSTR szUserSid,
2067         DWORD dwContext, DWORD dwFilter, DWORD dwIndex, DWORD *idx,
2068         LPWSTR szPatchCode, LPWSTR szTargetProductCode,
2069         MSIINSTALLCONTEXT *pdwTargetProductContext, LPWSTR szTargetUserSid,
2070         LPDWORD pcchTargetUserSid, LPWSTR *szTransforms)
2071 {
2072     LPWSTR usersid = NULL;
2073     UINT r = ERROR_INVALID_PARAMETER;
2074
2075     if (!szUserSid)
2076     {
2077         get_user_sid(&usersid);
2078         szUserSid = usersid;
2079     }
2080
2081     if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
2082     {
2083         r = msi_check_product_patches(szProductCode, szUserSid,
2084                                       MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
2085                                       dwIndex, idx, szPatchCode,
2086                                       szTargetProductCode,
2087                                       pdwTargetProductContext, szTargetUserSid,
2088                                       pcchTargetUserSid, szTransforms);
2089         if (r != ERROR_NO_MORE_ITEMS)
2090             goto done;
2091     }
2092
2093     if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
2094     {
2095         r = msi_check_product_patches(szProductCode, szUserSid,
2096                                       MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter,
2097                                       dwIndex, idx, szPatchCode,
2098                                       szTargetProductCode,
2099                                       pdwTargetProductContext, szTargetUserSid,
2100                                       pcchTargetUserSid, szTransforms);
2101         if (r != ERROR_NO_MORE_ITEMS)
2102             goto done;
2103     }
2104
2105     if (dwContext & MSIINSTALLCONTEXT_MACHINE)
2106     {
2107         r = msi_check_product_patches(szProductCode, szUserSid,
2108                                       MSIINSTALLCONTEXT_MACHINE, dwFilter,
2109                                       dwIndex, idx, szPatchCode,
2110                                       szTargetProductCode,
2111                                       pdwTargetProductContext, szTargetUserSid,
2112                                       pcchTargetUserSid, szTransforms);
2113         if (r != ERROR_NO_MORE_ITEMS)
2114             goto done;
2115     }
2116
2117 done:
2118     LocalFree(usersid);
2119     return r;
2120 }
2121
2122 /***********************************************************************
2123  * MsiEnumPatchesExW            [MSI.@]
2124  */
2125 UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
2126         DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
2127         LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
2128         LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
2129 {
2130     WCHAR squished_pc[GUID_SIZE];
2131     DWORD idx = 0;
2132     UINT r;
2133
2134     static DWORD last_index;
2135
2136     TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
2137           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
2138           dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
2139           szTargetUserSid, pcchTargetUserSid);
2140
2141     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
2142         return ERROR_INVALID_PARAMETER;
2143
2144     if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
2145         return ERROR_INVALID_PARAMETER;
2146
2147     if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
2148         return ERROR_INVALID_PARAMETER;
2149
2150     if (dwContext <= MSIINSTALLCONTEXT_NONE ||
2151         dwContext > MSIINSTALLCONTEXT_ALL)
2152         return ERROR_INVALID_PARAMETER;
2153
2154     if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
2155         return ERROR_INVALID_PARAMETER;
2156
2157     if (dwIndex && dwIndex - last_index != 1)
2158         return ERROR_INVALID_PARAMETER;
2159
2160     if (dwIndex == 0)
2161         last_index = 0;
2162
2163     r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter,
2164                          dwIndex, &idx, szPatchCode, szTargetProductCode,
2165                          pdwTargetProductContext, szTargetUserSid,
2166                          pcchTargetUserSid, NULL);
2167
2168     if (r == ERROR_SUCCESS)
2169         last_index = dwIndex;
2170     else
2171         last_index = 0;
2172
2173     return r;
2174 }
2175
2176 /***********************************************************************
2177  * MsiEnumPatchesA            [MSI.@]
2178  */
2179 UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex,
2180         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2181 {
2182     LPWSTR product, transforms;
2183     WCHAR patch[GUID_SIZE];
2184     DWORD len;
2185     UINT r;
2186
2187     TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex,
2188           lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2189
2190     if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2191         return ERROR_INVALID_PARAMETER;
2192
2193     product = strdupAtoW(szProduct);
2194     if (!product)
2195         return ERROR_OUTOFMEMORY;
2196
2197     len = *pcchTransformsBuf;
2198     transforms = msi_alloc( len * sizeof(WCHAR) );
2199     if (!transforms)
2200     {
2201         r = ERROR_OUTOFMEMORY;
2202         goto done;
2203     }
2204
2205     r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2206     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2207         goto done;
2208
2209     WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2210                         GUID_SIZE, NULL, NULL);
2211
2212     if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2213                              *pcchTransformsBuf, NULL, NULL))
2214         r = ERROR_MORE_DATA;
2215
2216     if (r == ERROR_MORE_DATA)
2217     {
2218         lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2219         *pcchTransformsBuf = len * 2;
2220     }
2221     else
2222         *pcchTransformsBuf = strlen( lpTransformsBuf );
2223
2224 done:
2225     msi_free(transforms);
2226     msi_free(product);
2227
2228     return r;
2229 }
2230
2231 /***********************************************************************
2232  * MsiEnumPatchesW            [MSI.@]
2233  */
2234 UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex,
2235         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2236 {
2237     WCHAR squished_pc[GUID_SIZE];
2238     LPWSTR transforms = NULL;
2239     HKEY prod;
2240     DWORD idx = 0;
2241     UINT r;
2242
2243     TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex,
2244           lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2245
2246     if (!szProduct || !squash_guid(szProduct, squished_pc))
2247         return ERROR_INVALID_PARAMETER;
2248
2249     if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2250         return ERROR_INVALID_PARAMETER;
2251
2252     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2253                               &prod, FALSE) != ERROR_SUCCESS &&
2254         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2255                               &prod, FALSE) != ERROR_SUCCESS &&
2256         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2257                               &prod, FALSE) != ERROR_SUCCESS)
2258         return ERROR_UNKNOWN_PRODUCT;
2259
2260     RegCloseKey(prod);
2261
2262     r = msi_enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL,
2263                          MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf,
2264                          NULL, NULL, NULL, NULL, &transforms);
2265     if (r != ERROR_SUCCESS)
2266         goto done;
2267
2268     lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2269     if (*pcchTransformsBuf <= lstrlenW(transforms))
2270     {
2271         r = ERROR_MORE_DATA;
2272         *pcchTransformsBuf = lstrlenW(transforms);
2273     }
2274     else
2275         *pcchTransformsBuf = lstrlenW(transforms);
2276
2277 done:
2278     msi_free(transforms);
2279     return r;
2280 }
2281
2282 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
2283         DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
2284         MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
2285 {
2286     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
2287           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
2288           szSid, pcchSid);
2289     return ERROR_NO_MORE_ITEMS;
2290 }
2291
2292 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
2293         DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
2294         MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
2295 {
2296     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
2297           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
2298           szSid, pcchSid);
2299     return ERROR_NO_MORE_ITEMS;
2300 }