msi: Use an iface instead of an vtbl pointer in IClassFactoryImpl.
[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         unsquash_guid(szValName, szProduct);
1553
1554     RegCloseKey(hkeyComp);
1555
1556     return r;
1557 }
1558
1559 static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1560                 awstring *lpQualBuf, LPDWORD pcchQual,
1561                 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1562 {
1563     DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1564     LPWSTR name = NULL, val = NULL;
1565     UINT r, r2;
1566     HKEY key;
1567
1568     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1569           lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1570
1571     if (!szComponent)
1572         return ERROR_INVALID_PARAMETER;
1573
1574     r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1575     if (r != ERROR_SUCCESS)
1576         return ERROR_UNKNOWN_COMPONENT;
1577
1578     /* figure out how big the name is we want to return */
1579     name_max = 0x10;
1580     r = ERROR_OUTOFMEMORY;
1581     name = msi_alloc( name_max * sizeof(WCHAR) );
1582     if (!name)
1583         goto end;
1584
1585     val_max = 0x10;
1586     r = ERROR_OUTOFMEMORY;
1587     val = msi_alloc( val_max );
1588     if (!val)
1589         goto end;
1590
1591     /* loop until we allocate enough memory */
1592     while (1)
1593     {
1594         name_sz = name_max;
1595         val_sz = val_max;
1596         r = RegEnumValueW( key, iIndex, name, &name_sz,
1597                            NULL, &type, (LPBYTE)val, &val_sz );
1598         if (r == ERROR_SUCCESS)
1599             break;
1600         if (r != ERROR_MORE_DATA)
1601             goto end;
1602  
1603         if (type != REG_MULTI_SZ)
1604         {
1605             ERR("component data has wrong type (%d)\n", type);
1606             goto end;
1607         }
1608
1609         r = ERROR_OUTOFMEMORY;
1610         if ((name_sz+1) >= name_max)
1611         {
1612             name_max *= 2;
1613             msi_free( name );
1614             name = msi_alloc( name_max * sizeof (WCHAR) );
1615             if (!name)
1616                 goto end;
1617             continue;
1618         }
1619         if (val_sz > val_max)
1620         {
1621             val_max = val_sz + sizeof (WCHAR);
1622             msi_free( val );
1623             val = msi_alloc( val_max * sizeof (WCHAR) );
1624             if (!val)
1625                 goto end;
1626             continue;
1627         }
1628         ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1629         goto end;
1630     }
1631
1632     ofs = 0;
1633     r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1634     if (r != ERROR_SUCCESS)
1635         goto end;
1636
1637     TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1638
1639     r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
1640     r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
1641
1642     if (r2 != ERROR_SUCCESS)
1643         r = r2;
1644
1645 end:
1646     msi_free(val);
1647     msi_free(name);
1648     RegCloseKey(key);
1649
1650     return r;
1651 }
1652
1653 /*************************************************************************
1654  *  MsiEnumComponentQualifiersA [MSI.@]
1655  */
1656 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1657                 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1658                 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1659 {
1660     awstring qual, appdata;
1661     LPWSTR comp;
1662     UINT r;
1663
1664     TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1665           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1666           pcchApplicationDataBuf);
1667
1668     comp = strdupAtoW( szComponent );
1669     if (szComponent && !comp)
1670         return ERROR_OUTOFMEMORY;
1671
1672     qual.unicode = FALSE;
1673     qual.str.a = lpQualifierBuf;
1674
1675     appdata.unicode = FALSE;
1676     appdata.str.a = lpApplicationDataBuf;
1677
1678     r = MSI_EnumComponentQualifiers( comp, iIndex,
1679               &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1680     msi_free( comp );
1681     return r;
1682 }
1683
1684 /*************************************************************************
1685  *  MsiEnumComponentQualifiersW [MSI.@]
1686  */
1687 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1688                 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1689                 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1690 {
1691     awstring qual, appdata;
1692
1693     TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1694           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1695           pcchApplicationDataBuf);
1696
1697     qual.unicode = TRUE;
1698     qual.str.w = lpQualifierBuf;
1699
1700     appdata.unicode = TRUE;
1701     appdata.str.w = lpApplicationDataBuf;
1702
1703     return MSI_EnumComponentQualifiers( szComponent, iIndex,
1704                  &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1705 }
1706
1707 /*************************************************************************
1708  *  MsiEnumRelatedProductsW   [MSI.@]
1709  *
1710  */
1711 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1712                                     DWORD iProductIndex, LPWSTR lpProductBuf)
1713 {
1714     UINT r;
1715     HKEY hkey;
1716     DWORD dwSize = SQUISH_GUID_SIZE;
1717     WCHAR szKeyName[SQUISH_GUID_SIZE];
1718
1719     TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1720           iProductIndex, lpProductBuf);
1721
1722     if (NULL == szUpgradeCode)
1723         return ERROR_INVALID_PARAMETER;
1724     if (NULL == lpProductBuf)
1725         return ERROR_INVALID_PARAMETER;
1726
1727     r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1728     if (r != ERROR_SUCCESS)
1729         return ERROR_NO_MORE_ITEMS;
1730
1731     r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1732     if( r == ERROR_SUCCESS )
1733         unsquash_guid(szKeyName, lpProductBuf);
1734     RegCloseKey(hkey);
1735
1736     return r;
1737 }
1738
1739 /*************************************************************************
1740  *  MsiEnumRelatedProductsA   [MSI.@]
1741  *
1742  */
1743 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1744                                     DWORD iProductIndex, LPSTR lpProductBuf)
1745 {
1746     LPWSTR szwUpgradeCode = NULL;
1747     WCHAR productW[GUID_SIZE];
1748     UINT r;
1749
1750     TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1751           iProductIndex, lpProductBuf);
1752
1753     if (szUpgradeCode)
1754     {
1755         szwUpgradeCode = strdupAtoW( szUpgradeCode );
1756         if( !szwUpgradeCode )
1757             return ERROR_OUTOFMEMORY;
1758     }
1759
1760     r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1761                                  iProductIndex, productW );
1762     if (r == ERROR_SUCCESS)
1763     {
1764         WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1765                              lpProductBuf, GUID_SIZE, NULL, NULL );
1766     }
1767     msi_free( szwUpgradeCode);
1768     return r;
1769 }
1770
1771 /***********************************************************************
1772  * MsiEnumPatchesExA            [MSI.@]
1773  */
1774 UINT WINAPI MsiEnumPatchesExA(LPCSTR szProductCode, LPCSTR szUserSid,
1775         DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPSTR szPatchCode,
1776         LPSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
1777         LPSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
1778 {
1779     LPWSTR prodcode = NULL;
1780     LPWSTR usersid = NULL;
1781     LPWSTR targsid = NULL;
1782     WCHAR patch[GUID_SIZE];
1783     WCHAR targprod[GUID_SIZE];
1784     DWORD len;
1785     UINT r;
1786
1787     TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
1788           debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, dwFilter,
1789           dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
1790           szTargetUserSid, pcchTargetUserSid);
1791
1792     if (szTargetUserSid && !pcchTargetUserSid)
1793         return ERROR_INVALID_PARAMETER;
1794
1795     if (szProductCode) prodcode = strdupAtoW(szProductCode);
1796     if (szUserSid) usersid = strdupAtoW(szUserSid);
1797
1798     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1799                           patch, targprod, pdwTargetProductContext,
1800                           NULL, &len);
1801     if (r != ERROR_SUCCESS)
1802         goto done;
1803
1804     WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1805                         GUID_SIZE, NULL, NULL);
1806     WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1807                         GUID_SIZE, NULL, NULL);
1808
1809     if (!szTargetUserSid)
1810     {
1811         if (pcchTargetUserSid)
1812             *pcchTargetUserSid = len;
1813
1814         goto done;
1815     }
1816
1817     targsid = msi_alloc(++len * sizeof(WCHAR));
1818     if (!targsid)
1819     {
1820         r = ERROR_OUTOFMEMORY;
1821         goto done;
1822     }
1823
1824     r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1825                           patch, targprod, pdwTargetProductContext,
1826                           targsid, &len);
1827     if (r != ERROR_SUCCESS || !szTargetUserSid)
1828         goto done;
1829
1830     WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1831                         *pcchTargetUserSid, NULL, NULL);
1832
1833     len = lstrlenW(targsid);
1834     if (*pcchTargetUserSid < len + 1)
1835     {
1836         r = ERROR_MORE_DATA;
1837         *pcchTargetUserSid = len * sizeof(WCHAR);
1838     }
1839     else
1840         *pcchTargetUserSid = len;
1841
1842 done:
1843     msi_free(prodcode);
1844     msi_free(usersid);
1845     msi_free(targsid);
1846
1847     return r;
1848 }
1849
1850 static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
1851                                 MSIINSTALLCONTEXT context,
1852                                 LPWSTR patch, MSIPATCHSTATE *state)
1853 {
1854     DWORD type, val, size;
1855     HKEY prod, hkey = 0;
1856     HKEY udpatch = 0;
1857     LONG res;
1858     UINT r = ERROR_NO_MORE_ITEMS;
1859
1860     *state = MSIPATCHSTATE_INVALID;
1861
1862     r = MSIREG_OpenUserDataProductKey(prodcode, context,
1863                                       usersid, &prod, FALSE);
1864     if (r != ERROR_SUCCESS)
1865         return ERROR_NO_MORE_ITEMS;
1866
1867     res = RegOpenKeyExW(prod, szPatches, 0, KEY_READ, &hkey);
1868     if (res != ERROR_SUCCESS)
1869         goto done;
1870
1871     res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1872     if (res != ERROR_SUCCESS)
1873         goto done;
1874
1875     size = sizeof(DWORD);
1876     res = RegGetValueW(udpatch, NULL, szState, RRF_RT_DWORD, &type, &val, &size);
1877     if (res != ERROR_SUCCESS ||
1878         val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1879     {
1880         r = ERROR_BAD_CONFIGURATION;
1881         goto done;
1882     }
1883
1884     *state = val;
1885     r = ERROR_SUCCESS;
1886
1887 done:
1888     RegCloseKey(udpatch);
1889     RegCloseKey(hkey);
1890     RegCloseKey(prod);
1891
1892     return r;
1893 }
1894
1895 static UINT msi_check_product_patches(LPCWSTR prodcode, LPCWSTR usersid,
1896         MSIINSTALLCONTEXT context, DWORD filter, DWORD index, DWORD *idx,
1897         LPWSTR patch, LPWSTR targetprod, MSIINSTALLCONTEXT *targetctx,
1898         LPWSTR targetsid, DWORD *sidsize, LPWSTR *transforms)
1899 {
1900     MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1901     LPWSTR ptr, patches = NULL;
1902     HKEY prod, patchkey = 0;
1903     HKEY localprod = 0, localpatch = 0;
1904     DWORD type, size;
1905     LONG res;
1906     UINT temp, r = ERROR_NO_MORE_ITEMS;
1907
1908     if (MSIREG_OpenProductKey(prodcode, usersid, context,
1909                               &prod, FALSE) != ERROR_SUCCESS)
1910         return ERROR_NO_MORE_ITEMS;
1911
1912     size = 0;
1913     res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, NULL,
1914                        &size);
1915     if (res != ERROR_SUCCESS)
1916         goto done;
1917
1918     if (type != REG_MULTI_SZ)
1919     {
1920         r = ERROR_BAD_CONFIGURATION;
1921         goto done;
1922     }
1923
1924     patches = msi_alloc(size);
1925     if (!patches)
1926     {
1927         r = ERROR_OUTOFMEMORY;
1928         goto done;
1929     }
1930
1931     res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type,
1932                        patches, &size);
1933     if (res != ERROR_SUCCESS)
1934         goto done;
1935
1936     ptr = patches;
1937     for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1938     {
1939         if (!unsquash_guid(ptr, patch))
1940         {
1941             r = ERROR_BAD_CONFIGURATION;
1942             goto done;
1943         }
1944
1945         size = 0;
1946         res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1947                            &type, NULL, &size);
1948         if (res != ERROR_SUCCESS)
1949             continue;
1950
1951         if (transforms)
1952         {
1953             *transforms = msi_alloc(size);
1954             if (!*transforms)
1955             {
1956                 r = ERROR_OUTOFMEMORY;
1957                 goto done;
1958             }
1959
1960             res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1961                                &type, *transforms, &size);
1962             if (res != ERROR_SUCCESS)
1963                 continue;
1964         }
1965
1966         if (context == MSIINSTALLCONTEXT_USERMANAGED)
1967         {
1968             if (!(filter & MSIPATCHSTATE_APPLIED))
1969             {
1970                 temp = msi_get_patch_state(prodcode, usersid, context,
1971                                            ptr, &state);
1972                 if (temp == ERROR_BAD_CONFIGURATION)
1973                 {
1974                     r = ERROR_BAD_CONFIGURATION;
1975                     goto done;
1976                 }
1977
1978                 if (temp != ERROR_SUCCESS || !(filter & state))
1979                     continue;
1980             }
1981         }
1982         else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1983         {
1984             if (!(filter & MSIPATCHSTATE_APPLIED))
1985             {
1986                 temp = msi_get_patch_state(prodcode, usersid, context,
1987                                            ptr, &state);
1988                 if (temp == ERROR_BAD_CONFIGURATION)
1989                 {
1990                     r = ERROR_BAD_CONFIGURATION;
1991                     goto done;
1992                 }
1993
1994                 if (temp != ERROR_SUCCESS || !(filter & state))
1995                     continue;
1996             }
1997             else
1998             {
1999                 temp = MSIREG_OpenUserDataPatchKey(patch, context,
2000                                                    &patchkey, FALSE);
2001                 RegCloseKey(patchkey);
2002                 if (temp != ERROR_SUCCESS)
2003                     continue;
2004             }
2005         }
2006         else if (context == MSIINSTALLCONTEXT_MACHINE)
2007         {
2008             usersid = szEmpty;
2009
2010             if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
2011                 RegOpenKeyExW(localprod, szPatches, 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
2012                 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
2013             {
2014                 res = RegGetValueW(patchkey, NULL, szState, RRF_RT_REG_DWORD,
2015                                    &type, &state, &size);
2016
2017                 if (!(filter & state))
2018                     res = ERROR_NO_MORE_ITEMS;
2019
2020                 RegCloseKey(patchkey);
2021             }
2022
2023             RegCloseKey(localpatch);
2024             RegCloseKey(localprod);
2025
2026             if (res != ERROR_SUCCESS)
2027                 continue;
2028         }
2029
2030         if (*idx < index)
2031         {
2032             (*idx)++;
2033             continue;
2034         }
2035
2036         r = ERROR_SUCCESS;
2037         if (targetprod)
2038             lstrcpyW(targetprod, prodcode);
2039
2040         if (targetctx)
2041             *targetctx = context;
2042
2043         if (targetsid)
2044         {
2045             lstrcpynW(targetsid, usersid, *sidsize);
2046             if (lstrlenW(usersid) >= *sidsize)
2047                 r = ERROR_MORE_DATA;
2048         }
2049
2050         if (sidsize)
2051         {
2052             *sidsize = lstrlenW(usersid);
2053             if (!targetsid)
2054                 *sidsize *= sizeof(WCHAR);
2055         }
2056     }
2057
2058 done:
2059     RegCloseKey(prod);
2060     msi_free(patches);
2061
2062     return r;
2063 }
2064
2065 static UINT msi_enum_patches(LPCWSTR szProductCode, LPCWSTR szUserSid,
2066         DWORD dwContext, DWORD dwFilter, DWORD dwIndex, DWORD *idx,
2067         LPWSTR szPatchCode, LPWSTR szTargetProductCode,
2068         MSIINSTALLCONTEXT *pdwTargetProductContext, LPWSTR szTargetUserSid,
2069         LPDWORD pcchTargetUserSid, LPWSTR *szTransforms)
2070 {
2071     LPWSTR usersid = NULL;
2072     UINT r = ERROR_INVALID_PARAMETER;
2073
2074     if (!szUserSid)
2075     {
2076         get_user_sid(&usersid);
2077         szUserSid = usersid;
2078     }
2079
2080     if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
2081     {
2082         r = msi_check_product_patches(szProductCode, szUserSid,
2083                                       MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
2084                                       dwIndex, idx, szPatchCode,
2085                                       szTargetProductCode,
2086                                       pdwTargetProductContext, szTargetUserSid,
2087                                       pcchTargetUserSid, szTransforms);
2088         if (r != ERROR_NO_MORE_ITEMS)
2089             goto done;
2090     }
2091
2092     if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
2093     {
2094         r = msi_check_product_patches(szProductCode, szUserSid,
2095                                       MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter,
2096                                       dwIndex, idx, szPatchCode,
2097                                       szTargetProductCode,
2098                                       pdwTargetProductContext, szTargetUserSid,
2099                                       pcchTargetUserSid, szTransforms);
2100         if (r != ERROR_NO_MORE_ITEMS)
2101             goto done;
2102     }
2103
2104     if (dwContext & MSIINSTALLCONTEXT_MACHINE)
2105     {
2106         r = msi_check_product_patches(szProductCode, szUserSid,
2107                                       MSIINSTALLCONTEXT_MACHINE, dwFilter,
2108                                       dwIndex, idx, szPatchCode,
2109                                       szTargetProductCode,
2110                                       pdwTargetProductContext, szTargetUserSid,
2111                                       pcchTargetUserSid, szTransforms);
2112         if (r != ERROR_NO_MORE_ITEMS)
2113             goto done;
2114     }
2115
2116 done:
2117     LocalFree(usersid);
2118     return r;
2119 }
2120
2121 /***********************************************************************
2122  * MsiEnumPatchesExW            [MSI.@]
2123  */
2124 UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
2125         DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
2126         LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
2127         LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
2128 {
2129     WCHAR squished_pc[GUID_SIZE];
2130     DWORD idx = 0;
2131     UINT r;
2132
2133     static DWORD last_index;
2134
2135     TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
2136           debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
2137           dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
2138           szTargetUserSid, pcchTargetUserSid);
2139
2140     if (!szProductCode || !squash_guid(szProductCode, squished_pc))
2141         return ERROR_INVALID_PARAMETER;
2142
2143     if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
2144         return ERROR_INVALID_PARAMETER;
2145
2146     if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
2147         return ERROR_INVALID_PARAMETER;
2148
2149     if (dwContext <= MSIINSTALLCONTEXT_NONE ||
2150         dwContext > MSIINSTALLCONTEXT_ALL)
2151         return ERROR_INVALID_PARAMETER;
2152
2153     if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
2154         return ERROR_INVALID_PARAMETER;
2155
2156     if (dwIndex && dwIndex - last_index != 1)
2157         return ERROR_INVALID_PARAMETER;
2158
2159     if (dwIndex == 0)
2160         last_index = 0;
2161
2162     r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter,
2163                          dwIndex, &idx, szPatchCode, szTargetProductCode,
2164                          pdwTargetProductContext, szTargetUserSid,
2165                          pcchTargetUserSid, NULL);
2166
2167     if (r == ERROR_SUCCESS)
2168         last_index = dwIndex;
2169     else
2170         last_index = 0;
2171
2172     return r;
2173 }
2174
2175 /***********************************************************************
2176  * MsiEnumPatchesA            [MSI.@]
2177  */
2178 UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex,
2179         LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2180 {
2181     LPWSTR product, transforms;
2182     WCHAR patch[GUID_SIZE];
2183     DWORD len;
2184     UINT r;
2185
2186     TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex,
2187           lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2188
2189     if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2190         return ERROR_INVALID_PARAMETER;
2191
2192     product = strdupAtoW(szProduct);
2193     if (!product)
2194         return ERROR_OUTOFMEMORY;
2195
2196     len = *pcchTransformsBuf;
2197     transforms = msi_alloc( len * sizeof(WCHAR) );
2198     if (!transforms)
2199     {
2200         r = ERROR_OUTOFMEMORY;
2201         goto done;
2202     }
2203
2204     r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2205     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2206         goto done;
2207
2208     WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2209                         GUID_SIZE, NULL, NULL);
2210
2211     if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2212                              *pcchTransformsBuf, NULL, NULL))
2213         r = ERROR_MORE_DATA;
2214
2215     if (r == ERROR_MORE_DATA)
2216     {
2217         lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2218         *pcchTransformsBuf = len * 2;
2219     }
2220     else
2221         *pcchTransformsBuf = strlen( lpTransformsBuf );
2222
2223 done:
2224     msi_free(transforms);
2225     msi_free(product);
2226
2227     return r;
2228 }
2229
2230 /***********************************************************************
2231  * MsiEnumPatchesW            [MSI.@]
2232  */
2233 UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex,
2234         LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2235 {
2236     WCHAR squished_pc[GUID_SIZE];
2237     LPWSTR transforms = NULL;
2238     HKEY prod;
2239     DWORD idx = 0;
2240     UINT r;
2241
2242     TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex,
2243           lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2244
2245     if (!szProduct || !squash_guid(szProduct, squished_pc))
2246         return ERROR_INVALID_PARAMETER;
2247
2248     if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2249         return ERROR_INVALID_PARAMETER;
2250
2251     if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2252                               &prod, FALSE) != ERROR_SUCCESS &&
2253         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2254                               &prod, FALSE) != ERROR_SUCCESS &&
2255         MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2256                               &prod, FALSE) != ERROR_SUCCESS)
2257         return ERROR_UNKNOWN_PRODUCT;
2258
2259     RegCloseKey(prod);
2260
2261     r = msi_enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL,
2262                          MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf,
2263                          NULL, NULL, NULL, NULL, &transforms);
2264     if (r != ERROR_SUCCESS)
2265         goto done;
2266
2267     lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2268     if (*pcchTransformsBuf <= lstrlenW(transforms))
2269     {
2270         r = ERROR_MORE_DATA;
2271         *pcchTransformsBuf = lstrlenW(transforms);
2272     }
2273     else
2274         *pcchTransformsBuf = lstrlenW(transforms);
2275
2276 done:
2277     msi_free(transforms);
2278     return r;
2279 }
2280
2281 UINT WINAPI MsiEnumProductsExA( LPCSTR szProductCode, LPCSTR szUserSid,
2282         DWORD dwContext, DWORD dwIndex, CHAR szInstalledProductCode[39],
2283         MSIINSTALLCONTEXT* pdwInstalledContext, LPSTR szSid, LPDWORD pcchSid)
2284 {
2285     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_a(szProductCode), debugstr_a(szUserSid),
2286           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
2287           szSid, pcchSid);
2288     return ERROR_NO_MORE_ITEMS;
2289 }
2290
2291 UINT WINAPI MsiEnumProductsExW( LPCWSTR szProductCode, LPCWSTR szUserSid,
2292         DWORD dwContext, DWORD dwIndex, WCHAR szInstalledProductCode[39],
2293         MSIINSTALLCONTEXT* pdwInstalledContext, LPWSTR szSid, LPDWORD pcchSid)
2294 {
2295     FIXME("%s %s %d %d %p %p %p %p\n", debugstr_w(szProductCode), debugstr_w(szUserSid),
2296           dwContext, dwIndex, szInstalledProductCode, pdwInstalledContext,
2297           szSid, pcchSid);
2298     return ERROR_NO_MORE_ITEMS;
2299 }