ntoskrnl.exe: Reimplement KeSetTimerEx() on top of thread pool.
[wine.git] / dlls / msi / registry.c
blob4d439d0b304b11ece930e4482b7633ad4bfc1e10
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
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
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msipriv.h"
34 #include "wincrypt.h"
35 #include "winver.h"
36 #include "winuser.h"
37 #include "sddl.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41 /*
42 * This module will be all the helper functions for registry access by the
43 * installer bits.
46 static const WCHAR szUserDataFeatures_fmt[] = {
47 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
48 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
49 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
50 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\','F','e','a','t','u','r','e','s',0};
52 static const WCHAR szUserDataComp_fmt[] = {
53 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
54 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
55 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
56 '%','s','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
58 static const WCHAR szUserDataComponents_fmt[] = {
59 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
60 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
61 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
62 '%','s','\\','C','o','m','p','o','n','e','n','t','s',0};
64 static const WCHAR szUserDataProd_fmt[] = {
65 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
66 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
67 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
68 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
70 static const WCHAR szUserDataProducts_fmt[] = {
71 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
72 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
73 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
74 '%','s','\\','P','r','o','d','u','c','t','s',0};
76 static const WCHAR szUserDataPatch_fmt[] = {
77 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
78 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
79 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
80 '%','s','\\','P','a','t','c','h','e','s','\\','%','s',0};
82 static const WCHAR szUserDataPatches_fmt[] = {
83 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
84 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
85 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
86 '%','s','\\','P','a','t','c','h','e','s',0};
88 static const WCHAR szUserDataProductPatches_fmt[] = {
89 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
90 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
91 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
92 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\','P','a','t','c','h','e','s',0};
94 static const WCHAR szInstallProperties_fmt[] = {
95 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
96 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
97 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
98 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
99 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
101 static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
102 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
103 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
104 'I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d','\\','%','s','\\',
105 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
107 static const WCHAR szInstaller_LocalManagedFeat_fmt[] = {
108 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
109 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
110 'I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d','\\','%','s','\\',
111 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\','%','s',0};
113 static const WCHAR szInstaller_Products[] = {
114 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
115 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
116 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
118 static const WCHAR szInstaller_Patches[] = {
119 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
120 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
121 'I','n','s','t','a','l','l','e','r','\\','P','a','t','c','h','e','s',0};
123 static const WCHAR szInstaller_LocalClassesProducts[] = {
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','\\','P','r','o','d','u','c','t','s',0};
127 static const WCHAR szInstaller_LocalClassesFeatures[] = {
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','\\','F','e','a','t','u','r','e','s',0};
131 static const WCHAR szInstaller_LocalClassesProd[] = {
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','\\','P','r','o','d','u','c','t','s','\\',0};
135 static const WCHAR szInstaller_LocalClassesFeat[] = {
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','\\','F','e','a','t','u','r','e','s','\\',0};
139 static const WCHAR szInstaller_ClassesUpgradeCode[] = {
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};
143 static const WCHAR szInstaller_ClassesUpgradeCodes[] = {
144 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
145 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s',0};
147 static const WCHAR szInstaller_Features[] = {
148 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
150 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
152 static const WCHAR szInstaller_UpgradeCodes[] = {
153 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
154 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
157 static const WCHAR szInstaller_UserUpgradeCodes[] = {
158 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
159 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
161 static const WCHAR szUninstall[] = {
162 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
164 'U','n','i','n','s','t','a','l','l','\\',0};
166 static const WCHAR szUserComponents[] = {
167 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
168 'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
170 static const WCHAR szInstaller_Components[] = {
171 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
172 'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
174 static const WCHAR szUserFeatures[] = {
175 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
176 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
178 static const WCHAR szUserProducts[] = {
179 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
180 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s','\\',0};
182 static const WCHAR szUserPatches[] = {
183 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
184 'I','n','s','t','a','l','l','e','r','\\','P','a','t','c','h','e','s','\\',0};
186 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
188 DWORD i,n=0;
190 if (lstrlenW(in) != 32)
191 return FALSE;
193 out[n++]='{';
194 for(i=0; i<8; i++)
195 out[n++] = in[7-i];
196 out[n++]='-';
197 for(i=0; i<4; i++)
198 out[n++] = in[11-i];
199 out[n++]='-';
200 for(i=0; i<4; i++)
201 out[n++] = in[15-i];
202 out[n++]='-';
203 for(i=0; i<2; i++)
205 out[n++] = in[17+i*2];
206 out[n++] = in[16+i*2];
208 out[n++]='-';
209 for( ; i<8; i++)
211 out[n++] = in[17+i*2];
212 out[n++] = in[16+i*2];
214 out[n++]='}';
215 out[n]=0;
216 return TRUE;
219 BOOL squash_guid(LPCWSTR in, LPWSTR out)
221 DWORD i,n=1;
222 GUID guid;
224 out[0] = 0;
226 if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
227 return FALSE;
229 for(i=0; i<8; i++)
230 out[7-i] = in[n++];
231 n++;
232 for(i=0; i<4; i++)
233 out[11-i] = in[n++];
234 n++;
235 for(i=0; i<4; i++)
236 out[15-i] = in[n++];
237 n++;
238 for(i=0; i<2; i++)
240 out[17+i*2] = in[n++];
241 out[16+i*2] = in[n++];
243 n++;
244 for( ; i<8; i++)
246 out[17+i*2] = in[n++];
247 out[16+i*2] = in[n++];
249 out[32]=0;
250 return TRUE;
254 /* tables for encoding and decoding base85 */
255 static const unsigned char table_dec85[0x80] = {
256 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
257 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
258 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
259 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
260 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
261 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
262 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
263 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
266 static const char table_enc85[] =
267 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
268 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
269 "yz{}~";
272 * Converts a base85 encoded guid into a GUID pointer
273 * Base85 encoded GUIDs should be 20 characters long.
275 * returns TRUE if successful, FALSE if not
277 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
279 DWORD i, val = 0, base = 1, *p;
281 if (!str)
282 return FALSE;
284 p = (DWORD*) guid;
285 for( i=0; i<20; i++ )
287 if( (i%5) == 0 )
289 val = 0;
290 base = 1;
292 val += table_dec85[str[i]] * base;
293 if( str[i] >= 0x80 )
294 return FALSE;
295 if( table_dec85[str[i]] == 0xff )
296 return FALSE;
297 if( (i%5) == 4 )
298 p[i/5] = val;
299 base *= 85;
301 return TRUE;
305 * Encodes a base85 guid given a GUID pointer
306 * Caller should provide a 21 character buffer for the encoded string.
308 * returns TRUE if successful, FALSE if not
310 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
312 unsigned int x, *p, i;
314 p = (unsigned int*) guid;
315 for( i=0; i<4; i++ )
317 x = p[i];
318 *str++ = table_enc85[x%85];
319 x = x/85;
320 *str++ = table_enc85[x%85];
321 x = x/85;
322 *str++ = table_enc85[x%85];
323 x = x/85;
324 *str++ = table_enc85[x%85];
325 x = x/85;
326 *str++ = table_enc85[x%85];
328 *str = 0;
330 return TRUE;
333 DWORD msi_version_str_to_dword(LPCWSTR p)
335 DWORD major, minor = 0, build = 0, version = 0;
337 if (!p)
338 return version;
340 major = wcstol(p, NULL, 10);
342 p = wcschr(p, '.');
343 if (p)
345 minor = wcstol(p+1, NULL, 10);
346 p = wcschr(p+1, '.');
347 if (p)
348 build = wcstol(p+1, NULL, 10);
351 return MAKELONG(build, MAKEWORD(minor, major));
354 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
356 DWORD len;
357 if (!value) value = szEmpty;
358 len = (lstrlenW(value) + 1) * sizeof (WCHAR);
359 return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
362 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
364 LPCWSTR p = value;
365 while (*p) p += lstrlenW(p) + 1;
366 return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
367 (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
370 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
372 return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
375 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
377 HKEY hsubkey = 0;
378 LONG r;
380 r = RegCreateKeyW( hkey, path, &hsubkey );
381 if (r != ERROR_SUCCESS)
382 return r;
383 r = msi_reg_set_val_str( hsubkey, name, val );
384 RegCloseKey( hsubkey );
385 return r;
388 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
390 DWORD len = 0;
391 LPWSTR val;
392 LONG r;
394 r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
395 if (r != ERROR_SUCCESS)
396 return NULL;
398 len += sizeof (WCHAR);
399 val = msi_alloc( len );
400 if (!val)
401 return NULL;
402 val[0] = 0;
403 RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
404 return val;
407 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
409 DWORD type, len = sizeof (DWORD);
410 LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
411 return r == ERROR_SUCCESS && type == REG_DWORD;
414 static WCHAR *get_user_sid(void)
416 HANDLE token;
417 DWORD size = 256;
418 TOKEN_USER *user;
419 WCHAR *ret;
421 if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL;
422 if (!(user = msi_alloc( size )))
424 CloseHandle( token );
425 return NULL;
427 if (!GetTokenInformation( token, TokenUser, user, size, &size ))
429 msi_free( user );
430 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = msi_alloc( size )))
432 CloseHandle( token );
433 return NULL;
435 GetTokenInformation( token, TokenUser, user, size, &size );
437 CloseHandle( token );
438 if (!ConvertSidToStringSidW( user->User.Sid, &ret ))
440 msi_free( user );
441 return NULL;
443 msi_free( user );
444 return ret;
447 UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create)
449 REGSAM access = KEY_ALL_ACCESS;
450 WCHAR keypath[0x200];
452 TRACE("%s\n", debugstr_w(product));
454 if (platform == PLATFORM_INTEL)
455 access |= KEY_WOW64_32KEY;
456 else
457 access |= KEY_WOW64_64KEY;
458 lstrcpyW(keypath, szUninstall);
459 lstrcatW(keypath, product);
460 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
461 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
464 UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
466 REGSAM access = KEY_ALL_ACCESS;
467 HKEY parent;
468 LONG r;
470 TRACE("%s\n", debugstr_w(product));
472 if (platform == PLATFORM_INTEL)
473 access |= KEY_WOW64_32KEY;
474 else
475 access |= KEY_WOW64_64KEY;
476 if ((r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szUninstall, 0, access, &parent)))
477 return r;
478 r = RegDeleteTreeW(parent, product);
479 RegCloseKey(parent);
480 return r;
483 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
485 HKEY root = HKEY_LOCAL_MACHINE;
486 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
487 WCHAR *usersid = NULL, squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH];
489 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
490 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
492 if (context == MSIINSTALLCONTEXT_MACHINE)
494 lstrcpyW(keypath, szInstaller_LocalClassesProd);
495 lstrcatW( keypath, squashed_pc );
497 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
499 root = HKEY_CURRENT_USER;
500 lstrcpyW(keypath, szUserProducts);
501 lstrcatW( keypath, squashed_pc );
503 else
505 if (!szUserSid)
507 if (!(usersid = get_user_sid()))
509 ERR("Failed to retrieve user SID\n");
510 return ERROR_FUNCTION_FAILED;
512 szUserSid = usersid;
514 swprintf( keypath, ARRAY_SIZE(keypath), szInstaller_LocalManagedProd_fmt, szUserSid, squashed_pc );
515 LocalFree(usersid);
517 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
518 return RegOpenKeyExW(root, keypath, 0, access, key);
521 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
523 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
525 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
526 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
528 lstrcpyW(keypath, szUserProducts);
529 lstrcatW( keypath, squashed_pc );
530 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
533 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
535 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
537 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
538 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
540 lstrcpyW(keypath, szUserPatches);
541 lstrcatW( keypath, squashed_pc );
543 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
544 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
547 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
548 HKEY *key, BOOL create)
550 HKEY root = HKEY_LOCAL_MACHINE;
551 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
552 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH], *usersid = NULL;
554 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
555 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
557 if (context == MSIINSTALLCONTEXT_MACHINE)
559 lstrcpyW(keypath, szInstaller_LocalClassesFeat);
560 lstrcatW( keypath, squashed_pc );
562 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
564 root = HKEY_CURRENT_USER;
565 lstrcpyW(keypath, szUserFeatures);
566 lstrcatW( keypath, squashed_pc );
568 else
570 if (!szUserSid)
572 if (!(usersid = get_user_sid()))
574 ERR("Failed to retrieve user SID\n");
575 return ERROR_FUNCTION_FAILED;
577 szUserSid = usersid;
579 swprintf( keypath, ARRAY_SIZE(keypath), szInstaller_LocalManagedFeat_fmt, szUserSid, squashed_pc );
580 LocalFree(usersid);
582 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
583 return RegOpenKeyExW(root, keypath, 0, access, key);
586 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
588 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
590 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
591 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
593 lstrcpyW(keypath, szUserFeatures);
594 lstrcatW( keypath, squashed_pc );
595 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
598 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
600 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
601 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
603 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
604 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
606 lstrcpyW(keypath, szInstaller_Features);
607 lstrcatW( keypath, squashed_pc );
609 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
610 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
613 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
614 HKEY *key, BOOL create)
616 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
617 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200], *usersid = NULL;
619 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
620 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
622 if (context == MSIINSTALLCONTEXT_MACHINE)
624 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataFeatures_fmt, szLocalSid, squashed_pc );
626 else
628 if (!szUserSid)
630 if (!(usersid = get_user_sid()))
632 ERR("Failed to retrieve user SID\n");
633 return ERROR_FUNCTION_FAILED;
635 szUserSid = usersid;
637 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataFeatures_fmt, szUserSid, squashed_pc );
638 LocalFree(usersid);
640 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
641 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
644 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
646 WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200];
647 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
648 UINT ret;
650 if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED;
651 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc));
653 lstrcpyW(keypath, szUserComponents);
654 lstrcatW( keypath, squashed_cc );
656 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
657 ret = RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
658 if (ret != ERROR_FILE_NOT_FOUND) return ret;
660 lstrcpyW(keypath, szInstaller_Components);
661 lstrcatW( keypath, squashed_cc );
662 return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key );
665 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
667 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
668 WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
670 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
671 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
673 if (!szUserSid)
675 if (!(usersid = get_user_sid()))
677 ERR("Failed to retrieve user SID\n");
678 return ERROR_FUNCTION_FAILED;
680 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataComp_fmt, usersid, squashed_comp );
681 LocalFree(usersid);
683 else
684 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataComp_fmt, szUserSid, squashed_comp );
686 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
687 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
690 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
692 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
693 WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
694 HKEY hkey;
695 LONG r;
697 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
698 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
700 if (!szUserSid)
702 if (!(usersid = get_user_sid()))
704 ERR("Failed to retrieve user SID\n");
705 return ERROR_FUNCTION_FAILED;
707 swprintf(keypath, ARRAY_SIZE(keypath), szUserDataComponents_fmt, usersid);
708 LocalFree(usersid);
710 else
711 swprintf(keypath, ARRAY_SIZE(keypath), szUserDataComponents_fmt, szUserSid);
713 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
714 r = RegDeleteTreeW( hkey, squashed_comp );
715 RegCloseKey(hkey);
716 return r;
719 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
721 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
722 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
724 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
725 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
727 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
728 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataProd_fmt, szLocalSid, squashed_pc );
729 else if (szUserSid)
730 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataProd_fmt, szUserSid, squashed_pc );
731 else
733 if (!(usersid = get_user_sid()))
735 ERR("Failed to retrieve user SID\n");
736 return ERROR_FUNCTION_FAILED;
738 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataProd_fmt, usersid, squashed_pc );
739 LocalFree(usersid);
741 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
742 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
745 UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create)
747 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
748 WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
750 if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED;
751 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch));
753 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
754 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataPatch_fmt, szLocalSid, squashed_patch );
755 else
757 if (!(usersid = get_user_sid()))
759 ERR("Failed to retrieve user SID\n");
760 return ERROR_FUNCTION_FAILED;
762 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataPatch_fmt, usersid, squashed_patch );
763 LocalFree(usersid);
765 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
766 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
769 UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
771 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
772 WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
773 HKEY hkey;
774 LONG r;
776 if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED;
777 TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch));
779 if (context == MSIINSTALLCONTEXT_MACHINE)
780 swprintf(keypath, ARRAY_SIZE(keypath), szUserDataPatches_fmt, szLocalSid);
781 else
783 if (!(usersid = get_user_sid()))
785 ERR("Failed to retrieve user SID\n");
786 return ERROR_FUNCTION_FAILED;
788 swprintf(keypath, ARRAY_SIZE(keypath), szUserDataPatches_fmt, usersid);
789 LocalFree(usersid);
791 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
792 r = RegDeleteTreeW( hkey, squashed_patch );
793 RegCloseKey(hkey);
794 return r;
797 UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
799 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
800 WCHAR *usersid, squashed_product[SQUASHED_GUID_SIZE], keypath[0x200];
802 if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED;
803 TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product));
805 if (context == MSIINSTALLCONTEXT_MACHINE)
806 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataProductPatches_fmt, szLocalSid, squashed_product );
807 else
809 if (!(usersid = get_user_sid()))
811 ERR("Failed to retrieve user SID\n");
812 return ERROR_FUNCTION_FAILED;
814 swprintf( keypath, ARRAY_SIZE(keypath), szUserDataProductPatches_fmt, usersid, squashed_product );
815 LocalFree(usersid);
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);
821 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
823 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
824 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
826 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
827 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
829 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
830 swprintf( keypath, ARRAY_SIZE(keypath), szInstallProperties_fmt, szLocalSid, squashed_pc );
831 else if (szUserSid)
832 swprintf( keypath, ARRAY_SIZE(keypath), szInstallProperties_fmt, szUserSid, squashed_pc );
833 else
835 if (!(usersid = get_user_sid()))
837 ERR("Failed to retrieve user SID\n");
838 return ERROR_FUNCTION_FAILED;
840 swprintf( keypath, ARRAY_SIZE(keypath), szInstallProperties_fmt, usersid, squashed_pc );
841 LocalFree(usersid);
843 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
844 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
847 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context)
849 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
850 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
851 HKEY hkey;
852 LONG r;
854 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
855 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
857 if (context == MSIINSTALLCONTEXT_MACHINE)
858 swprintf(keypath, ARRAY_SIZE(keypath), szUserDataProducts_fmt, szLocalSid);
859 else
861 if (!(usersid = get_user_sid()))
863 ERR("Failed to retrieve user SID\n");
864 return ERROR_FUNCTION_FAILED;
866 swprintf(keypath, ARRAY_SIZE(keypath), szUserDataProducts_fmt, usersid);
867 LocalFree(usersid);
870 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
871 r = RegDeleteTreeW( hkey, squashed_pc );
872 RegCloseKey(hkey);
873 return r;
876 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
878 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
879 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
880 HKEY hkey;
881 LONG r;
883 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
884 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
886 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_Products, 0, access, &hkey)) return ERROR_SUCCESS;
887 r = RegDeleteTreeW( hkey, squashed_pc );
888 RegCloseKey(hkey);
889 return r;
892 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
894 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
895 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
897 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
898 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
900 swprintf( keypath, ARRAY_SIZE(keypath), szInstaller_Patches, squashed_pc );
902 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
903 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
906 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
908 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
909 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
911 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
912 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
914 lstrcpyW(keypath, szInstaller_UpgradeCodes);
915 lstrcatW( keypath, squashed_uc );
917 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
918 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
921 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
923 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
925 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
926 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
928 lstrcpyW(keypath, szInstaller_UserUpgradeCodes);
929 lstrcatW( keypath, squashed_uc );
931 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
932 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
935 UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code )
937 WCHAR squashed_code[SQUASHED_GUID_SIZE];
938 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
939 HKEY hkey;
940 LONG ret;
942 if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED;
943 TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) );
945 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, szInstaller_UpgradeCodes, 0, access, &hkey )) return ERROR_SUCCESS;
946 ret = RegDeleteTreeW( hkey, squashed_code );
947 RegCloseKey( hkey );
948 return ret;
951 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
953 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
955 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
956 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
958 lstrcpyW(keypath, szInstaller_UserUpgradeCodes);
959 lstrcatW( keypath, squashed_uc );
960 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
963 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
965 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
966 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
967 HKEY hkey;
968 LONG r;
970 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
971 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
973 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProducts, 0, access, &hkey)) return ERROR_SUCCESS;
974 r = RegDeleteTreeW( hkey, squashed_pc );
975 RegCloseKey(hkey);
976 return r;
979 UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
981 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
982 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
983 HKEY hkey;
984 LONG r;
986 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
987 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
989 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesFeatures, 0, access, &hkey)) return ERROR_SUCCESS;
990 r = RegDeleteTreeW( hkey, squashed_pc );
991 RegCloseKey(hkey);
992 return r;
995 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
997 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
998 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
1000 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
1001 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
1003 lstrcpyW(keypath, szInstaller_ClassesUpgradeCode);
1004 lstrcatW( keypath, squashed_uc );
1006 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
1007 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
1010 UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
1012 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
1013 WCHAR squashed_uc[SQUASHED_GUID_SIZE];
1014 HKEY hkey;
1015 LONG r;
1017 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
1018 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
1020 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_ClassesUpgradeCodes, 0, access, &hkey)) return ERROR_SUCCESS;
1021 r = RegDeleteTreeW( hkey, squashed_uc );
1022 RegCloseKey(hkey);
1023 return r;
1026 /*************************************************************************
1027 * MsiDecomposeDescriptorW [MSI.@]
1029 * Decomposes an MSI descriptor into product, feature and component parts.
1030 * An MSI descriptor is a string of the form:
1031 * [base 85 guid] [feature code] '>' [base 85 guid] or
1032 * [base 85 guid] [feature code] '<'
1034 * PARAMS
1035 * szDescriptor [I] the descriptor to decompose
1036 * szProduct [O] buffer of MAX_FEATURE_CHARS+1 for the product guid
1037 * szFeature [O] buffer of MAX_FEATURE_CHARS+1 for the feature code
1038 * szComponent [O] buffer of MAX_FEATURE_CHARS+1 for the component guid
1039 * pUsed [O] the length of the descriptor
1041 * RETURNS
1042 * ERROR_SUCCESS if everything worked correctly
1043 * ERROR_INVALID_PARAMETER if the descriptor was invalid
1046 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1047 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1049 UINT len;
1050 const WCHAR *p;
1051 GUID product, component;
1053 TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1054 szFeature, szComponent, pUsed);
1056 if (!decode_base85_guid( szDescriptor, &product ))
1057 return ERROR_INVALID_PARAMETER;
1059 TRACE("product %s\n", debugstr_guid( &product ));
1061 if (!(p = wcschr( &szDescriptor[20], '>' )))
1062 p = wcschr( &szDescriptor[20], '<' );
1063 if (!p)
1064 return ERROR_INVALID_PARAMETER;
1066 len = (p - &szDescriptor[20]);
1067 if( len > MAX_FEATURE_CHARS )
1068 return ERROR_INVALID_PARAMETER;
1070 TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1072 if (*p == '>')
1074 if (!decode_base85_guid( p+1, &component ))
1075 return ERROR_INVALID_PARAMETER;
1076 TRACE( "component %s\n", debugstr_guid(&component) );
1079 if (szProduct)
1080 StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1081 if (szComponent)
1083 if (*p == '>')
1084 StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1085 else
1086 szComponent[0] = 0;
1088 if (szFeature)
1090 memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1091 szFeature[len] = 0;
1094 len = p - szDescriptor + 1;
1095 if (*p == '>') len += 20;
1097 TRACE("length = %d\n", len);
1098 if (pUsed) *pUsed = len;
1100 return ERROR_SUCCESS;
1103 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1104 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1106 WCHAR product[MAX_FEATURE_CHARS+1];
1107 WCHAR feature[MAX_FEATURE_CHARS+1];
1108 WCHAR component[MAX_FEATURE_CHARS+1];
1109 LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1110 UINT r;
1112 TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1113 szFeature, szComponent, pUsed);
1115 str = strdupAtoW( szDescriptor );
1116 if( szDescriptor && !str )
1117 return ERROR_OUTOFMEMORY;
1119 if (szProduct)
1120 p = product;
1121 if (szFeature)
1122 f = feature;
1123 if (szComponent)
1124 c = component;
1126 r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1128 if (r == ERROR_SUCCESS)
1130 WideCharToMultiByte( CP_ACP, 0, p, -1,
1131 szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1132 WideCharToMultiByte( CP_ACP, 0, f, -1,
1133 szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1134 WideCharToMultiByte( CP_ACP, 0, c, -1,
1135 szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1138 msi_free( str );
1140 return r;
1143 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1145 DWORD r;
1146 WCHAR szwGuid[GUID_SIZE];
1148 TRACE("%d %p\n", index, lpguid);
1150 if (NULL == lpguid)
1151 return ERROR_INVALID_PARAMETER;
1152 r = MsiEnumProductsW(index, szwGuid);
1153 if( r == ERROR_SUCCESS )
1154 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1156 return r;
1159 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1161 TRACE("%d %p\n", index, lpguid);
1163 if (NULL == lpguid)
1164 return ERROR_INVALID_PARAMETER;
1166 return MsiEnumProductsExW( NULL, szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid,
1167 NULL, NULL, NULL );
1170 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
1171 LPSTR szFeature, LPSTR szParent)
1173 DWORD r;
1174 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1175 LPWSTR szwProduct = NULL;
1177 TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1179 if( szProduct )
1181 szwProduct = strdupAtoW( szProduct );
1182 if( !szwProduct )
1183 return ERROR_OUTOFMEMORY;
1186 r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1187 if( r == ERROR_SUCCESS )
1189 WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1190 szFeature, GUID_SIZE, NULL, NULL);
1191 WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1192 szParent, GUID_SIZE, NULL, NULL);
1195 msi_free( szwProduct);
1197 return r;
1200 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
1201 LPWSTR szFeature, LPWSTR szParent)
1203 HKEY hkeyProduct = 0;
1204 DWORD r, sz;
1206 TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1208 if( !szProduct )
1209 return ERROR_INVALID_PARAMETER;
1211 r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1212 if( r != ERROR_SUCCESS )
1213 return ERROR_NO_MORE_ITEMS;
1215 sz = GUID_SIZE;
1216 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1217 RegCloseKey(hkeyProduct);
1219 return r;
1222 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1224 DWORD r;
1225 WCHAR szwGuid[GUID_SIZE];
1227 TRACE("%u, %p\n", index, lpguid);
1229 if (!lpguid) return ERROR_INVALID_PARAMETER;
1231 r = MsiEnumComponentsW(index, szwGuid);
1232 if( r == ERROR_SUCCESS )
1233 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1235 return r;
1238 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1240 TRACE("%u, %p\n", index, lpguid);
1242 if (!lpguid) return ERROR_INVALID_PARAMETER;
1244 return MsiEnumComponentsExW( szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
1247 UINT WINAPI MsiEnumComponentsExA( LPCSTR user_sid, DWORD ctx, DWORD index, CHAR guid[39],
1248 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
1250 UINT r;
1251 WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
1253 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
1254 sid, sid_len);
1256 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
1257 if (user_sid && !(user_sidW = strdupAtoW( user_sid ))) return ERROR_OUTOFMEMORY;
1258 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
1260 msi_free( user_sidW );
1261 return ERROR_OUTOFMEMORY;
1263 r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
1264 if (r == ERROR_SUCCESS)
1266 if (guid) WideCharToMultiByte( CP_ACP, 0, guidW, GUID_SIZE, guid, GUID_SIZE, NULL, NULL );
1267 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
1269 msi_free( user_sidW );
1270 msi_free( sidW );
1271 return r;
1274 static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1275 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1277 static const WCHAR componentsW[] =
1278 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1279 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1280 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
1281 'S','-','1','-','5','-','1','8','\\','C','o','m','p','o','n','e','n','t','s',0};
1282 UINT r = ERROR_SUCCESS;
1283 WCHAR component[SQUASHED_GUID_SIZE];
1284 DWORD i = 0, len_component;
1285 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1286 HKEY key_components;
1288 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, componentsW, 0, access, &key_components ))
1289 return ERROR_NO_MORE_ITEMS;
1291 len_component = ARRAY_SIZE( component );
1292 while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
1294 if (*idx == index) goto found;
1295 (*idx)++;
1296 len_component = ARRAY_SIZE( component );
1297 i++;
1299 RegCloseKey( key_components );
1300 return ERROR_NO_MORE_ITEMS;
1302 found:
1303 if (sid_len)
1305 if (*sid_len < 1)
1307 *sid_len = 1;
1308 r = ERROR_MORE_DATA;
1310 else if (sid)
1312 *sid_len = 0;
1313 sid[0] = 0;
1316 if (guid) unsquash_guid( component, guid );
1317 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
1318 RegCloseKey( key_components );
1319 return r;
1322 static UINT fetch_user_component( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx,
1323 WCHAR guid[39], MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid,
1324 LPDWORD sid_len )
1326 static const WCHAR userdataW[] =
1327 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1328 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1329 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a',0};
1330 static const WCHAR componentsW[] = {'\\','C','o','m','p','o','n','e','n','t','s',0};
1331 UINT r = ERROR_SUCCESS;
1332 WCHAR path[MAX_PATH], component[SQUASHED_GUID_SIZE], user[128];
1333 DWORD i = 0, j = 0, len_component, len_user;
1334 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1335 HKEY key_users, key_components;
1337 if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
1338 return ERROR_NO_MORE_ITEMS;
1340 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, userdataW, 0, access, &key_users ))
1341 return ERROR_NO_MORE_ITEMS;
1343 len_user = ARRAY_SIZE( user );
1344 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
1346 if ((wcscmp( usersid, szAllSid ) && wcscmp( usersid, user )) ||
1347 !wcscmp( szLocalSid, user ))
1349 i++;
1350 len_user = ARRAY_SIZE( user );
1351 continue;
1353 lstrcpyW( path, user );
1354 lstrcatW( path, componentsW );
1355 if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
1357 i++;
1358 len_user = ARRAY_SIZE( user );
1359 continue;
1361 len_component = ARRAY_SIZE( component );
1362 while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
1364 if (*idx == index) goto found;
1365 (*idx)++;
1366 len_component = ARRAY_SIZE( component );
1367 j++;
1369 RegCloseKey( key_components );
1370 len_user = ARRAY_SIZE( user );
1371 i++;
1373 RegCloseKey( key_users );
1374 return ERROR_NO_MORE_ITEMS;
1376 found:
1377 if (sid_len)
1379 if (*sid_len < len_user + 1)
1381 *sid_len = len_user + 1;
1382 r = ERROR_MORE_DATA;
1384 else if (sid)
1386 *sid_len = len_user;
1387 lstrcpyW( sid, user );
1390 if (guid) unsquash_guid( component, guid );
1391 if (installed_ctx) *installed_ctx = ctx;
1392 RegCloseKey( key_components );
1393 RegCloseKey( key_users );
1394 return r;
1397 static UINT enum_components( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1398 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1400 UINT r = ERROR_NO_MORE_ITEMS;
1401 WCHAR *user = NULL;
1403 if (!usersid)
1405 usersid = user = get_user_sid();
1406 if (!user) return ERROR_FUNCTION_FAILED;
1408 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
1410 r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERMANAGED, index, idx, guid,
1411 installed_ctx, sid, sid_len );
1412 if (r != ERROR_NO_MORE_ITEMS) goto done;
1414 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
1416 r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index, idx, guid,
1417 installed_ctx, sid, sid_len );
1418 if (r != ERROR_NO_MORE_ITEMS) goto done;
1420 if (ctx & MSIINSTALLCONTEXT_MACHINE)
1422 r = fetch_machine_component( MSIINSTALLCONTEXT_MACHINE, index, idx, guid, installed_ctx,
1423 sid, sid_len );
1424 if (r != ERROR_NO_MORE_ITEMS) goto done;
1427 done:
1428 LocalFree( user );
1429 return r;
1432 UINT WINAPI MsiEnumComponentsExW( LPCWSTR user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
1433 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1435 UINT r;
1436 DWORD idx = 0;
1437 static DWORD last_index;
1439 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
1440 sid, sid_len);
1442 if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
1443 return ERROR_INVALID_PARAMETER;
1445 if (index && index - last_index != 1)
1446 return ERROR_INVALID_PARAMETER;
1448 if (!index) last_index = 0;
1450 r = enum_components( user_sid, ctx, index, &idx, guid, installed_ctx, sid, sid_len );
1451 if (r == ERROR_SUCCESS)
1452 last_index = index;
1453 else
1454 last_index = 0;
1456 return r;
1459 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1461 DWORD r;
1462 WCHAR szwProduct[GUID_SIZE];
1463 LPWSTR szwComponent = NULL;
1465 TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1467 if ( !szProduct )
1468 return ERROR_INVALID_PARAMETER;
1470 if( szComponent )
1472 szwComponent = strdupAtoW( szComponent );
1473 if( !szwComponent )
1474 return ERROR_OUTOFMEMORY;
1477 r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1478 if( r == ERROR_SUCCESS )
1480 WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1481 szProduct, GUID_SIZE, NULL, NULL);
1484 msi_free( szwComponent);
1486 return r;
1489 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1491 HKEY hkeyComp = 0;
1492 DWORD r, sz;
1493 WCHAR szValName[SQUASHED_GUID_SIZE];
1495 TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1497 if (!szComponent || !*szComponent || !szProduct)
1498 return ERROR_INVALID_PARAMETER;
1500 if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1501 MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkeyComp, FALSE) != ERROR_SUCCESS)
1502 return ERROR_UNKNOWN_COMPONENT;
1504 /* see if there are any products at all */
1505 sz = SQUASHED_GUID_SIZE;
1506 r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1507 if (r != ERROR_SUCCESS)
1509 RegCloseKey(hkeyComp);
1511 if (index != 0)
1512 return ERROR_INVALID_PARAMETER;
1514 return ERROR_UNKNOWN_COMPONENT;
1517 sz = SQUASHED_GUID_SIZE;
1518 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1519 if( r == ERROR_SUCCESS )
1521 unsquash_guid(szValName, szProduct);
1522 TRACE("-> %s\n", debugstr_w(szProduct));
1524 RegCloseKey(hkeyComp);
1525 return r;
1528 UINT WINAPI MsiEnumClientsExA(LPCSTR component, LPCSTR usersid, DWORD ctx, DWORD index,
1529 CHAR installed_product[GUID_SIZE],
1530 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len)
1532 FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid),
1533 ctx, index, installed_product, installed_ctx, sid, sid_len);
1534 return ERROR_ACCESS_DENIED;
1537 UINT WINAPI MsiEnumClientsExW(LPCWSTR component, LPCWSTR usersid, DWORD ctx, DWORD index,
1538 WCHAR installed_product[GUID_SIZE],
1539 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len)
1541 FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid),
1542 ctx, index, installed_product, installed_ctx, sid, sid_len);
1543 return ERROR_ACCESS_DENIED;
1546 static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1547 awstring *lpQualBuf, LPDWORD pcchQual,
1548 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1550 DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1551 LPWSTR name = NULL, val = NULL;
1552 UINT r, r2;
1553 HKEY key;
1555 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1556 lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1558 if (!szComponent)
1559 return ERROR_INVALID_PARAMETER;
1561 r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1562 if (r != ERROR_SUCCESS)
1563 return ERROR_UNKNOWN_COMPONENT;
1565 /* figure out how big the name is we want to return */
1566 name_max = 0x10;
1567 r = ERROR_OUTOFMEMORY;
1568 name = msi_alloc( name_max * sizeof(WCHAR) );
1569 if (!name)
1570 goto end;
1572 val_max = 0x10;
1573 r = ERROR_OUTOFMEMORY;
1574 val = msi_alloc( val_max );
1575 if (!val)
1576 goto end;
1578 /* loop until we allocate enough memory */
1579 while (1)
1581 name_sz = name_max;
1582 val_sz = val_max;
1583 r = RegEnumValueW( key, iIndex, name, &name_sz,
1584 NULL, &type, (LPBYTE)val, &val_sz );
1585 if (r == ERROR_SUCCESS)
1586 break;
1587 if (r != ERROR_MORE_DATA)
1588 goto end;
1590 if (type != REG_MULTI_SZ)
1592 ERR("component data has wrong type (%d)\n", type);
1593 goto end;
1596 r = ERROR_OUTOFMEMORY;
1597 if (name_sz + 1 >= name_max)
1599 name_max *= 2;
1600 msi_free( name );
1601 name = msi_alloc( name_max * sizeof (WCHAR) );
1602 if (!name)
1603 goto end;
1604 continue;
1606 if (val_sz > val_max)
1608 val_max = val_sz + sizeof (WCHAR);
1609 msi_free( val );
1610 val = msi_alloc( val_max * sizeof (WCHAR) );
1611 if (!val)
1612 goto end;
1613 continue;
1615 ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1616 goto end;
1619 ofs = 0;
1620 r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1621 if (r != ERROR_SUCCESS)
1622 goto end;
1624 TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1626 r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
1627 r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
1629 if (r2 != ERROR_SUCCESS)
1630 r = r2;
1632 end:
1633 msi_free(val);
1634 msi_free(name);
1635 RegCloseKey(key);
1636 return r;
1639 /*************************************************************************
1640 * MsiEnumComponentQualifiersA [MSI.@]
1642 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1643 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1644 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1646 awstring qual, appdata;
1647 LPWSTR comp;
1648 UINT r;
1650 TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1651 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1652 pcchApplicationDataBuf);
1654 comp = strdupAtoW( szComponent );
1655 if (szComponent && !comp)
1656 return ERROR_OUTOFMEMORY;
1658 qual.unicode = FALSE;
1659 qual.str.a = lpQualifierBuf;
1661 appdata.unicode = FALSE;
1662 appdata.str.a = lpApplicationDataBuf;
1664 r = MSI_EnumComponentQualifiers( comp, iIndex,
1665 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1666 msi_free( comp );
1667 return r;
1670 /*************************************************************************
1671 * MsiEnumComponentQualifiersW [MSI.@]
1673 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1674 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1675 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1677 awstring qual, appdata;
1679 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1680 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1681 pcchApplicationDataBuf);
1683 qual.unicode = TRUE;
1684 qual.str.w = lpQualifierBuf;
1686 appdata.unicode = TRUE;
1687 appdata.str.w = lpApplicationDataBuf;
1689 return MSI_EnumComponentQualifiers( szComponent, iIndex,
1690 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1693 /*************************************************************************
1694 * MsiEnumRelatedProductsW [MSI.@]
1697 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1698 DWORD iProductIndex, LPWSTR lpProductBuf)
1700 UINT r;
1701 HKEY hkey;
1702 WCHAR szKeyName[SQUASHED_GUID_SIZE];
1703 DWORD dwSize = ARRAY_SIZE(szKeyName);
1705 TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1706 iProductIndex, lpProductBuf);
1708 if (NULL == szUpgradeCode)
1709 return ERROR_INVALID_PARAMETER;
1710 if (NULL == lpProductBuf)
1711 return ERROR_INVALID_PARAMETER;
1713 r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1714 if (r != ERROR_SUCCESS)
1715 return ERROR_NO_MORE_ITEMS;
1717 r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1718 if( r == ERROR_SUCCESS )
1719 unsquash_guid(szKeyName, lpProductBuf);
1720 RegCloseKey(hkey);
1722 return r;
1725 /*************************************************************************
1726 * MsiEnumRelatedProductsA [MSI.@]
1729 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1730 DWORD iProductIndex, LPSTR lpProductBuf)
1732 LPWSTR szwUpgradeCode = NULL;
1733 WCHAR productW[GUID_SIZE];
1734 UINT r;
1736 TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1737 iProductIndex, lpProductBuf);
1739 if (szUpgradeCode)
1741 szwUpgradeCode = strdupAtoW( szUpgradeCode );
1742 if( !szwUpgradeCode )
1743 return ERROR_OUTOFMEMORY;
1746 r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1747 iProductIndex, productW );
1748 if (r == ERROR_SUCCESS)
1750 WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1751 lpProductBuf, GUID_SIZE, NULL, NULL );
1753 msi_free( szwUpgradeCode);
1754 return r;
1757 /***********************************************************************
1758 * MsiEnumPatchesExA [MSI.@]
1760 UINT WINAPI MsiEnumPatchesExA(LPCSTR szProductCode, LPCSTR szUserSid,
1761 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPSTR szPatchCode,
1762 LPSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
1763 LPSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
1765 LPWSTR prodcode = NULL;
1766 LPWSTR usersid = NULL;
1767 LPWSTR targsid = NULL;
1768 WCHAR patch[GUID_SIZE];
1769 WCHAR targprod[GUID_SIZE];
1770 DWORD len;
1771 UINT r;
1773 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
1774 debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, dwFilter,
1775 dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
1776 szTargetUserSid, pcchTargetUserSid);
1778 if (szTargetUserSid && !pcchTargetUserSid)
1779 return ERROR_INVALID_PARAMETER;
1781 if (szProductCode) prodcode = strdupAtoW(szProductCode);
1782 if (szUserSid) usersid = strdupAtoW(szUserSid);
1784 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1785 patch, targprod, pdwTargetProductContext,
1786 NULL, &len);
1787 if (r != ERROR_SUCCESS)
1788 goto done;
1790 WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1791 GUID_SIZE, NULL, NULL);
1792 WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1793 GUID_SIZE, NULL, NULL);
1795 if (!szTargetUserSid)
1797 if (pcchTargetUserSid)
1798 *pcchTargetUserSid = len;
1800 goto done;
1803 targsid = msi_alloc(++len * sizeof(WCHAR));
1804 if (!targsid)
1806 r = ERROR_OUTOFMEMORY;
1807 goto done;
1810 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1811 patch, targprod, pdwTargetProductContext,
1812 targsid, &len);
1813 if (r != ERROR_SUCCESS || !szTargetUserSid)
1814 goto done;
1816 WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1817 *pcchTargetUserSid, NULL, NULL);
1819 len = lstrlenW(targsid);
1820 if (*pcchTargetUserSid < len + 1)
1822 r = ERROR_MORE_DATA;
1823 *pcchTargetUserSid = len * sizeof(WCHAR);
1825 else
1826 *pcchTargetUserSid = len;
1828 done:
1829 msi_free(prodcode);
1830 msi_free(usersid);
1831 msi_free(targsid);
1833 return r;
1836 static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
1837 MSIINSTALLCONTEXT context,
1838 LPWSTR patch, MSIPATCHSTATE *state)
1840 DWORD type, val, size;
1841 HKEY prod, hkey = 0;
1842 HKEY udpatch = 0;
1843 LONG res;
1844 UINT r = ERROR_NO_MORE_ITEMS;
1846 *state = MSIPATCHSTATE_INVALID;
1848 r = MSIREG_OpenUserDataProductKey(prodcode, context,
1849 usersid, &prod, FALSE);
1850 if (r != ERROR_SUCCESS)
1851 return ERROR_NO_MORE_ITEMS;
1853 res = RegOpenKeyExW(prod, szPatches, 0, KEY_READ, &hkey);
1854 if (res != ERROR_SUCCESS)
1855 goto done;
1857 res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1858 if (res != ERROR_SUCCESS)
1859 goto done;
1861 size = sizeof(DWORD);
1862 res = RegGetValueW(udpatch, NULL, szState, RRF_RT_DWORD, &type, &val, &size);
1863 if (res != ERROR_SUCCESS ||
1864 val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1866 r = ERROR_BAD_CONFIGURATION;
1867 goto done;
1870 *state = val;
1871 r = ERROR_SUCCESS;
1873 done:
1874 RegCloseKey(udpatch);
1875 RegCloseKey(hkey);
1876 RegCloseKey(prod);
1878 return r;
1881 static UINT msi_check_product_patches(LPCWSTR prodcode, LPCWSTR usersid,
1882 MSIINSTALLCONTEXT context, DWORD filter, DWORD index, DWORD *idx,
1883 LPWSTR patch, LPWSTR targetprod, MSIINSTALLCONTEXT *targetctx,
1884 LPWSTR targetsid, DWORD *sidsize, LPWSTR *transforms)
1886 MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1887 LPWSTR ptr, patches = NULL;
1888 HKEY prod, patchkey = 0;
1889 HKEY localprod = 0, localpatch = 0;
1890 DWORD type, size;
1891 LONG res;
1892 UINT temp, r = ERROR_NO_MORE_ITEMS;
1894 if (MSIREG_OpenProductKey(prodcode, usersid, context,
1895 &prod, FALSE) != ERROR_SUCCESS)
1896 return ERROR_NO_MORE_ITEMS;
1898 size = 0;
1899 res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, NULL,
1900 &size);
1901 if (res != ERROR_SUCCESS)
1902 goto done;
1904 if (type != REG_MULTI_SZ)
1906 r = ERROR_BAD_CONFIGURATION;
1907 goto done;
1910 patches = msi_alloc(size);
1911 if (!patches)
1913 r = ERROR_OUTOFMEMORY;
1914 goto done;
1917 res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type,
1918 patches, &size);
1919 if (res != ERROR_SUCCESS)
1920 goto done;
1922 for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1924 if (!unsquash_guid(ptr, patch))
1926 r = ERROR_BAD_CONFIGURATION;
1927 goto done;
1930 size = 0;
1931 res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1932 &type, NULL, &size);
1933 if (res != ERROR_SUCCESS)
1934 continue;
1936 if (transforms)
1938 *transforms = msi_alloc(size);
1939 if (!*transforms)
1941 r = ERROR_OUTOFMEMORY;
1942 goto done;
1945 res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1946 &type, *transforms, &size);
1947 if (res != ERROR_SUCCESS)
1948 continue;
1951 if (context == MSIINSTALLCONTEXT_USERMANAGED)
1953 if (!(filter & MSIPATCHSTATE_APPLIED))
1955 temp = msi_get_patch_state(prodcode, usersid, context,
1956 ptr, &state);
1957 if (temp == ERROR_BAD_CONFIGURATION)
1959 r = ERROR_BAD_CONFIGURATION;
1960 goto done;
1963 if (temp != ERROR_SUCCESS || !(filter & state))
1964 continue;
1967 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1969 if (!(filter & MSIPATCHSTATE_APPLIED))
1971 temp = msi_get_patch_state(prodcode, usersid, context,
1972 ptr, &state);
1973 if (temp == ERROR_BAD_CONFIGURATION)
1975 r = ERROR_BAD_CONFIGURATION;
1976 goto done;
1979 if (temp != ERROR_SUCCESS || !(filter & state))
1980 continue;
1982 else
1984 temp = MSIREG_OpenUserDataPatchKey(patch, context,
1985 &patchkey, FALSE);
1986 RegCloseKey(patchkey);
1987 if (temp != ERROR_SUCCESS)
1988 continue;
1991 else if (context == MSIINSTALLCONTEXT_MACHINE)
1993 usersid = szEmpty;
1995 if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
1996 RegOpenKeyExW(localprod, szPatches, 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
1997 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
1999 res = RegGetValueW(patchkey, NULL, szState, RRF_RT_REG_DWORD,
2000 &type, &state, &size);
2002 if (!(filter & state))
2003 res = ERROR_NO_MORE_ITEMS;
2005 RegCloseKey(patchkey);
2008 RegCloseKey(localpatch);
2009 RegCloseKey(localprod);
2011 if (res != ERROR_SUCCESS)
2012 continue;
2015 if (*idx < index)
2017 (*idx)++;
2018 continue;
2021 r = ERROR_SUCCESS;
2022 if (targetprod)
2023 lstrcpyW(targetprod, prodcode);
2025 if (targetctx)
2026 *targetctx = context;
2028 if (targetsid)
2030 lstrcpynW(targetsid, usersid, *sidsize);
2031 if (lstrlenW(usersid) >= *sidsize)
2032 r = ERROR_MORE_DATA;
2035 if (sidsize)
2037 *sidsize = lstrlenW(usersid);
2038 if (!targetsid)
2039 *sidsize *= sizeof(WCHAR);
2043 done:
2044 RegCloseKey(prod);
2045 msi_free(patches);
2047 return r;
2050 static UINT msi_enum_patches(LPCWSTR szProductCode, LPCWSTR szUserSid,
2051 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, DWORD *idx,
2052 LPWSTR szPatchCode, LPWSTR szTargetProductCode,
2053 MSIINSTALLCONTEXT *pdwTargetProductContext, LPWSTR szTargetUserSid,
2054 LPDWORD pcchTargetUserSid, LPWSTR *szTransforms)
2056 LPWSTR usersid = NULL;
2057 UINT r = ERROR_INVALID_PARAMETER;
2059 if (!szUserSid)
2061 szUserSid = usersid = get_user_sid();
2062 if (!usersid) return ERROR_FUNCTION_FAILED;
2065 if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
2067 r = msi_check_product_patches(szProductCode, szUserSid,
2068 MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
2069 dwIndex, idx, szPatchCode,
2070 szTargetProductCode,
2071 pdwTargetProductContext, szTargetUserSid,
2072 pcchTargetUserSid, szTransforms);
2073 if (r != ERROR_NO_MORE_ITEMS)
2074 goto done;
2077 if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
2079 r = msi_check_product_patches(szProductCode, szUserSid,
2080 MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter,
2081 dwIndex, idx, szPatchCode,
2082 szTargetProductCode,
2083 pdwTargetProductContext, szTargetUserSid,
2084 pcchTargetUserSid, szTransforms);
2085 if (r != ERROR_NO_MORE_ITEMS)
2086 goto done;
2089 if (dwContext & MSIINSTALLCONTEXT_MACHINE)
2091 r = msi_check_product_patches(szProductCode, szUserSid,
2092 MSIINSTALLCONTEXT_MACHINE, dwFilter,
2093 dwIndex, idx, szPatchCode,
2094 szTargetProductCode,
2095 pdwTargetProductContext, szTargetUserSid,
2096 pcchTargetUserSid, szTransforms);
2097 if (r != ERROR_NO_MORE_ITEMS)
2098 goto done;
2101 done:
2102 LocalFree(usersid);
2103 return r;
2106 /***********************************************************************
2107 * MsiEnumPatchesExW [MSI.@]
2109 UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
2110 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
2111 LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
2112 LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
2114 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
2115 DWORD idx = 0;
2116 UINT r;
2118 static DWORD last_index;
2120 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
2121 debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
2122 dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
2123 szTargetUserSid, pcchTargetUserSid);
2125 if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
2126 return ERROR_INVALID_PARAMETER;
2128 if (szUserSid && !wcscmp( szUserSid, szLocalSid ))
2129 return ERROR_INVALID_PARAMETER;
2131 if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
2132 return ERROR_INVALID_PARAMETER;
2134 if (dwContext <= MSIINSTALLCONTEXT_NONE ||
2135 dwContext > MSIINSTALLCONTEXT_ALL)
2136 return ERROR_INVALID_PARAMETER;
2138 if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
2139 return ERROR_INVALID_PARAMETER;
2141 if (dwIndex && dwIndex - last_index != 1)
2142 return ERROR_INVALID_PARAMETER;
2144 if (dwIndex == 0)
2145 last_index = 0;
2147 r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter,
2148 dwIndex, &idx, szPatchCode, szTargetProductCode,
2149 pdwTargetProductContext, szTargetUserSid,
2150 pcchTargetUserSid, NULL);
2152 if (r == ERROR_SUCCESS)
2153 last_index = dwIndex;
2154 else
2155 last_index = 0;
2157 return r;
2160 /***********************************************************************
2161 * MsiEnumPatchesA [MSI.@]
2163 UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex,
2164 LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2166 LPWSTR product, transforms;
2167 WCHAR patch[GUID_SIZE];
2168 DWORD len;
2169 UINT r;
2171 TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex,
2172 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2174 if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2175 return ERROR_INVALID_PARAMETER;
2177 product = strdupAtoW(szProduct);
2178 if (!product)
2179 return ERROR_OUTOFMEMORY;
2181 len = *pcchTransformsBuf;
2182 transforms = msi_alloc( len * sizeof(WCHAR) );
2183 if (!transforms)
2185 r = ERROR_OUTOFMEMORY;
2186 goto done;
2189 r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2190 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2191 goto done;
2193 WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2194 GUID_SIZE, NULL, NULL);
2196 if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2197 *pcchTransformsBuf, NULL, NULL))
2198 r = ERROR_MORE_DATA;
2200 if (r == ERROR_MORE_DATA)
2202 lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2203 *pcchTransformsBuf = len * 2;
2205 else
2206 *pcchTransformsBuf = strlen( lpTransformsBuf );
2208 done:
2209 msi_free(transforms);
2210 msi_free(product);
2212 return r;
2215 /***********************************************************************
2216 * MsiEnumPatchesW [MSI.@]
2218 UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex,
2219 LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2221 WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
2222 HKEY prod;
2223 DWORD idx = 0;
2224 UINT r;
2226 TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex,
2227 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2229 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
2230 return ERROR_INVALID_PARAMETER;
2232 if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2233 return ERROR_INVALID_PARAMETER;
2235 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2236 &prod, FALSE) != ERROR_SUCCESS &&
2237 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2238 &prod, FALSE) != ERROR_SUCCESS &&
2239 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2240 &prod, FALSE) != ERROR_SUCCESS)
2241 return ERROR_UNKNOWN_PRODUCT;
2243 RegCloseKey(prod);
2245 r = msi_enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL,
2246 MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf,
2247 NULL, NULL, NULL, NULL, &transforms);
2248 if (r != ERROR_SUCCESS)
2249 goto done;
2251 lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2252 if (*pcchTransformsBuf <= lstrlenW(transforms))
2254 r = ERROR_MORE_DATA;
2255 *pcchTransformsBuf = lstrlenW(transforms);
2257 else
2258 *pcchTransformsBuf = lstrlenW(transforms);
2260 done:
2261 msi_free(transforms);
2262 return r;
2265 UINT WINAPI MsiEnumProductsExA( LPCSTR product, LPCSTR usersid, DWORD ctx, DWORD index,
2266 CHAR installed_product[GUID_SIZE],
2267 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
2269 UINT r;
2270 WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
2272 TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid),
2273 ctx, index, installed_product, installed_ctx, sid, sid_len);
2275 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
2276 if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2277 if (usersid && !(usersidW = strdupAtoW( usersid )))
2279 msi_free( productW );
2280 return ERROR_OUTOFMEMORY;
2282 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
2284 msi_free( usersidW );
2285 msi_free( productW );
2286 return ERROR_OUTOFMEMORY;
2288 r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
2289 installed_ctx, sidW, sid_len );
2290 if (r == ERROR_SUCCESS)
2292 if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
2293 installed_product, GUID_SIZE, NULL, NULL );
2294 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
2296 msi_free( productW );
2297 msi_free( usersidW );
2298 msi_free( sidW );
2299 return r;
2302 static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
2303 WCHAR installed_product[GUID_SIZE],
2304 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2306 static const WCHAR productsW[] =
2307 {'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
2308 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
2309 UINT r;
2310 WCHAR product[SQUASHED_GUID_SIZE];
2311 DWORD i = 0, len;
2312 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2313 HKEY key;
2315 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, productsW, 0, access, &key ))
2316 return ERROR_NO_MORE_ITEMS;
2318 len = ARRAY_SIZE( product );
2319 while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
2321 if (match && wcscmp( match, product ))
2323 i++;
2324 len = ARRAY_SIZE( product );
2325 continue;
2327 if (*idx == index) goto found;
2328 (*idx)++;
2329 len = ARRAY_SIZE( product );
2330 i++;
2332 RegCloseKey( key );
2333 return ERROR_NO_MORE_ITEMS;
2335 found:
2336 if (sid_len && *sid_len < 1)
2338 *sid_len = 1;
2339 r = ERROR_MORE_DATA;
2341 else
2343 if (installed_product) unsquash_guid( product, installed_product );
2344 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
2345 if (sid)
2347 sid[0] = 0;
2348 *sid_len = 0;
2350 r = ERROR_SUCCESS;
2352 RegCloseKey( key );
2353 return r;
2356 static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
2357 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2358 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2360 static const WCHAR managedW[] =
2361 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2362 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s',
2363 'i','o','n','\\','I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d',0};
2364 static const WCHAR managed_productsW[] =
2365 {'\\','I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
2366 static const WCHAR unmanaged_productsW[] =
2367 {'\\','S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2368 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
2369 UINT r;
2370 const WCHAR *subkey;
2371 WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
2372 DWORD i = 0, j = 0, len_product, len_user;
2373 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2374 HKEY key_users, key_products;
2376 if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
2378 subkey = managed_productsW;
2379 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, managedW, 0, access, &key_users ))
2380 return ERROR_NO_MORE_ITEMS;
2382 else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
2384 subkey = unmanaged_productsW;
2385 if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
2386 return ERROR_NO_MORE_ITEMS;
2388 else return ERROR_INVALID_PARAMETER;
2390 len_user = ARRAY_SIZE( user );
2391 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
2393 if (wcscmp( usersid, user ) && wcscmp( usersid, szAllSid ))
2395 i++;
2396 len_user = ARRAY_SIZE( user );
2397 continue;
2399 lstrcpyW( path, user );
2400 lstrcatW( path, subkey );
2401 if (RegOpenKeyExW( key_users, path, 0, access, &key_products ))
2403 i++;
2404 len_user = ARRAY_SIZE( user );
2405 continue;
2407 len_product = ARRAY_SIZE( product );
2408 while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
2410 if (match && wcscmp( match, product ))
2412 j++;
2413 len_product = ARRAY_SIZE( product );
2414 continue;
2416 if (*idx == index) goto found;
2417 (*idx)++;
2418 len_product = ARRAY_SIZE( product );
2419 j++;
2421 RegCloseKey( key_products );
2422 len_user = ARRAY_SIZE( user );
2423 i++;
2425 RegCloseKey( key_users );
2426 return ERROR_NO_MORE_ITEMS;
2428 found:
2429 if (sid_len && *sid_len <= len_user)
2431 *sid_len = len_user;
2432 r = ERROR_MORE_DATA;
2434 else
2436 if (installed_product) unsquash_guid( product, installed_product );
2437 if (installed_ctx) *installed_ctx = ctx;
2438 if (sid)
2440 lstrcpyW( sid, user );
2441 *sid_len = len_user;
2443 r = ERROR_SUCCESS;
2445 RegCloseKey( key_products );
2446 RegCloseKey( key_users );
2447 return r;
2450 static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2451 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2452 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2454 UINT r = ERROR_NO_MORE_ITEMS;
2455 WCHAR *user = NULL;
2457 if (!usersid)
2459 usersid = user = get_user_sid();
2460 if (!user) return ERROR_FUNCTION_FAILED;
2462 if (ctx & MSIINSTALLCONTEXT_MACHINE)
2464 r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
2465 sid, sid_len );
2466 if (r != ERROR_NO_MORE_ITEMS) goto done;
2468 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
2470 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
2471 idx, installed_product, installed_ctx, sid, sid_len );
2472 if (r != ERROR_NO_MORE_ITEMS) goto done;
2474 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
2476 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
2477 idx, installed_product, installed_ctx, sid, sid_len );
2478 if (r != ERROR_NO_MORE_ITEMS) goto done;
2481 done:
2482 LocalFree( user );
2483 return r;
2486 UINT WINAPI MsiEnumProductsExW( LPCWSTR product, LPCWSTR usersid, DWORD ctx, DWORD index,
2487 WCHAR installed_product[GUID_SIZE],
2488 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
2490 UINT r;
2491 DWORD idx = 0;
2492 static DWORD last_index;
2494 TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid),
2495 ctx, index, installed_product, installed_ctx, sid, sid_len);
2497 if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
2498 return ERROR_INVALID_PARAMETER;
2500 if (index && index - last_index != 1)
2501 return ERROR_INVALID_PARAMETER;
2503 if (!index) last_index = 0;
2505 r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
2506 sid, sid_len );
2507 if (r == ERROR_SUCCESS)
2508 last_index = index;
2509 else
2510 last_index = 0;
2512 return r;