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