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