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