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