include: Use the hard-float calling convention for Windows APIs on ARM
[wine.git] / dlls / msi / registry.c
blobcbc8d8d6f0a58d5855f0db971d909e463e71ac5f
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 "wine/unicode.h"
36 #include "winver.h"
37 #include "winuser.h"
38 #include "sddl.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 /*
43 * This module will be all the helper functions for registry access by the
44 * installer bits.
47 static const WCHAR szUserDataFeatures_fmt[] = {
48 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
49 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
50 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
51 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\','F','e','a','t','u','r','e','s',0};
53 static const WCHAR szUserDataComp_fmt[] = {
54 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
55 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
56 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
57 '%','s','\\','C','o','m','p','o','n','e','n','t','s','\\','%','s',0};
59 static const WCHAR szUserDataComponents_fmt[] = {
60 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
61 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
62 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
63 '%','s','\\','C','o','m','p','o','n','e','n','t','s',0};
65 static const WCHAR szUserDataProd_fmt[] = {
66 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
67 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
68 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
69 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
71 static const WCHAR szUserDataProducts_fmt[] = {
72 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
73 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
74 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
75 '%','s','\\','P','r','o','d','u','c','t','s',0};
77 static const WCHAR szUserDataPatch_fmt[] = {
78 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
79 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
80 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
81 '%','s','\\','P','a','t','c','h','e','s','\\','%','s',0};
83 static const WCHAR szUserDataPatches_fmt[] = {
84 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
85 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
86 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
87 '%','s','\\','P','a','t','c','h','e','s',0};
89 static const WCHAR szUserDataProductPatches_fmt[] = {
90 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
91 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
92 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
93 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\','P','a','t','c','h','e','s',0};
95 static const WCHAR szInstallProperties_fmt[] = {
96 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
97 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
98 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
99 '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\',
100 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0};
102 static const WCHAR szInstaller_LocalManagedProd_fmt[] = {
103 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
104 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
105 'I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d','\\','%','s','\\',
106 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s','\\','%','s',0};
108 static const WCHAR szInstaller_LocalManagedFeat_fmt[] = {
109 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
110 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
111 'I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d','\\','%','s','\\',
112 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\','%','s',0};
114 static const WCHAR szInstaller_Products[] = {
115 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
116 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
117 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
119 static const WCHAR szInstaller_Patches[] = {
120 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
121 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
122 'I','n','s','t','a','l','l','e','r','\\','P','a','t','c','h','e','s',0};
124 static const WCHAR szInstaller_LocalClassesProducts[] = {
125 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
126 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
128 static const WCHAR szInstaller_LocalClassesFeatures[] = {
129 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
130 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s',0};
132 static const WCHAR szInstaller_LocalClassesProd[] = {
133 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
134 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s','\\',0};
136 static const WCHAR szInstaller_LocalClassesFeat[] = {
137 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
138 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
140 static const WCHAR szInstaller_ClassesUpgradeCode[] = {
141 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
142 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
144 static const WCHAR szInstaller_ClassesUpgradeCodes[] = {
145 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
146 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s',0};
148 static const WCHAR szInstaller_Features[] = {
149 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
150 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
153 static const WCHAR szInstaller_UpgradeCodes[] = {
154 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
156 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
158 static const WCHAR szInstaller_UserUpgradeCodes[] = {
159 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
160 'I','n','s','t','a','l','l','e','r','\\','U','p','g','r','a','d','e','C','o','d','e','s','\\',0};
162 static const WCHAR szUninstall[] = {
163 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'U','n','i','n','s','t','a','l','l','\\',0};
167 static const WCHAR szUninstall_32node[] = {
168 'S','o','f','t','w','a','r','e','\\','W','o','w','6','4','3','2','N','o','d','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','U','n','i','n','s','t','a','l','l','\\',0};
172 static const WCHAR szUserComponents[] = {
173 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
174 'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
176 static const WCHAR szInstaller_Components[] = {
177 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
178 'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s','\\',0};
180 static const WCHAR szUserFeatures[] = {
181 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
182 'I','n','s','t','a','l','l','e','r','\\','F','e','a','t','u','r','e','s','\\',0};
184 static const WCHAR szUserProducts[] = {
185 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
186 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s','\\',0};
188 static const WCHAR szUserPatches[] = {
189 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
190 'I','n','s','t','a','l','l','e','r','\\','P','a','t','c','h','e','s','\\',0};
192 BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
194 DWORD i,n=0;
196 if (lstrlenW(in) != 32)
197 return FALSE;
199 out[n++]='{';
200 for(i=0; i<8; i++)
201 out[n++] = in[7-i];
202 out[n++]='-';
203 for(i=0; i<4; i++)
204 out[n++] = in[11-i];
205 out[n++]='-';
206 for(i=0; i<4; i++)
207 out[n++] = in[15-i];
208 out[n++]='-';
209 for(i=0; i<2; i++)
211 out[n++] = in[17+i*2];
212 out[n++] = in[16+i*2];
214 out[n++]='-';
215 for( ; i<8; i++)
217 out[n++] = in[17+i*2];
218 out[n++] = in[16+i*2];
220 out[n++]='}';
221 out[n]=0;
222 return TRUE;
225 BOOL squash_guid(LPCWSTR in, LPWSTR out)
227 DWORD i,n=1;
228 GUID guid;
230 out[0] = 0;
232 if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid)))
233 return FALSE;
235 for(i=0; i<8; i++)
236 out[7-i] = in[n++];
237 n++;
238 for(i=0; i<4; i++)
239 out[11-i] = in[n++];
240 n++;
241 for(i=0; i<4; i++)
242 out[15-i] = in[n++];
243 n++;
244 for(i=0; i<2; i++)
246 out[17+i*2] = in[n++];
247 out[16+i*2] = in[n++];
249 n++;
250 for( ; i<8; i++)
252 out[17+i*2] = in[n++];
253 out[16+i*2] = in[n++];
255 out[32]=0;
256 return TRUE;
260 /* tables for encoding and decoding base85 */
261 static const unsigned char table_dec85[0x80] = {
262 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
263 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
264 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
265 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
266 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
267 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
268 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
269 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
272 static const char table_enc85[] =
273 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
274 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
275 "yz{}~";
278 * Converts a base85 encoded guid into a GUID pointer
279 * Base85 encoded GUIDs should be 20 characters long.
281 * returns TRUE if successful, FALSE if not
283 BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
285 DWORD i, val = 0, base = 1, *p;
287 if (!str)
288 return FALSE;
290 p = (DWORD*) guid;
291 for( i=0; i<20; i++ )
293 if( (i%5) == 0 )
295 val = 0;
296 base = 1;
298 val += table_dec85[str[i]] * base;
299 if( str[i] >= 0x80 )
300 return FALSE;
301 if( table_dec85[str[i]] == 0xff )
302 return FALSE;
303 if( (i%5) == 4 )
304 p[i/5] = val;
305 base *= 85;
307 return TRUE;
311 * Encodes a base85 guid given a GUID pointer
312 * Caller should provide a 21 character buffer for the encoded string.
314 * returns TRUE if successful, FALSE if not
316 BOOL encode_base85_guid( GUID *guid, LPWSTR str )
318 unsigned int x, *p, i;
320 p = (unsigned int*) guid;
321 for( i=0; i<4; i++ )
323 x = p[i];
324 *str++ = table_enc85[x%85];
325 x = x/85;
326 *str++ = table_enc85[x%85];
327 x = x/85;
328 *str++ = table_enc85[x%85];
329 x = x/85;
330 *str++ = table_enc85[x%85];
331 x = x/85;
332 *str++ = table_enc85[x%85];
334 *str = 0;
336 return TRUE;
339 DWORD msi_version_str_to_dword(LPCWSTR p)
341 DWORD major, minor = 0, build = 0, version = 0;
343 if (!p)
344 return version;
346 major = atoiW(p);
348 p = strchrW(p, '.');
349 if (p)
351 minor = atoiW(p+1);
352 p = strchrW(p+1, '.');
353 if (p)
354 build = atoiW(p+1);
357 return MAKELONG(build, MAKEWORD(minor, major));
360 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
362 DWORD len;
363 if (!value) value = szEmpty;
364 len = (lstrlenW(value) + 1) * sizeof (WCHAR);
365 return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, len );
368 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value )
370 LPCWSTR p = value;
371 while (*p) p += lstrlenW(p) + 1;
372 return RegSetValueExW( hkey, name, 0, REG_MULTI_SZ,
373 (const BYTE *)value, (p + 1 - value) * sizeof(WCHAR) );
376 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val )
378 return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) );
381 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val )
383 HKEY hsubkey = 0;
384 LONG r;
386 r = RegCreateKeyW( hkey, path, &hsubkey );
387 if (r != ERROR_SUCCESS)
388 return r;
389 r = msi_reg_set_val_str( hsubkey, name, val );
390 RegCloseKey( hsubkey );
391 return r;
394 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name )
396 DWORD len = 0;
397 LPWSTR val;
398 LONG r;
400 r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len);
401 if (r != ERROR_SUCCESS)
402 return NULL;
404 len += sizeof (WCHAR);
405 val = msi_alloc( len );
406 if (!val)
407 return NULL;
408 val[0] = 0;
409 RegQueryValueExW(hkey, name, NULL, NULL, (LPBYTE) val, &len);
410 return val;
413 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val)
415 DWORD type, len = sizeof (DWORD);
416 LONG r = RegQueryValueExW(hkey, name, NULL, &type, (LPBYTE) val, &len);
417 return r == ERROR_SUCCESS && type == REG_DWORD;
420 static WCHAR *get_user_sid(void)
422 HANDLE token;
423 DWORD size = 256;
424 TOKEN_USER *user;
425 WCHAR *ret;
427 if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL;
428 if (!(user = msi_alloc( size )))
430 CloseHandle( token );
431 return NULL;
433 if (!GetTokenInformation( token, TokenUser, user, size, &size ))
435 msi_free( user );
436 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = msi_alloc( size )))
438 CloseHandle( token );
439 return NULL;
441 GetTokenInformation( token, TokenUser, user, size, &size );
443 CloseHandle( token );
444 if (!ConvertSidToStringSidW( user->User.Sid, &ret ))
446 msi_free( user );
447 return NULL;
449 msi_free( user );
450 return ret;
453 UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create)
455 WCHAR keypath[0x200];
457 TRACE("%s\n", debugstr_w(product));
459 if (is_64bit && platform == PLATFORM_INTEL)
461 strcpyW(keypath, szUninstall_32node);
462 strcatW(keypath, product);
464 else
466 strcpyW(keypath, szUninstall);
467 strcatW(keypath, product);
469 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, KEY_ALL_ACCESS, NULL, key, NULL);
470 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, KEY_ALL_ACCESS, key);
473 UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform)
475 WCHAR keypath[0x200];
477 TRACE("%s\n", debugstr_w(product));
479 if (is_64bit && platform == PLATFORM_INTEL)
481 strcpyW(keypath, szUninstall_32node);
482 strcatW(keypath, product);
484 else
486 strcpyW(keypath, szUninstall);
487 strcatW(keypath, product);
489 return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath);
492 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
494 HKEY root = HKEY_LOCAL_MACHINE;
495 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
496 WCHAR *usersid = NULL, squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH];
498 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
499 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
501 if (context == MSIINSTALLCONTEXT_MACHINE)
503 strcpyW(keypath, szInstaller_LocalClassesProd);
504 strcatW( keypath, squashed_pc );
506 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
508 root = HKEY_CURRENT_USER;
509 strcpyW(keypath, szUserProducts);
510 strcatW( keypath, squashed_pc );
512 else
514 if (!szUserSid)
516 if (!(usersid = get_user_sid()))
518 ERR("Failed to retrieve user SID\n");
519 return ERROR_FUNCTION_FAILED;
521 szUserSid = usersid;
523 sprintfW( keypath, szInstaller_LocalManagedProd_fmt, szUserSid, squashed_pc );
524 LocalFree(usersid);
526 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
527 return RegOpenKeyExW(root, keypath, 0, access, key);
530 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct)
532 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
534 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
535 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
537 strcpyW(keypath, szUserProducts);
538 strcatW( keypath, squashed_pc );
539 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
542 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
544 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
546 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
547 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
549 strcpyW(keypath, szUserPatches);
550 strcatW( keypath, squashed_pc );
552 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
553 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
556 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
557 HKEY *key, BOOL create)
559 HKEY root = HKEY_LOCAL_MACHINE;
560 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
561 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[MAX_PATH], *usersid = NULL;
563 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
564 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
566 if (context == MSIINSTALLCONTEXT_MACHINE)
568 strcpyW(keypath, szInstaller_LocalClassesFeat);
569 strcatW( keypath, squashed_pc );
571 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
573 root = HKEY_CURRENT_USER;
574 strcpyW(keypath, szUserFeatures);
575 strcatW( keypath, squashed_pc );
577 else
579 if (!szUserSid)
581 if (!(usersid = get_user_sid()))
583 ERR("Failed to retrieve user SID\n");
584 return ERROR_FUNCTION_FAILED;
586 szUserSid = usersid;
588 sprintfW( keypath, szInstaller_LocalManagedFeat_fmt, szUserSid, squashed_pc );
589 LocalFree(usersid);
591 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL);
592 return RegOpenKeyExW(root, keypath, 0, access, key);
595 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct)
597 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
599 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
600 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
602 strcpyW(keypath, szUserFeatures);
603 strcatW( keypath, squashed_pc );
604 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
607 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create)
609 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
610 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
612 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
613 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
615 strcpyW(keypath, szInstaller_Features);
616 strcatW( keypath, squashed_pc );
618 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
619 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
622 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context,
623 HKEY *key, BOOL create)
625 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
626 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200], *usersid = NULL;
628 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
629 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
631 if (context == MSIINSTALLCONTEXT_MACHINE)
633 sprintfW( keypath, szUserDataFeatures_fmt, szLocalSid, squashed_pc );
635 else
637 if (!szUserSid)
639 if (!(usersid = get_user_sid()))
641 ERR("Failed to retrieve user SID\n");
642 return ERROR_FUNCTION_FAILED;
644 szUserSid = usersid;
646 sprintfW( keypath, szUserDataFeatures_fmt, szUserSid, squashed_pc );
647 LocalFree(usersid);
649 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
650 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
653 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create)
655 WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200];
656 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
657 UINT ret;
659 if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED;
660 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc));
662 strcpyW(keypath, szUserComponents);
663 strcatW( keypath, squashed_cc );
665 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
666 ret = RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
667 if (ret != ERROR_FILE_NOT_FOUND) return ret;
669 strcpyW(keypath, szInstaller_Components);
670 strcatW( keypath, squashed_cc );
671 return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key );
674 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create)
676 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
677 WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
679 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
680 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
682 if (!szUserSid)
684 if (!(usersid = get_user_sid()))
686 ERR("Failed to retrieve user SID\n");
687 return ERROR_FUNCTION_FAILED;
689 sprintfW( keypath, szUserDataComp_fmt, usersid, squashed_comp );
690 LocalFree(usersid);
692 else
693 sprintfW( keypath, szUserDataComp_fmt, szUserSid, squashed_comp );
695 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
696 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
699 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid)
701 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
702 WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200];
703 HKEY hkey;
704 LONG r;
706 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED;
707 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp));
709 if (!szUserSid)
711 if (!(usersid = get_user_sid()))
713 ERR("Failed to retrieve user SID\n");
714 return ERROR_FUNCTION_FAILED;
716 sprintfW(keypath, szUserDataComponents_fmt, usersid);
717 LocalFree(usersid);
719 else
720 sprintfW(keypath, szUserDataComponents_fmt, szUserSid);
722 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
723 r = RegDeleteTreeW( hkey, squashed_comp );
724 RegCloseKey(hkey);
725 return r;
728 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
730 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
731 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
733 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
734 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
736 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
737 sprintfW( keypath, szUserDataProd_fmt, szLocalSid, squashed_pc );
738 else if (szUserSid)
739 sprintfW( keypath, szUserDataProd_fmt, szUserSid, squashed_pc );
740 else
742 if (!(usersid = get_user_sid()))
744 ERR("Failed to retrieve user SID\n");
745 return ERROR_FUNCTION_FAILED;
747 sprintfW( keypath, szUserDataProd_fmt, usersid, squashed_pc );
748 LocalFree(usersid);
750 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
751 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
754 UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create)
756 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
757 WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
759 if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED;
760 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch));
762 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
763 sprintfW( keypath, szUserDataPatch_fmt, szLocalSid, squashed_patch );
764 else
766 if (!(usersid = get_user_sid()))
768 ERR("Failed to retrieve user SID\n");
769 return ERROR_FUNCTION_FAILED;
771 sprintfW( keypath, szUserDataPatch_fmt, usersid, squashed_patch );
772 LocalFree(usersid);
774 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
775 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
778 UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context)
780 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
781 WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200];
782 HKEY hkey;
783 LONG r;
785 if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED;
786 TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch));
788 if (context == MSIINSTALLCONTEXT_MACHINE)
789 sprintfW(keypath, szUserDataPatches_fmt, szLocalSid);
790 else
792 if (!(usersid = get_user_sid()))
794 ERR("Failed to retrieve user SID\n");
795 return ERROR_FUNCTION_FAILED;
797 sprintfW(keypath, szUserDataPatches_fmt, usersid);
798 LocalFree(usersid);
800 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
801 r = RegDeleteTreeW( hkey, squashed_patch );
802 RegCloseKey(hkey);
803 return r;
806 UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create)
808 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
809 WCHAR *usersid, squashed_product[SQUASHED_GUID_SIZE], keypath[0x200];
811 if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED;
812 TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product));
814 if (context == MSIINSTALLCONTEXT_MACHINE)
815 sprintfW( keypath, szUserDataProductPatches_fmt, szLocalSid, squashed_product );
816 else
818 if (!(usersid = get_user_sid()))
820 ERR("Failed to retrieve user SID\n");
821 return ERROR_FUNCTION_FAILED;
823 sprintfW( keypath, szUserDataProductPatches_fmt, usersid, squashed_product );
824 LocalFree(usersid);
826 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
827 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
830 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create)
832 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
833 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
835 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
836 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
838 if (dwContext == MSIINSTALLCONTEXT_MACHINE)
839 sprintfW( keypath, szInstallProperties_fmt, szLocalSid, squashed_pc );
840 else if (szUserSid)
841 sprintfW( keypath, szInstallProperties_fmt, szUserSid, squashed_pc );
842 else
844 if (!(usersid = get_user_sid()))
846 ERR("Failed to retrieve user SID\n");
847 return ERROR_FUNCTION_FAILED;
849 sprintfW( keypath, szInstallProperties_fmt, usersid, squashed_pc );
850 LocalFree(usersid);
852 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
853 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
856 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context)
858 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
859 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
860 HKEY hkey;
861 LONG r;
863 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
864 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
866 if (context == MSIINSTALLCONTEXT_MACHINE)
867 sprintfW(keypath, szUserDataProducts_fmt, szLocalSid);
868 else
870 if (!(usersid = get_user_sid()))
872 ERR("Failed to retrieve user SID\n");
873 return ERROR_FUNCTION_FAILED;
875 sprintfW(keypath, szUserDataProducts_fmt, usersid);
876 LocalFree(usersid);
879 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, &hkey)) return ERROR_SUCCESS;
880 r = RegDeleteTreeW( hkey, squashed_pc );
881 RegCloseKey(hkey);
882 return r;
885 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct)
887 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
888 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
889 HKEY hkey;
890 LONG r;
892 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED;
893 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc));
895 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_Products, 0, access, &hkey)) return ERROR_SUCCESS;
896 r = RegDeleteTreeW( hkey, squashed_pc );
897 RegCloseKey(hkey);
898 return r;
901 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create)
903 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
904 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200];
906 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED;
907 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc));
909 sprintfW( keypath, szInstaller_Patches, squashed_pc );
911 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
912 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
915 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
917 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
918 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
920 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
921 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
923 strcpyW(keypath, szInstaller_UpgradeCodes);
924 strcatW( keypath, squashed_uc );
926 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
927 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
930 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
932 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
934 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
935 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
937 strcpyW(keypath, szInstaller_UserUpgradeCodes);
938 strcatW( keypath, squashed_uc );
940 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key);
941 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key);
944 UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code )
946 WCHAR squashed_code[SQUASHED_GUID_SIZE];
947 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
948 HKEY hkey;
949 LONG ret;
951 if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED;
952 TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) );
954 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, szInstaller_UpgradeCodes, 0, access, &hkey )) return ERROR_SUCCESS;
955 ret = RegDeleteTreeW( hkey, squashed_code );
956 RegCloseKey( hkey );
957 return ret;
960 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode)
962 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
964 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
965 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
967 strcpyW(keypath, szInstaller_UserUpgradeCodes);
968 strcatW( keypath, squashed_uc );
969 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath);
972 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode)
974 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
975 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
976 HKEY hkey;
977 LONG r;
979 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
980 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
982 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesProducts, 0, access, &hkey)) return ERROR_SUCCESS;
983 r = RegDeleteTreeW( hkey, squashed_pc );
984 RegCloseKey(hkey);
985 return r;
988 UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode)
990 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
991 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
992 HKEY hkey;
993 LONG r;
995 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED;
996 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc));
998 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_LocalClassesFeatures, 0, access, &hkey)) return ERROR_SUCCESS;
999 r = RegDeleteTreeW( hkey, squashed_pc );
1000 RegCloseKey(hkey);
1001 return r;
1004 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create)
1006 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
1007 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200];
1009 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
1010 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
1012 strcpyW(keypath, szInstaller_ClassesUpgradeCode);
1013 strcatW( keypath, squashed_uc );
1015 if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL);
1016 return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key);
1019 UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode)
1021 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS;
1022 WCHAR squashed_uc[SQUASHED_GUID_SIZE];
1023 HKEY hkey;
1024 LONG r;
1026 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED;
1027 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc));
1029 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szInstaller_ClassesUpgradeCodes, 0, access, &hkey)) return ERROR_SUCCESS;
1030 r = RegDeleteTreeW( hkey, squashed_uc );
1031 RegCloseKey(hkey);
1032 return r;
1035 /*************************************************************************
1036 * MsiDecomposeDescriptorW [MSI.@]
1038 * Decomposes an MSI descriptor into product, feature and component parts.
1039 * An MSI descriptor is a string of the form:
1040 * [base 85 guid] [feature code] '>' [base 85 guid] or
1041 * [base 85 guid] [feature code] '<'
1043 * PARAMS
1044 * szDescriptor [I] the descriptor to decompose
1045 * szProduct [O] buffer of MAX_FEATURE_CHARS+1 for the product guid
1046 * szFeature [O] buffer of MAX_FEATURE_CHARS+1 for the feature code
1047 * szComponent [O] buffer of MAX_FEATURE_CHARS+1 for the component guid
1048 * pUsed [O] the length of the descriptor
1050 * RETURNS
1051 * ERROR_SUCCESS if everything worked correctly
1052 * ERROR_INVALID_PARAMETER if the descriptor was invalid
1055 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
1056 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed )
1058 UINT len;
1059 const WCHAR *p;
1060 GUID product, component;
1062 TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct,
1063 szFeature, szComponent, pUsed);
1065 if (!decode_base85_guid( szDescriptor, &product ))
1066 return ERROR_INVALID_PARAMETER;
1068 TRACE("product %s\n", debugstr_guid( &product ));
1070 if (!(p = strchrW( &szDescriptor[20], '>' )))
1071 p = strchrW( &szDescriptor[20], '<' );
1072 if (!p)
1073 return ERROR_INVALID_PARAMETER;
1075 len = (p - &szDescriptor[20]);
1076 if( len > MAX_FEATURE_CHARS )
1077 return ERROR_INVALID_PARAMETER;
1079 TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len ));
1081 if (*p == '>')
1083 if (!decode_base85_guid( p+1, &component ))
1084 return ERROR_INVALID_PARAMETER;
1085 TRACE( "component %s\n", debugstr_guid(&component) );
1088 if (szProduct)
1089 StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
1090 if (szComponent)
1092 if (*p == '>')
1093 StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
1094 else
1095 szComponent[0] = 0;
1097 if (szFeature)
1099 memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
1100 szFeature[len] = 0;
1103 len = p - szDescriptor + 1;
1104 if (*p == '>') len += 20;
1106 TRACE("length = %d\n", len);
1107 if (pUsed) *pUsed = len;
1109 return ERROR_SUCCESS;
1112 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
1113 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
1115 WCHAR product[MAX_FEATURE_CHARS+1];
1116 WCHAR feature[MAX_FEATURE_CHARS+1];
1117 WCHAR component[MAX_FEATURE_CHARS+1];
1118 LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
1119 UINT r;
1121 TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
1122 szFeature, szComponent, pUsed);
1124 str = strdupAtoW( szDescriptor );
1125 if( szDescriptor && !str )
1126 return ERROR_OUTOFMEMORY;
1128 if (szProduct)
1129 p = product;
1130 if (szFeature)
1131 f = feature;
1132 if (szComponent)
1133 c = component;
1135 r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
1137 if (r == ERROR_SUCCESS)
1139 WideCharToMultiByte( CP_ACP, 0, p, -1,
1140 szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
1141 WideCharToMultiByte( CP_ACP, 0, f, -1,
1142 szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
1143 WideCharToMultiByte( CP_ACP, 0, c, -1,
1144 szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
1147 msi_free( str );
1149 return r;
1152 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
1154 DWORD r;
1155 WCHAR szwGuid[GUID_SIZE];
1157 TRACE("%d %p\n", index, lpguid);
1159 if (NULL == lpguid)
1160 return ERROR_INVALID_PARAMETER;
1161 r = MsiEnumProductsW(index, szwGuid);
1162 if( r == ERROR_SUCCESS )
1163 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1165 return r;
1168 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
1170 TRACE("%d %p\n", index, lpguid);
1172 if (NULL == lpguid)
1173 return ERROR_INVALID_PARAMETER;
1175 return MsiEnumProductsExW( NULL, szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid,
1176 NULL, NULL, NULL );
1179 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
1180 LPSTR szFeature, LPSTR szParent)
1182 DWORD r;
1183 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
1184 LPWSTR szwProduct = NULL;
1186 TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent);
1188 if( szProduct )
1190 szwProduct = strdupAtoW( szProduct );
1191 if( !szwProduct )
1192 return ERROR_OUTOFMEMORY;
1195 r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
1196 if( r == ERROR_SUCCESS )
1198 WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
1199 szFeature, GUID_SIZE, NULL, NULL);
1200 WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
1201 szParent, GUID_SIZE, NULL, NULL);
1204 msi_free( szwProduct);
1206 return r;
1209 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
1210 LPWSTR szFeature, LPWSTR szParent)
1212 HKEY hkeyProduct = 0;
1213 DWORD r, sz;
1215 TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent);
1217 if( !szProduct )
1218 return ERROR_INVALID_PARAMETER;
1220 r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE);
1221 if( r != ERROR_SUCCESS )
1222 return ERROR_NO_MORE_ITEMS;
1224 sz = GUID_SIZE;
1225 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
1226 RegCloseKey(hkeyProduct);
1228 return r;
1231 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
1233 DWORD r;
1234 WCHAR szwGuid[GUID_SIZE];
1236 TRACE("%u, %p\n", index, lpguid);
1238 if (!lpguid) return ERROR_INVALID_PARAMETER;
1240 r = MsiEnumComponentsW(index, szwGuid);
1241 if( r == ERROR_SUCCESS )
1242 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
1244 return r;
1247 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
1249 TRACE("%u, %p\n", index, lpguid);
1251 if (!lpguid) return ERROR_INVALID_PARAMETER;
1253 return MsiEnumComponentsExW( szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL );
1256 UINT WINAPI MsiEnumComponentsExA( LPCSTR user_sid, DWORD ctx, DWORD index, CHAR guid[39],
1257 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
1259 UINT r;
1260 WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE];
1262 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx,
1263 sid, sid_len);
1265 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
1266 if (user_sid && !(user_sidW = strdupAtoW( user_sid ))) return ERROR_OUTOFMEMORY;
1267 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
1269 msi_free( user_sidW );
1270 return ERROR_OUTOFMEMORY;
1272 r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len );
1273 if (r == ERROR_SUCCESS)
1275 if (guid) WideCharToMultiByte( CP_ACP, 0, guidW, GUID_SIZE, guid, GUID_SIZE, NULL, NULL );
1276 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
1278 msi_free( user_sidW );
1279 msi_free( sidW );
1280 return r;
1283 static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1284 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1286 static const WCHAR componentsW[] =
1287 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1288 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1289 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a','\\',
1290 'S','-','1','-','5','-','1','8','\\','C','o','m','p','o','n','e','n','t','s',0};
1291 UINT r = ERROR_SUCCESS;
1292 WCHAR component[SQUASHED_GUID_SIZE];
1293 DWORD i = 0, len_component;
1294 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1295 HKEY key_components;
1297 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, componentsW, 0, access, &key_components ))
1298 return ERROR_NO_MORE_ITEMS;
1300 len_component = sizeof(component)/sizeof(component[0]);
1301 while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL ))
1303 if (*idx == index) goto found;
1304 (*idx)++;
1305 len_component = sizeof(component)/sizeof(component[0]);
1306 i++;
1308 RegCloseKey( key_components );
1309 return ERROR_NO_MORE_ITEMS;
1311 found:
1312 if (sid_len)
1314 if (*sid_len < 1)
1316 *sid_len = 1;
1317 r = ERROR_MORE_DATA;
1319 else if (sid)
1321 *sid_len = 0;
1322 sid[0] = 0;
1325 if (guid) unsquash_guid( component, guid );
1326 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
1327 RegCloseKey( key_components );
1328 return r;
1331 static UINT fetch_user_component( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx,
1332 WCHAR guid[39], MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid,
1333 LPDWORD sid_len )
1335 static const WCHAR userdataW[] =
1336 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1337 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1338 'I','n','s','t','a','l','l','e','r','\\','U','s','e','r','D','a','t','a',0};
1339 static const WCHAR componentsW[] = {'\\','C','o','m','p','o','n','e','n','t','s',0};
1340 UINT r = ERROR_SUCCESS;
1341 WCHAR path[MAX_PATH], component[SQUASHED_GUID_SIZE], user[128];
1342 DWORD i = 0, j = 0, len_component, len_user;
1343 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
1344 HKEY key_users, key_components;
1346 if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */
1347 return ERROR_NO_MORE_ITEMS;
1349 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, userdataW, 0, access, &key_users ))
1350 return ERROR_NO_MORE_ITEMS;
1352 len_user = sizeof(user)/sizeof(user[0]);
1353 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
1355 if ((strcmpW( usersid, szAllSid ) && strcmpW( usersid, user )) ||
1356 !strcmpW( szLocalSid, user ))
1358 i++;
1359 len_user = sizeof(user)/sizeof(user[0]);
1360 continue;
1362 strcpyW( path, user );
1363 strcatW( path, componentsW );
1364 if (RegOpenKeyExW( key_users, path, 0, access, &key_components ))
1366 i++;
1367 len_user = sizeof(user)/sizeof(user[0]);
1368 continue;
1370 len_component = sizeof(component)/sizeof(component[0]);
1371 while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL ))
1373 if (*idx == index) goto found;
1374 (*idx)++;
1375 len_component = sizeof(component)/sizeof(component[0]);
1376 j++;
1378 RegCloseKey( key_components );
1379 len_user = sizeof(user)/sizeof(user[0]);
1380 i++;
1382 RegCloseKey( key_users );
1383 return ERROR_NO_MORE_ITEMS;
1385 found:
1386 if (sid_len)
1388 if (*sid_len < len_user + 1)
1390 *sid_len = len_user + 1;
1391 r = ERROR_MORE_DATA;
1393 else if (sid)
1395 *sid_len = len_user;
1396 strcpyW( sid, user );
1399 if (guid) unsquash_guid( component, guid );
1400 if (installed_ctx) *installed_ctx = ctx;
1401 RegCloseKey( key_components );
1402 RegCloseKey( key_users );
1403 return r;
1406 static UINT enum_components( const WCHAR *usersid, DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39],
1407 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1409 UINT r = ERROR_NO_MORE_ITEMS;
1410 WCHAR *user = NULL;
1412 if (!usersid)
1414 usersid = user = get_user_sid();
1415 if (!user) return ERROR_FUNCTION_FAILED;
1417 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
1419 r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERMANAGED, index, idx, guid,
1420 installed_ctx, sid, sid_len );
1421 if (r != ERROR_NO_MORE_ITEMS) goto done;
1423 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
1425 r = fetch_user_component( usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index, idx, guid,
1426 installed_ctx, sid, sid_len );
1427 if (r != ERROR_NO_MORE_ITEMS) goto done;
1429 if (ctx & MSIINSTALLCONTEXT_MACHINE)
1431 r = fetch_machine_component( MSIINSTALLCONTEXT_MACHINE, index, idx, guid, installed_ctx,
1432 sid, sid_len );
1433 if (r != ERROR_NO_MORE_ITEMS) goto done;
1436 done:
1437 LocalFree( user );
1438 return r;
1441 UINT WINAPI MsiEnumComponentsExW( LPCWSTR user_sid, DWORD ctx, DWORD index, WCHAR guid[39],
1442 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
1444 UINT r;
1445 DWORD idx = 0;
1446 static DWORD last_index;
1448 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx,
1449 sid, sid_len);
1451 if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE))
1452 return ERROR_INVALID_PARAMETER;
1454 if (index && index - last_index != 1)
1455 return ERROR_INVALID_PARAMETER;
1457 if (!index) last_index = 0;
1459 r = enum_components( user_sid, ctx, index, &idx, guid, installed_ctx, sid, sid_len );
1460 if (r == ERROR_SUCCESS)
1461 last_index = index;
1462 else
1463 last_index = 0;
1465 return r;
1468 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
1470 DWORD r;
1471 WCHAR szwProduct[GUID_SIZE];
1472 LPWSTR szwComponent = NULL;
1474 TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct);
1476 if ( !szProduct )
1477 return ERROR_INVALID_PARAMETER;
1479 if( szComponent )
1481 szwComponent = strdupAtoW( szComponent );
1482 if( !szwComponent )
1483 return ERROR_OUTOFMEMORY;
1486 r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
1487 if( r == ERROR_SUCCESS )
1489 WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
1490 szProduct, GUID_SIZE, NULL, NULL);
1493 msi_free( szwComponent);
1495 return r;
1498 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
1500 HKEY hkeyComp = 0;
1501 DWORD r, sz;
1502 WCHAR szValName[SQUASHED_GUID_SIZE];
1504 TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct);
1506 if (!szComponent || !*szComponent || !szProduct)
1507 return ERROR_INVALID_PARAMETER;
1509 if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS &&
1510 MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkeyComp, FALSE) != ERROR_SUCCESS)
1511 return ERROR_UNKNOWN_COMPONENT;
1513 /* see if there are any products at all */
1514 sz = SQUASHED_GUID_SIZE;
1515 r = RegEnumValueW(hkeyComp, 0, szValName, &sz, NULL, NULL, NULL, NULL);
1516 if (r != ERROR_SUCCESS)
1518 RegCloseKey(hkeyComp);
1520 if (index != 0)
1521 return ERROR_INVALID_PARAMETER;
1523 return ERROR_UNKNOWN_COMPONENT;
1526 sz = SQUASHED_GUID_SIZE;
1527 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
1528 if( r == ERROR_SUCCESS )
1530 unsquash_guid(szValName, szProduct);
1531 TRACE("-> %s\n", debugstr_w(szProduct));
1533 RegCloseKey(hkeyComp);
1534 return r;
1537 UINT WINAPI MsiEnumClientsExA(LPCSTR component, LPCSTR usersid, DWORD ctx, DWORD index,
1538 CHAR installed_product[GUID_SIZE],
1539 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len)
1541 FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid),
1542 ctx, index, installed_product, installed_ctx, sid, sid_len);
1543 return ERROR_ACCESS_DENIED;
1546 UINT WINAPI MsiEnumClientsExW(LPCWSTR component, LPCWSTR usersid, DWORD ctx, DWORD index,
1547 WCHAR installed_product[GUID_SIZE],
1548 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len)
1550 FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid),
1551 ctx, index, installed_product, installed_ctx, sid, sid_len);
1552 return ERROR_ACCESS_DENIED;
1555 static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
1556 awstring *lpQualBuf, LPDWORD pcchQual,
1557 awstring *lpAppBuf, LPDWORD pcchAppBuf )
1559 DWORD name_sz, val_sz, name_max, val_max, type, ofs;
1560 LPWSTR name = NULL, val = NULL;
1561 UINT r, r2;
1562 HKEY key;
1564 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1565 lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
1567 if (!szComponent)
1568 return ERROR_INVALID_PARAMETER;
1570 r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
1571 if (r != ERROR_SUCCESS)
1572 return ERROR_UNKNOWN_COMPONENT;
1574 /* figure out how big the name is we want to return */
1575 name_max = 0x10;
1576 r = ERROR_OUTOFMEMORY;
1577 name = msi_alloc( name_max * sizeof(WCHAR) );
1578 if (!name)
1579 goto end;
1581 val_max = 0x10;
1582 r = ERROR_OUTOFMEMORY;
1583 val = msi_alloc( val_max );
1584 if (!val)
1585 goto end;
1587 /* loop until we allocate enough memory */
1588 while (1)
1590 name_sz = name_max;
1591 val_sz = val_max;
1592 r = RegEnumValueW( key, iIndex, name, &name_sz,
1593 NULL, &type, (LPBYTE)val, &val_sz );
1594 if (r == ERROR_SUCCESS)
1595 break;
1596 if (r != ERROR_MORE_DATA)
1597 goto end;
1599 if (type != REG_MULTI_SZ)
1601 ERR("component data has wrong type (%d)\n", type);
1602 goto end;
1605 r = ERROR_OUTOFMEMORY;
1606 if (name_sz + 1 >= name_max)
1608 name_max *= 2;
1609 msi_free( name );
1610 name = msi_alloc( name_max * sizeof (WCHAR) );
1611 if (!name)
1612 goto end;
1613 continue;
1615 if (val_sz > val_max)
1617 val_max = val_sz + sizeof (WCHAR);
1618 msi_free( val );
1619 val = msi_alloc( val_max * sizeof (WCHAR) );
1620 if (!val)
1621 goto end;
1622 continue;
1624 ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz );
1625 goto end;
1628 ofs = 0;
1629 r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
1630 if (r != ERROR_SUCCESS)
1631 goto end;
1633 TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
1635 r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual );
1636 r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf );
1638 if (r2 != ERROR_SUCCESS)
1639 r = r2;
1641 end:
1642 msi_free(val);
1643 msi_free(name);
1644 RegCloseKey(key);
1645 return r;
1648 /*************************************************************************
1649 * MsiEnumComponentQualifiersA [MSI.@]
1651 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
1652 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1653 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1655 awstring qual, appdata;
1656 LPWSTR comp;
1657 UINT r;
1659 TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex,
1660 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1661 pcchApplicationDataBuf);
1663 comp = strdupAtoW( szComponent );
1664 if (szComponent && !comp)
1665 return ERROR_OUTOFMEMORY;
1667 qual.unicode = FALSE;
1668 qual.str.a = lpQualifierBuf;
1670 appdata.unicode = FALSE;
1671 appdata.str.a = lpApplicationDataBuf;
1673 r = MSI_EnumComponentQualifiers( comp, iIndex,
1674 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1675 msi_free( comp );
1676 return r;
1679 /*************************************************************************
1680 * MsiEnumComponentQualifiersW [MSI.@]
1682 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
1683 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf,
1684 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf )
1686 awstring qual, appdata;
1688 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex,
1689 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
1690 pcchApplicationDataBuf);
1692 qual.unicode = TRUE;
1693 qual.str.w = lpQualifierBuf;
1695 appdata.unicode = TRUE;
1696 appdata.str.w = lpApplicationDataBuf;
1698 return MSI_EnumComponentQualifiers( szComponent, iIndex,
1699 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
1702 /*************************************************************************
1703 * MsiEnumRelatedProductsW [MSI.@]
1706 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved,
1707 DWORD iProductIndex, LPWSTR lpProductBuf)
1709 UINT r;
1710 HKEY hkey;
1711 WCHAR szKeyName[SQUASHED_GUID_SIZE];
1712 DWORD dwSize = sizeof(szKeyName)/sizeof(szKeyName[0]);
1714 TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved,
1715 iProductIndex, lpProductBuf);
1717 if (NULL == szUpgradeCode)
1718 return ERROR_INVALID_PARAMETER;
1719 if (NULL == lpProductBuf)
1720 return ERROR_INVALID_PARAMETER;
1722 r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE);
1723 if (r != ERROR_SUCCESS)
1724 return ERROR_NO_MORE_ITEMS;
1726 r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL);
1727 if( r == ERROR_SUCCESS )
1728 unsquash_guid(szKeyName, lpProductBuf);
1729 RegCloseKey(hkey);
1731 return r;
1734 /*************************************************************************
1735 * MsiEnumRelatedProductsA [MSI.@]
1738 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved,
1739 DWORD iProductIndex, LPSTR lpProductBuf)
1741 LPWSTR szwUpgradeCode = NULL;
1742 WCHAR productW[GUID_SIZE];
1743 UINT r;
1745 TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved,
1746 iProductIndex, lpProductBuf);
1748 if (szUpgradeCode)
1750 szwUpgradeCode = strdupAtoW( szUpgradeCode );
1751 if( !szwUpgradeCode )
1752 return ERROR_OUTOFMEMORY;
1755 r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved,
1756 iProductIndex, productW );
1757 if (r == ERROR_SUCCESS)
1759 WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE,
1760 lpProductBuf, GUID_SIZE, NULL, NULL );
1762 msi_free( szwUpgradeCode);
1763 return r;
1766 /***********************************************************************
1767 * MsiEnumPatchesExA [MSI.@]
1769 UINT WINAPI MsiEnumPatchesExA(LPCSTR szProductCode, LPCSTR szUserSid,
1770 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPSTR szPatchCode,
1771 LPSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
1772 LPSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
1774 LPWSTR prodcode = NULL;
1775 LPWSTR usersid = NULL;
1776 LPWSTR targsid = NULL;
1777 WCHAR patch[GUID_SIZE];
1778 WCHAR targprod[GUID_SIZE];
1779 DWORD len;
1780 UINT r;
1782 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
1783 debugstr_a(szProductCode), debugstr_a(szUserSid), dwContext, dwFilter,
1784 dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
1785 szTargetUserSid, pcchTargetUserSid);
1787 if (szTargetUserSid && !pcchTargetUserSid)
1788 return ERROR_INVALID_PARAMETER;
1790 if (szProductCode) prodcode = strdupAtoW(szProductCode);
1791 if (szUserSid) usersid = strdupAtoW(szUserSid);
1793 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1794 patch, targprod, pdwTargetProductContext,
1795 NULL, &len);
1796 if (r != ERROR_SUCCESS)
1797 goto done;
1799 WideCharToMultiByte(CP_ACP, 0, patch, -1, szPatchCode,
1800 GUID_SIZE, NULL, NULL);
1801 WideCharToMultiByte(CP_ACP, 0, targprod, -1, szTargetProductCode,
1802 GUID_SIZE, NULL, NULL);
1804 if (!szTargetUserSid)
1806 if (pcchTargetUserSid)
1807 *pcchTargetUserSid = len;
1809 goto done;
1812 targsid = msi_alloc(++len * sizeof(WCHAR));
1813 if (!targsid)
1815 r = ERROR_OUTOFMEMORY;
1816 goto done;
1819 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex,
1820 patch, targprod, pdwTargetProductContext,
1821 targsid, &len);
1822 if (r != ERROR_SUCCESS || !szTargetUserSid)
1823 goto done;
1825 WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid,
1826 *pcchTargetUserSid, NULL, NULL);
1828 len = lstrlenW(targsid);
1829 if (*pcchTargetUserSid < len + 1)
1831 r = ERROR_MORE_DATA;
1832 *pcchTargetUserSid = len * sizeof(WCHAR);
1834 else
1835 *pcchTargetUserSid = len;
1837 done:
1838 msi_free(prodcode);
1839 msi_free(usersid);
1840 msi_free(targsid);
1842 return r;
1845 static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid,
1846 MSIINSTALLCONTEXT context,
1847 LPWSTR patch, MSIPATCHSTATE *state)
1849 DWORD type, val, size;
1850 HKEY prod, hkey = 0;
1851 HKEY udpatch = 0;
1852 LONG res;
1853 UINT r = ERROR_NO_MORE_ITEMS;
1855 *state = MSIPATCHSTATE_INVALID;
1857 r = MSIREG_OpenUserDataProductKey(prodcode, context,
1858 usersid, &prod, FALSE);
1859 if (r != ERROR_SUCCESS)
1860 return ERROR_NO_MORE_ITEMS;
1862 res = RegOpenKeyExW(prod, szPatches, 0, KEY_READ, &hkey);
1863 if (res != ERROR_SUCCESS)
1864 goto done;
1866 res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch);
1867 if (res != ERROR_SUCCESS)
1868 goto done;
1870 size = sizeof(DWORD);
1871 res = RegGetValueW(udpatch, NULL, szState, RRF_RT_DWORD, &type, &val, &size);
1872 if (res != ERROR_SUCCESS ||
1873 val < MSIPATCHSTATE_APPLIED || val > MSIPATCHSTATE_REGISTERED)
1875 r = ERROR_BAD_CONFIGURATION;
1876 goto done;
1879 *state = val;
1880 r = ERROR_SUCCESS;
1882 done:
1883 RegCloseKey(udpatch);
1884 RegCloseKey(hkey);
1885 RegCloseKey(prod);
1887 return r;
1890 static UINT msi_check_product_patches(LPCWSTR prodcode, LPCWSTR usersid,
1891 MSIINSTALLCONTEXT context, DWORD filter, DWORD index, DWORD *idx,
1892 LPWSTR patch, LPWSTR targetprod, MSIINSTALLCONTEXT *targetctx,
1893 LPWSTR targetsid, DWORD *sidsize, LPWSTR *transforms)
1895 MSIPATCHSTATE state = MSIPATCHSTATE_INVALID;
1896 LPWSTR ptr, patches = NULL;
1897 HKEY prod, patchkey = 0;
1898 HKEY localprod = 0, localpatch = 0;
1899 DWORD type, size;
1900 LONG res;
1901 UINT temp, r = ERROR_NO_MORE_ITEMS;
1903 if (MSIREG_OpenProductKey(prodcode, usersid, context,
1904 &prod, FALSE) != ERROR_SUCCESS)
1905 return ERROR_NO_MORE_ITEMS;
1907 size = 0;
1908 res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, NULL,
1909 &size);
1910 if (res != ERROR_SUCCESS)
1911 goto done;
1913 if (type != REG_MULTI_SZ)
1915 r = ERROR_BAD_CONFIGURATION;
1916 goto done;
1919 patches = msi_alloc(size);
1920 if (!patches)
1922 r = ERROR_OUTOFMEMORY;
1923 goto done;
1926 res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type,
1927 patches, &size);
1928 if (res != ERROR_SUCCESS)
1929 goto done;
1931 for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1)
1933 if (!unsquash_guid(ptr, patch))
1935 r = ERROR_BAD_CONFIGURATION;
1936 goto done;
1939 size = 0;
1940 res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1941 &type, NULL, &size);
1942 if (res != ERROR_SUCCESS)
1943 continue;
1945 if (transforms)
1947 *transforms = msi_alloc(size);
1948 if (!*transforms)
1950 r = ERROR_OUTOFMEMORY;
1951 goto done;
1954 res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ,
1955 &type, *transforms, &size);
1956 if (res != ERROR_SUCCESS)
1957 continue;
1960 if (context == MSIINSTALLCONTEXT_USERMANAGED)
1962 if (!(filter & MSIPATCHSTATE_APPLIED))
1964 temp = msi_get_patch_state(prodcode, usersid, context,
1965 ptr, &state);
1966 if (temp == ERROR_BAD_CONFIGURATION)
1968 r = ERROR_BAD_CONFIGURATION;
1969 goto done;
1972 if (temp != ERROR_SUCCESS || !(filter & state))
1973 continue;
1976 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED)
1978 if (!(filter & MSIPATCHSTATE_APPLIED))
1980 temp = msi_get_patch_state(prodcode, usersid, context,
1981 ptr, &state);
1982 if (temp == ERROR_BAD_CONFIGURATION)
1984 r = ERROR_BAD_CONFIGURATION;
1985 goto done;
1988 if (temp != ERROR_SUCCESS || !(filter & state))
1989 continue;
1991 else
1993 temp = MSIREG_OpenUserDataPatchKey(patch, context,
1994 &patchkey, FALSE);
1995 RegCloseKey(patchkey);
1996 if (temp != ERROR_SUCCESS)
1997 continue;
2000 else if (context == MSIINSTALLCONTEXT_MACHINE)
2002 usersid = szEmpty;
2004 if (MSIREG_OpenUserDataProductKey(prodcode, context, NULL, &localprod, FALSE) == ERROR_SUCCESS &&
2005 RegOpenKeyExW(localprod, szPatches, 0, KEY_READ, &localpatch) == ERROR_SUCCESS &&
2006 RegOpenKeyExW(localpatch, ptr, 0, KEY_READ, &patchkey) == ERROR_SUCCESS)
2008 res = RegGetValueW(patchkey, NULL, szState, RRF_RT_REG_DWORD,
2009 &type, &state, &size);
2011 if (!(filter & state))
2012 res = ERROR_NO_MORE_ITEMS;
2014 RegCloseKey(patchkey);
2017 RegCloseKey(localpatch);
2018 RegCloseKey(localprod);
2020 if (res != ERROR_SUCCESS)
2021 continue;
2024 if (*idx < index)
2026 (*idx)++;
2027 continue;
2030 r = ERROR_SUCCESS;
2031 if (targetprod)
2032 lstrcpyW(targetprod, prodcode);
2034 if (targetctx)
2035 *targetctx = context;
2037 if (targetsid)
2039 lstrcpynW(targetsid, usersid, *sidsize);
2040 if (lstrlenW(usersid) >= *sidsize)
2041 r = ERROR_MORE_DATA;
2044 if (sidsize)
2046 *sidsize = lstrlenW(usersid);
2047 if (!targetsid)
2048 *sidsize *= sizeof(WCHAR);
2052 done:
2053 RegCloseKey(prod);
2054 msi_free(patches);
2056 return r;
2059 static UINT msi_enum_patches(LPCWSTR szProductCode, LPCWSTR szUserSid,
2060 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, DWORD *idx,
2061 LPWSTR szPatchCode, LPWSTR szTargetProductCode,
2062 MSIINSTALLCONTEXT *pdwTargetProductContext, LPWSTR szTargetUserSid,
2063 LPDWORD pcchTargetUserSid, LPWSTR *szTransforms)
2065 LPWSTR usersid = NULL;
2066 UINT r = ERROR_INVALID_PARAMETER;
2068 if (!szUserSid)
2070 szUserSid = usersid = get_user_sid();
2071 if (!usersid) return ERROR_FUNCTION_FAILED;
2074 if (dwContext & MSIINSTALLCONTEXT_USERMANAGED)
2076 r = msi_check_product_patches(szProductCode, szUserSid,
2077 MSIINSTALLCONTEXT_USERMANAGED, dwFilter,
2078 dwIndex, idx, szPatchCode,
2079 szTargetProductCode,
2080 pdwTargetProductContext, szTargetUserSid,
2081 pcchTargetUserSid, szTransforms);
2082 if (r != ERROR_NO_MORE_ITEMS)
2083 goto done;
2086 if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED)
2088 r = msi_check_product_patches(szProductCode, szUserSid,
2089 MSIINSTALLCONTEXT_USERUNMANAGED, dwFilter,
2090 dwIndex, idx, szPatchCode,
2091 szTargetProductCode,
2092 pdwTargetProductContext, szTargetUserSid,
2093 pcchTargetUserSid, szTransforms);
2094 if (r != ERROR_NO_MORE_ITEMS)
2095 goto done;
2098 if (dwContext & MSIINSTALLCONTEXT_MACHINE)
2100 r = msi_check_product_patches(szProductCode, szUserSid,
2101 MSIINSTALLCONTEXT_MACHINE, dwFilter,
2102 dwIndex, idx, szPatchCode,
2103 szTargetProductCode,
2104 pdwTargetProductContext, szTargetUserSid,
2105 pcchTargetUserSid, szTransforms);
2106 if (r != ERROR_NO_MORE_ITEMS)
2107 goto done;
2110 done:
2111 LocalFree(usersid);
2112 return r;
2115 /***********************************************************************
2116 * MsiEnumPatchesExW [MSI.@]
2118 UINT WINAPI MsiEnumPatchesExW(LPCWSTR szProductCode, LPCWSTR szUserSid,
2119 DWORD dwContext, DWORD dwFilter, DWORD dwIndex, LPWSTR szPatchCode,
2120 LPWSTR szTargetProductCode, MSIINSTALLCONTEXT *pdwTargetProductContext,
2121 LPWSTR szTargetUserSid, LPDWORD pcchTargetUserSid)
2123 WCHAR squashed_pc[SQUASHED_GUID_SIZE];
2124 DWORD idx = 0;
2125 UINT r;
2127 static DWORD last_index;
2129 TRACE("(%s, %s, %d, %d, %d, %p, %p, %p, %p, %p)\n",
2130 debugstr_w(szProductCode), debugstr_w(szUserSid), dwContext, dwFilter,
2131 dwIndex, szPatchCode, szTargetProductCode, pdwTargetProductContext,
2132 szTargetUserSid, pcchTargetUserSid);
2134 if (!szProductCode || !squash_guid( szProductCode, squashed_pc ))
2135 return ERROR_INVALID_PARAMETER;
2137 if (szUserSid && !strcmpW( szUserSid, szLocalSid ))
2138 return ERROR_INVALID_PARAMETER;
2140 if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid)
2141 return ERROR_INVALID_PARAMETER;
2143 if (dwContext <= MSIINSTALLCONTEXT_NONE ||
2144 dwContext > MSIINSTALLCONTEXT_ALL)
2145 return ERROR_INVALID_PARAMETER;
2147 if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL)
2148 return ERROR_INVALID_PARAMETER;
2150 if (dwIndex && dwIndex - last_index != 1)
2151 return ERROR_INVALID_PARAMETER;
2153 if (dwIndex == 0)
2154 last_index = 0;
2156 r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter,
2157 dwIndex, &idx, szPatchCode, szTargetProductCode,
2158 pdwTargetProductContext, szTargetUserSid,
2159 pcchTargetUserSid, NULL);
2161 if (r == ERROR_SUCCESS)
2162 last_index = dwIndex;
2163 else
2164 last_index = 0;
2166 return r;
2169 /***********************************************************************
2170 * MsiEnumPatchesA [MSI.@]
2172 UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex,
2173 LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2175 LPWSTR product, transforms;
2176 WCHAR patch[GUID_SIZE];
2177 DWORD len;
2178 UINT r;
2180 TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex,
2181 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2183 if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2184 return ERROR_INVALID_PARAMETER;
2186 product = strdupAtoW(szProduct);
2187 if (!product)
2188 return ERROR_OUTOFMEMORY;
2190 len = *pcchTransformsBuf;
2191 transforms = msi_alloc( len * sizeof(WCHAR) );
2192 if (!transforms)
2194 r = ERROR_OUTOFMEMORY;
2195 goto done;
2198 r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len);
2199 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
2200 goto done;
2202 WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf,
2203 GUID_SIZE, NULL, NULL);
2205 if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf,
2206 *pcchTransformsBuf, NULL, NULL))
2207 r = ERROR_MORE_DATA;
2209 if (r == ERROR_MORE_DATA)
2211 lpTransformsBuf[*pcchTransformsBuf - 1] = '\0';
2212 *pcchTransformsBuf = len * 2;
2214 else
2215 *pcchTransformsBuf = strlen( lpTransformsBuf );
2217 done:
2218 msi_free(transforms);
2219 msi_free(product);
2221 return r;
2224 /***********************************************************************
2225 * MsiEnumPatchesW [MSI.@]
2227 UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex,
2228 LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf)
2230 WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE];
2231 HKEY prod;
2232 DWORD idx = 0;
2233 UINT r;
2235 TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex,
2236 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
2238 if (!szProduct || !squash_guid( szProduct, squashed_pc ))
2239 return ERROR_INVALID_PARAMETER;
2241 if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf)
2242 return ERROR_INVALID_PARAMETER;
2244 if (MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERMANAGED,
2245 &prod, FALSE) != ERROR_SUCCESS &&
2246 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
2247 &prod, FALSE) != ERROR_SUCCESS &&
2248 MSIREG_OpenProductKey(szProduct, NULL, MSIINSTALLCONTEXT_MACHINE,
2249 &prod, FALSE) != ERROR_SUCCESS)
2250 return ERROR_UNKNOWN_PRODUCT;
2252 RegCloseKey(prod);
2254 r = msi_enum_patches(szProduct, NULL, MSIINSTALLCONTEXT_ALL,
2255 MSIPATCHSTATE_ALL, iPatchIndex, &idx, lpPatchBuf,
2256 NULL, NULL, NULL, NULL, &transforms);
2257 if (r != ERROR_SUCCESS)
2258 goto done;
2260 lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf);
2261 if (*pcchTransformsBuf <= lstrlenW(transforms))
2263 r = ERROR_MORE_DATA;
2264 *pcchTransformsBuf = lstrlenW(transforms);
2266 else
2267 *pcchTransformsBuf = lstrlenW(transforms);
2269 done:
2270 msi_free(transforms);
2271 return r;
2274 UINT WINAPI MsiEnumProductsExA( LPCSTR product, LPCSTR usersid, DWORD ctx, DWORD index,
2275 CHAR installed_product[GUID_SIZE],
2276 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len )
2278 UINT r;
2279 WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL;
2281 TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(product), debugstr_a(usersid),
2282 ctx, index, installed_product, installed_ctx, sid, sid_len);
2284 if (sid && !sid_len) return ERROR_INVALID_PARAMETER;
2285 if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY;
2286 if (usersid && !(usersidW = strdupAtoW( usersid )))
2288 msi_free( productW );
2289 return ERROR_OUTOFMEMORY;
2291 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) )))
2293 msi_free( usersidW );
2294 msi_free( productW );
2295 return ERROR_OUTOFMEMORY;
2297 r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW,
2298 installed_ctx, sidW, sid_len );
2299 if (r == ERROR_SUCCESS)
2301 if (installed_product) WideCharToMultiByte( CP_ACP, 0, installed_productW, GUID_SIZE,
2302 installed_product, GUID_SIZE, NULL, NULL );
2303 if (sid) WideCharToMultiByte( CP_ACP, 0, sidW, *sid_len + 1, sid, *sid_len + 1, NULL, NULL );
2305 msi_free( productW );
2306 msi_free( usersidW );
2307 msi_free( sidW );
2308 return r;
2311 static UINT fetch_machine_product( const WCHAR *match, DWORD index, DWORD *idx,
2312 WCHAR installed_product[GUID_SIZE],
2313 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2315 static const WCHAR productsW[] =
2316 {'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\',
2317 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
2318 UINT r;
2319 WCHAR product[SQUASHED_GUID_SIZE];
2320 DWORD i = 0, len;
2321 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2322 HKEY key;
2324 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, productsW, 0, access, &key ))
2325 return ERROR_NO_MORE_ITEMS;
2327 len = sizeof(product)/sizeof(product[0]);
2328 while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL ))
2330 if (match && strcmpW( match, product ))
2332 i++;
2333 len = sizeof(product)/sizeof(product[0]);
2334 continue;
2336 if (*idx == index) goto found;
2337 (*idx)++;
2338 len = sizeof(product)/sizeof(product[0]);
2339 i++;
2341 RegCloseKey( key );
2342 return ERROR_NO_MORE_ITEMS;
2344 found:
2345 if (sid_len && *sid_len < 1)
2347 *sid_len = 1;
2348 r = ERROR_MORE_DATA;
2350 else
2352 if (installed_product) unsquash_guid( product, installed_product );
2353 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE;
2354 if (sid)
2356 sid[0] = 0;
2357 *sid_len = 0;
2359 r = ERROR_SUCCESS;
2361 RegCloseKey( key );
2362 return r;
2365 static UINT fetch_user_product( const WCHAR *match, const WCHAR *usersid, DWORD ctx, DWORD index,
2366 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2367 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2369 static const WCHAR managedW[] =
2370 {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2371 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s',
2372 'i','o','n','\\','I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d',0};
2373 static const WCHAR managed_productsW[] =
2374 {'\\','I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
2375 static const WCHAR unmanaged_productsW[] =
2376 {'\\','S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2377 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0};
2378 UINT r;
2379 const WCHAR *subkey;
2380 WCHAR path[MAX_PATH], product[SQUASHED_GUID_SIZE], user[128];
2381 DWORD i = 0, j = 0, len_product, len_user;
2382 REGSAM access = KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY;
2383 HKEY key_users, key_products;
2385 if (ctx == MSIINSTALLCONTEXT_USERMANAGED)
2387 subkey = managed_productsW;
2388 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, managedW, 0, access, &key_users ))
2389 return ERROR_NO_MORE_ITEMS;
2391 else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED)
2393 subkey = unmanaged_productsW;
2394 if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users ))
2395 return ERROR_NO_MORE_ITEMS;
2397 else return ERROR_INVALID_PARAMETER;
2399 len_user = sizeof(user)/sizeof(user[0]);
2400 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL ))
2402 if (strcmpW( usersid, user ) && strcmpW( usersid, szAllSid ))
2404 i++;
2405 len_user = sizeof(user)/sizeof(user[0]);
2406 continue;
2408 strcpyW( path, user );
2409 strcatW( path, subkey );
2410 if (RegOpenKeyExW( key_users, path, 0, access, &key_products ))
2412 i++;
2413 len_user = sizeof(user)/sizeof(user[0]);
2414 continue;
2416 len_product = sizeof(product)/sizeof(product[0]);
2417 while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL ))
2419 if (match && strcmpW( match, product ))
2421 j++;
2422 len_product = sizeof(product)/sizeof(product[0]);
2423 continue;
2425 if (*idx == index) goto found;
2426 (*idx)++;
2427 len_product = sizeof(product)/sizeof(product[0]);
2428 j++;
2430 RegCloseKey( key_products );
2431 len_user = sizeof(user)/sizeof(user[0]);
2432 i++;
2434 RegCloseKey( key_users );
2435 return ERROR_NO_MORE_ITEMS;
2437 found:
2438 if (sid_len && *sid_len <= len_user)
2440 *sid_len = len_user;
2441 r = ERROR_MORE_DATA;
2443 else
2445 if (installed_product) unsquash_guid( product, installed_product );
2446 if (installed_ctx) *installed_ctx = ctx;
2447 if (sid)
2449 strcpyW( sid, user );
2450 *sid_len = len_user;
2452 r = ERROR_SUCCESS;
2454 RegCloseKey( key_products );
2455 RegCloseKey( key_users );
2456 return r;
2459 static UINT enum_products( const WCHAR *product, const WCHAR *usersid, DWORD ctx, DWORD index,
2460 DWORD *idx, WCHAR installed_product[GUID_SIZE],
2461 MSIINSTALLCONTEXT *installed_ctx, WCHAR *sid, DWORD *sid_len )
2463 UINT r = ERROR_NO_MORE_ITEMS;
2464 WCHAR *user = NULL;
2466 if (!usersid)
2468 usersid = user = get_user_sid();
2469 if (!user) return ERROR_FUNCTION_FAILED;
2471 if (ctx & MSIINSTALLCONTEXT_MACHINE)
2473 r = fetch_machine_product( product, index, idx, installed_product, installed_ctx,
2474 sid, sid_len );
2475 if (r != ERROR_NO_MORE_ITEMS) goto done;
2477 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED)
2479 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, index,
2480 idx, installed_product, installed_ctx, sid, sid_len );
2481 if (r != ERROR_NO_MORE_ITEMS) goto done;
2483 if (ctx & MSIINSTALLCONTEXT_USERMANAGED)
2485 r = fetch_user_product( product, usersid, MSIINSTALLCONTEXT_USERMANAGED, index,
2486 idx, installed_product, installed_ctx, sid, sid_len );
2487 if (r != ERROR_NO_MORE_ITEMS) goto done;
2490 done:
2491 LocalFree( user );
2492 return r;
2495 UINT WINAPI MsiEnumProductsExW( LPCWSTR product, LPCWSTR usersid, DWORD ctx, DWORD index,
2496 WCHAR installed_product[GUID_SIZE],
2497 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len )
2499 UINT r;
2500 DWORD idx = 0;
2501 static DWORD last_index;
2503 TRACE("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(product), debugstr_w(usersid),
2504 ctx, index, installed_product, installed_ctx, sid, sid_len);
2506 if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE))
2507 return ERROR_INVALID_PARAMETER;
2509 if (index && index - last_index != 1)
2510 return ERROR_INVALID_PARAMETER;
2512 if (!index) last_index = 0;
2514 r = enum_products( product, usersid, ctx, index, &idx, installed_product, installed_ctx,
2515 sid, sid_len );
2516 if (r == ERROR_SUCCESS)
2517 last_index = index;
2518 else
2519 last_index = 0;
2521 return r;