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