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