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