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