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