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