1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2005 Mike McCormack for CodeWeavers 5 * Copyright 2005 Aric Stewart for CodeWeavers 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdarg.h> 23 24 #define COBJMACROS 25 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" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(msi); 41 42 /* 43 * This module will be all the helper functions for registry access by the 44 * installer bits. 45 */ 46 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}; 52 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}; 58 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}; 64 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}; 70 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}; 76 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}; 82 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}; 88 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}; 94 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}; 101 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}; 107 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}; 113 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}; 118 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}; 123 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}; 127 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}; 131 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}; 135 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}; 139 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}; 143 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}; 147 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}; 152 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}; 157 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}; 161 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}; 166 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}; 171 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}; 175 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}; 179 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}; 183 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}; 187 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}; 191 192 BOOL unsquash_guid(LPCWSTR in, LPWSTR out) 193 { 194 DWORD i,n=0; 195 196 if (lstrlenW(in) != 32) 197 return FALSE; 198 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++) 210 { 211 out[n++] = in[17+i*2]; 212 out[n++] = in[16+i*2]; 213 } 214 out[n++]='-'; 215 for( ; i<8; i++) 216 { 217 out[n++] = in[17+i*2]; 218 out[n++] = in[16+i*2]; 219 } 220 out[n++]='}'; 221 out[n]=0; 222 return TRUE; 223 } 224 225 BOOL squash_guid(LPCWSTR in, LPWSTR out) 226 { 227 DWORD i,n=1; 228 GUID guid; 229 230 out[0] = 0; 231 232 if (FAILED(CLSIDFromString((LPCOLESTR)in, &guid))) 233 return FALSE; 234 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++) 245 { 246 out[17+i*2] = in[n++]; 247 out[16+i*2] = in[n++]; 248 } 249 n++; 250 for( ; i<8; i++) 251 { 252 out[17+i*2] = in[n++]; 253 out[16+i*2] = in[n++]; 254 } 255 out[32]=0; 256 return TRUE; 257 } 258 259 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, 270 }; 271 272 static const char table_enc85[] = 273 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO" 274 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx" 275 "yz{}~"; 276 277 /* 278 * Converts a base85 encoded guid into a GUID pointer 279 * Base85 encoded GUIDs should be 20 characters long. 280 * 281 * returns TRUE if successful, FALSE if not 282 */ 283 BOOL decode_base85_guid( LPCWSTR str, GUID *guid ) 284 { 285 DWORD i, val = 0, base = 1, *p; 286 287 if (!str) 288 return FALSE; 289 290 p = (DWORD*) guid; 291 for( i=0; i<20; i++ ) 292 { 293 if( (i%5) == 0 ) 294 { 295 val = 0; 296 base = 1; 297 } 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; 306 } 307 return TRUE; 308 } 309 310 /* 311 * Encodes a base85 guid given a GUID pointer 312 * Caller should provide a 21 character buffer for the encoded string. 313 * 314 * returns TRUE if successful, FALSE if not 315 */ 316 BOOL encode_base85_guid( GUID *guid, LPWSTR str ) 317 { 318 unsigned int x, *p, i; 319 320 p = (unsigned int*) guid; 321 for( i=0; i<4; i++ ) 322 { 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]; 333 } 334 *str = 0; 335 336 return TRUE; 337 } 338 339 DWORD msi_version_str_to_dword(LPCWSTR p) 340 { 341 DWORD major, minor = 0, build = 0, version = 0; 342 343 if (!p) 344 return version; 345 346 major = atoiW(p); 347 348 p = strchrW(p, '.'); 349 if (p) 350 { 351 minor = atoiW(p+1); 352 p = strchrW(p+1, '.'); 353 if (p) 354 build = atoiW(p+1); 355 } 356 357 return MAKELONG(build, MAKEWORD(minor, major)); 358 } 359 360 LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) 361 { 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 ); 366 } 367 368 LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) 369 { 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) ); 374 } 375 376 LONG msi_reg_set_val_dword( HKEY hkey, LPCWSTR name, DWORD val ) 377 { 378 return RegSetValueExW( hkey, name, 0, REG_DWORD, (LPBYTE)&val, sizeof (DWORD) ); 379 } 380 381 LONG msi_reg_set_subkey_val( HKEY hkey, LPCWSTR path, LPCWSTR name, LPCWSTR val ) 382 { 383 HKEY hsubkey = 0; 384 LONG r; 385 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; 392 } 393 394 LPWSTR msi_reg_get_val_str( HKEY hkey, LPCWSTR name ) 395 { 396 DWORD len = 0; 397 LPWSTR val; 398 LONG r; 399 400 r = RegQueryValueExW(hkey, name, NULL, NULL, NULL, &len); 401 if (r != ERROR_SUCCESS) 402 return NULL; 403 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; 411 } 412 413 BOOL msi_reg_get_val_dword( HKEY hkey, LPCWSTR name, DWORD *val) 414 { 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; 418 } 419 420 static WCHAR *get_user_sid(void) 421 { 422 HANDLE token; 423 DWORD size = 256; 424 TOKEN_USER *user; 425 WCHAR *ret; 426 427 if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token )) return NULL; 428 if (!(user = msi_alloc( size ))) 429 { 430 CloseHandle( token ); 431 return NULL; 432 } 433 if (!GetTokenInformation( token, TokenUser, user, size, &size )) 434 { 435 msi_free( user ); 436 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !(user = msi_alloc( size ))) 437 { 438 CloseHandle( token ); 439 return NULL; 440 } 441 GetTokenInformation( token, TokenUser, user, size, &size ); 442 } 443 CloseHandle( token ); 444 if (!ConvertSidToStringSidW( user->User.Sid, &ret )) 445 { 446 msi_free( user ); 447 return NULL; 448 } 449 msi_free( user ); 450 return ret; 451 } 452 453 UINT MSIREG_OpenUninstallKey(const WCHAR *product, enum platform platform, HKEY *key, BOOL create) 454 { 455 WCHAR keypath[0x200]; 456 457 TRACE("%s\n", debugstr_w(product)); 458 459 if (is_64bit && platform == PLATFORM_INTEL) 460 { 461 strcpyW(keypath, szUninstall_32node); 462 strcatW(keypath, product); 463 } 464 else 465 { 466 strcpyW(keypath, szUninstall); 467 strcatW(keypath, product); 468 } 469 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); 471 } 472 473 UINT MSIREG_DeleteUninstallKey(const WCHAR *product, enum platform platform) 474 { 475 WCHAR keypath[0x200]; 476 477 TRACE("%s\n", debugstr_w(product)); 478 479 if (is_64bit && platform == PLATFORM_INTEL) 480 { 481 strcpyW(keypath, szUninstall_32node); 482 strcatW(keypath, product); 483 } 484 else 485 { 486 strcpyW(keypath, szUninstall); 487 strcatW(keypath, product); 488 } 489 return RegDeleteTreeW(HKEY_LOCAL_MACHINE, keypath); 490 } 491 492 UINT MSIREG_OpenProductKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create) 493 { 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]; 497 498 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 499 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 500 501 if (context == MSIINSTALLCONTEXT_MACHINE) 502 { 503 strcpyW(keypath, szInstaller_LocalClassesProd); 504 strcatW( keypath, squashed_pc ); 505 } 506 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED) 507 { 508 root = HKEY_CURRENT_USER; 509 strcpyW(keypath, szUserProducts); 510 strcatW( keypath, squashed_pc ); 511 } 512 else 513 { 514 if (!szUserSid) 515 { 516 if (!(usersid = get_user_sid())) 517 { 518 ERR("Failed to retrieve user SID\n"); 519 return ERROR_FUNCTION_FAILED; 520 } 521 szUserSid = usersid; 522 } 523 sprintfW( keypath, szInstaller_LocalManagedProd_fmt, szUserSid, squashed_pc ); 524 LocalFree(usersid); 525 } 526 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL); 527 return RegOpenKeyExW(root, keypath, 0, access, key); 528 } 529 530 UINT MSIREG_DeleteUserProductKey(LPCWSTR szProduct) 531 { 532 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 533 534 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 535 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 536 537 strcpyW(keypath, szUserProducts); 538 strcatW( keypath, squashed_pc ); 539 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath); 540 } 541 542 UINT MSIREG_OpenUserPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create) 543 { 544 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 545 546 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED; 547 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc)); 548 549 strcpyW(keypath, szUserPatches); 550 strcatW( keypath, squashed_pc ); 551 552 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key); 553 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key); 554 } 555 556 UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, 557 HKEY *key, BOOL create) 558 { 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; 562 563 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 564 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 565 566 if (context == MSIINSTALLCONTEXT_MACHINE) 567 { 568 strcpyW(keypath, szInstaller_LocalClassesFeat); 569 strcatW( keypath, squashed_pc ); 570 } 571 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED) 572 { 573 root = HKEY_CURRENT_USER; 574 strcpyW(keypath, szUserFeatures); 575 strcatW( keypath, squashed_pc ); 576 } 577 else 578 { 579 if (!szUserSid) 580 { 581 if (!(usersid = get_user_sid())) 582 { 583 ERR("Failed to retrieve user SID\n"); 584 return ERROR_FUNCTION_FAILED; 585 } 586 szUserSid = usersid; 587 } 588 sprintfW( keypath, szInstaller_LocalManagedFeat_fmt, szUserSid, squashed_pc ); 589 LocalFree(usersid); 590 } 591 if (create) return RegCreateKeyExW(root, keypath, 0, NULL, 0, access, NULL, key, NULL); 592 return RegOpenKeyExW(root, keypath, 0, access, key); 593 } 594 595 UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct) 596 { 597 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 598 599 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 600 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 601 602 strcpyW(keypath, szUserFeatures); 603 strcatW( keypath, squashed_pc ); 604 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath); 605 } 606 607 static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create) 608 { 609 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 610 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 611 612 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 613 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 614 615 strcpyW(keypath, szInstaller_Features); 616 strcatW( keypath, squashed_pc ); 617 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); 620 } 621 622 UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, 623 HKEY *key, BOOL create) 624 { 625 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 626 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200], *usersid = NULL; 627 628 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 629 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 630 631 if (context == MSIINSTALLCONTEXT_MACHINE) 632 { 633 sprintfW( keypath, szUserDataFeatures_fmt, szLocalSid, squashed_pc ); 634 } 635 else 636 { 637 if (!szUserSid) 638 { 639 if (!(usersid = get_user_sid())) 640 { 641 ERR("Failed to retrieve user SID\n"); 642 return ERROR_FUNCTION_FAILED; 643 } 644 szUserSid = usersid; 645 } 646 sprintfW( keypath, szUserDataFeatures_fmt, szUserSid, squashed_pc ); 647 LocalFree(usersid); 648 } 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); 651 } 652 653 UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY *key, BOOL create) 654 { 655 WCHAR squashed_cc[SQUASHED_GUID_SIZE], keypath[0x200]; 656 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 657 UINT ret; 658 659 if (!squash_guid( szComponent, squashed_cc)) return ERROR_FUNCTION_FAILED; 660 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_cc)); 661 662 strcpyW(keypath, szUserComponents); 663 strcatW( keypath, squashed_cc ); 664 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; 668 669 strcpyW(keypath, szInstaller_Components); 670 strcatW( keypath, squashed_cc ); 671 return RegOpenKeyExW( HKEY_LOCAL_MACHINE, keypath, 0, access, key ); 672 } 673 674 UINT MSIREG_OpenUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid, HKEY *key, BOOL create) 675 { 676 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 677 WCHAR *usersid, squashed_comp[SQUASHED_GUID_SIZE], keypath[0x200]; 678 679 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED; 680 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp)); 681 682 if (!szUserSid) 683 { 684 if (!(usersid = get_user_sid())) 685 { 686 ERR("Failed to retrieve user SID\n"); 687 return ERROR_FUNCTION_FAILED; 688 } 689 sprintfW( keypath, szUserDataComp_fmt, usersid, squashed_comp ); 690 LocalFree(usersid); 691 } 692 else 693 sprintfW( keypath, szUserDataComp_fmt, szUserSid, squashed_comp ); 694 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); 697 } 698 699 UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid) 700 { 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; 705 706 if (!squash_guid( szComponent, squashed_comp )) return ERROR_FUNCTION_FAILED; 707 TRACE("%s squashed %s\n", debugstr_w(szComponent), debugstr_w(squashed_comp)); 708 709 if (!szUserSid) 710 { 711 if (!(usersid = get_user_sid())) 712 { 713 ERR("Failed to retrieve user SID\n"); 714 return ERROR_FUNCTION_FAILED; 715 } 716 sprintfW(keypath, szUserDataComponents_fmt, usersid); 717 LocalFree(usersid); 718 } 719 else 720 sprintfW(keypath, szUserDataComponents_fmt, szUserSid); 721 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; 726 } 727 728 UINT MSIREG_OpenUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create) 729 { 730 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 731 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 732 733 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 734 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 735 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 741 { 742 if (!(usersid = get_user_sid())) 743 { 744 ERR("Failed to retrieve user SID\n"); 745 return ERROR_FUNCTION_FAILED; 746 } 747 sprintfW( keypath, szUserDataProd_fmt, usersid, squashed_pc ); 748 LocalFree(usersid); 749 } 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); 752 } 753 754 UINT MSIREG_OpenUserDataPatchKey(LPCWSTR szPatch, MSIINSTALLCONTEXT dwContext, HKEY *key, BOOL create) 755 { 756 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 757 WCHAR *usersid, squashed_patch[SQUASHED_GUID_SIZE], keypath[0x200]; 758 759 if (!squash_guid( szPatch, squashed_patch )) return ERROR_FUNCTION_FAILED; 760 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_patch)); 761 762 if (dwContext == MSIINSTALLCONTEXT_MACHINE) 763 sprintfW( keypath, szUserDataPatch_fmt, szLocalSid, squashed_patch ); 764 else 765 { 766 if (!(usersid = get_user_sid())) 767 { 768 ERR("Failed to retrieve user SID\n"); 769 return ERROR_FUNCTION_FAILED; 770 } 771 sprintfW( keypath, szUserDataPatch_fmt, usersid, squashed_patch ); 772 LocalFree(usersid); 773 } 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); 776 } 777 778 UINT MSIREG_DeleteUserDataPatchKey(LPCWSTR patch, MSIINSTALLCONTEXT context) 779 { 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; 784 785 if (!squash_guid( patch, squashed_patch )) return ERROR_FUNCTION_FAILED; 786 TRACE("%s squashed %s\n", debugstr_w(patch), debugstr_w(squashed_patch)); 787 788 if (context == MSIINSTALLCONTEXT_MACHINE) 789 sprintfW(keypath, szUserDataPatches_fmt, szLocalSid); 790 else 791 { 792 if (!(usersid = get_user_sid())) 793 { 794 ERR("Failed to retrieve user SID\n"); 795 return ERROR_FUNCTION_FAILED; 796 } 797 sprintfW(keypath, szUserDataPatches_fmt, usersid); 798 LocalFree(usersid); 799 } 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; 804 } 805 806 UINT MSIREG_OpenUserDataProductPatchesKey(LPCWSTR product, MSIINSTALLCONTEXT context, HKEY *key, BOOL create) 807 { 808 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 809 WCHAR *usersid, squashed_product[SQUASHED_GUID_SIZE], keypath[0x200]; 810 811 if (!squash_guid( product, squashed_product )) return ERROR_FUNCTION_FAILED; 812 TRACE("%s squashed %s\n", debugstr_w(product), debugstr_w(squashed_product)); 813 814 if (context == MSIINSTALLCONTEXT_MACHINE) 815 sprintfW( keypath, szUserDataProductPatches_fmt, szLocalSid, squashed_product ); 816 else 817 { 818 if (!(usersid = get_user_sid())) 819 { 820 ERR("Failed to retrieve user SID\n"); 821 return ERROR_FUNCTION_FAILED; 822 } 823 sprintfW( keypath, szUserDataProductPatches_fmt, usersid, squashed_product ); 824 LocalFree(usersid); 825 } 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); 828 } 829 830 UINT MSIREG_OpenInstallProps(LPCWSTR szProduct, MSIINSTALLCONTEXT dwContext, LPCWSTR szUserSid, HKEY *key, BOOL create) 831 { 832 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 833 WCHAR *usersid, squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 834 835 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 836 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 837 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 843 { 844 if (!(usersid = get_user_sid())) 845 { 846 ERR("Failed to retrieve user SID\n"); 847 return ERROR_FUNCTION_FAILED; 848 } 849 sprintfW( keypath, szInstallProperties_fmt, usersid, squashed_pc ); 850 LocalFree(usersid); 851 } 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); 854 } 855 856 UINT MSIREG_DeleteUserDataProductKey(LPCWSTR szProduct, MSIINSTALLCONTEXT context) 857 { 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; 862 863 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 864 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 865 866 if (context == MSIINSTALLCONTEXT_MACHINE) 867 sprintfW(keypath, szUserDataProducts_fmt, szLocalSid); 868 else 869 { 870 if (!(usersid = get_user_sid())) 871 { 872 ERR("Failed to retrieve user SID\n"); 873 return ERROR_FUNCTION_FAILED; 874 } 875 sprintfW(keypath, szUserDataProducts_fmt, usersid); 876 LocalFree(usersid); 877 } 878 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; 883 } 884 885 UINT MSIREG_DeleteProductKey(LPCWSTR szProduct) 886 { 887 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 888 WCHAR squashed_pc[SQUASHED_GUID_SIZE]; 889 HKEY hkey; 890 LONG r; 891 892 if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; 893 TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); 894 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; 899 } 900 901 UINT MSIREG_OpenPatchesKey(LPCWSTR szPatch, HKEY *key, BOOL create) 902 { 903 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 904 WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; 905 906 if (!squash_guid( szPatch, squashed_pc )) return ERROR_FUNCTION_FAILED; 907 TRACE("%s squashed %s\n", debugstr_w(szPatch), debugstr_w(squashed_pc)); 908 909 sprintfW( keypath, szInstaller_Patches, squashed_pc ); 910 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); 913 } 914 915 UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create) 916 { 917 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 918 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200]; 919 920 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED; 921 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc)); 922 923 strcpyW(keypath, szInstaller_UpgradeCodes); 924 strcatW( keypath, squashed_uc ); 925 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); 928 } 929 930 UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create) 931 { 932 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200]; 933 934 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED; 935 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc)); 936 937 strcpyW(keypath, szInstaller_UserUpgradeCodes); 938 strcatW( keypath, squashed_uc ); 939 940 if (create) return RegCreateKeyW(HKEY_CURRENT_USER, keypath, key); 941 return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key); 942 } 943 944 UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code ) 945 { 946 WCHAR squashed_code[SQUASHED_GUID_SIZE]; 947 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 948 HKEY hkey; 949 LONG ret; 950 951 if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED; 952 TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) ); 953 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; 958 } 959 960 UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode) 961 { 962 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200]; 963 964 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED; 965 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc)); 966 967 strcpyW(keypath, szInstaller_UserUpgradeCodes); 968 strcatW( keypath, squashed_uc ); 969 return RegDeleteTreeW(HKEY_CURRENT_USER, keypath); 970 } 971 972 UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode) 973 { 974 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 975 WCHAR squashed_pc[SQUASHED_GUID_SIZE]; 976 HKEY hkey; 977 LONG r; 978 979 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED; 980 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc)); 981 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; 986 } 987 988 UINT MSIREG_DeleteLocalClassesFeaturesKey(LPCWSTR szProductCode) 989 { 990 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 991 WCHAR squashed_pc[SQUASHED_GUID_SIZE]; 992 HKEY hkey; 993 LONG r; 994 995 if (!squash_guid( szProductCode, squashed_pc )) return ERROR_FUNCTION_FAILED; 996 TRACE("%s squashed %s\n", debugstr_w(szProductCode), debugstr_w(squashed_pc)); 997 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; 1002 } 1003 1004 UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY *key, BOOL create) 1005 { 1006 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 1007 WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200]; 1008 1009 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED; 1010 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc)); 1011 1012 strcpyW(keypath, szInstaller_ClassesUpgradeCode); 1013 strcatW( keypath, squashed_uc ); 1014 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); 1017 } 1018 1019 UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode) 1020 { 1021 REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; 1022 WCHAR squashed_uc[SQUASHED_GUID_SIZE]; 1023 HKEY hkey; 1024 LONG r; 1025 1026 if (!squash_guid( szUpgradeCode, squashed_uc )) return ERROR_FUNCTION_FAILED; 1027 TRACE("%s squashed %s\n", debugstr_w(szUpgradeCode), debugstr_w(squashed_uc)); 1028 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; 1033 } 1034 1035 /************************************************************************* 1036 * MsiDecomposeDescriptorW [MSI.@] 1037 * 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] '<' 1042 * 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 1049 * 1050 * RETURNS 1051 * ERROR_SUCCESS if everything worked correctly 1052 * ERROR_INVALID_PARAMETER if the descriptor was invalid 1053 * 1054 */ 1055 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct, 1056 LPWSTR szFeature, LPWSTR szComponent, LPDWORD pUsed ) 1057 { 1058 UINT len; 1059 const WCHAR *p; 1060 GUID product, component; 1061 1062 TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct, 1063 szFeature, szComponent, pUsed); 1064 1065 if (!decode_base85_guid( szDescriptor, &product )) 1066 return ERROR_INVALID_PARAMETER; 1067 1068 TRACE("product %s\n", debugstr_guid( &product )); 1069 1070 if (!(p = strchrW( &szDescriptor[20], '>' ))) 1071 p = strchrW( &szDescriptor[20], '<' ); 1072 if (!p) 1073 return ERROR_INVALID_PARAMETER; 1074 1075 len = (p - &szDescriptor[20]); 1076 if( len > MAX_FEATURE_CHARS ) 1077 return ERROR_INVALID_PARAMETER; 1078 1079 TRACE("feature %s\n", debugstr_wn( &szDescriptor[20], len )); 1080 1081 if (*p == '>') 1082 { 1083 if (!decode_base85_guid( p+1, &component )) 1084 return ERROR_INVALID_PARAMETER; 1085 TRACE( "component %s\n", debugstr_guid(&component) ); 1086 } 1087 1088 if (szProduct) 1089 StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 ); 1090 if (szComponent) 1091 { 1092 if (*p == '>') 1093 StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 ); 1094 else 1095 szComponent[0] = 0; 1096 } 1097 if (szFeature) 1098 { 1099 memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) ); 1100 szFeature[len] = 0; 1101 } 1102 1103 len = p - szDescriptor + 1; 1104 if (*p == '>') len += 20; 1105 1106 TRACE("length = %d\n", len); 1107 if (pUsed) *pUsed = len; 1108 1109 return ERROR_SUCCESS; 1110 } 1111 1112 UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct, 1113 LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed ) 1114 { 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; 1120 1121 TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct, 1122 szFeature, szComponent, pUsed); 1123 1124 str = strdupAtoW( szDescriptor ); 1125 if( szDescriptor && !str ) 1126 return ERROR_OUTOFMEMORY; 1127 1128 if (szProduct) 1129 p = product; 1130 if (szFeature) 1131 f = feature; 1132 if (szComponent) 1133 c = component; 1134 1135 r = MsiDecomposeDescriptorW( str, p, f, c, pUsed ); 1136 1137 if (r == ERROR_SUCCESS) 1138 { 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 ); 1145 } 1146 1147 msi_free( str ); 1148 1149 return r; 1150 } 1151 1152 UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid) 1153 { 1154 DWORD r; 1155 WCHAR szwGuid[GUID_SIZE]; 1156 1157 TRACE("%d %p\n", index, lpguid); 1158 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); 1164 1165 return r; 1166 } 1167 1168 UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid) 1169 { 1170 TRACE("%d %p\n", index, lpguid); 1171 1172 if (NULL == lpguid) 1173 return ERROR_INVALID_PARAMETER; 1174 1175 return MsiEnumProductsExW( NULL, szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid, 1176 NULL, NULL, NULL ); 1177 } 1178 1179 UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, 1180 LPSTR szFeature, LPSTR szParent) 1181 { 1182 DWORD r; 1183 WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE]; 1184 LPWSTR szwProduct = NULL; 1185 1186 TRACE("%s %d %p %p\n", debugstr_a(szProduct), index, szFeature, szParent); 1187 1188 if( szProduct ) 1189 { 1190 szwProduct = strdupAtoW( szProduct ); 1191 if( !szwProduct ) 1192 return ERROR_OUTOFMEMORY; 1193 } 1194 1195 r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent); 1196 if( r == ERROR_SUCCESS ) 1197 { 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); 1202 } 1203 1204 msi_free( szwProduct); 1205 1206 return r; 1207 } 1208 1209 UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, 1210 LPWSTR szFeature, LPWSTR szParent) 1211 { 1212 HKEY hkeyProduct = 0; 1213 DWORD r, sz; 1214 1215 TRACE("%s %d %p %p\n", debugstr_w(szProduct), index, szFeature, szParent); 1216 1217 if( !szProduct ) 1218 return ERROR_INVALID_PARAMETER; 1219 1220 r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE); 1221 if( r != ERROR_SUCCESS ) 1222 return ERROR_NO_MORE_ITEMS; 1223 1224 sz = GUID_SIZE; 1225 r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL); 1226 RegCloseKey(hkeyProduct); 1227 1228 return r; 1229 } 1230 1231 UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid) 1232 { 1233 DWORD r; 1234 WCHAR szwGuid[GUID_SIZE]; 1235 1236 TRACE("%u, %p\n", index, lpguid); 1237 1238 if (!lpguid) return ERROR_INVALID_PARAMETER; 1239 1240 r = MsiEnumComponentsW(index, szwGuid); 1241 if( r == ERROR_SUCCESS ) 1242 WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); 1243 1244 return r; 1245 } 1246 1247 UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid) 1248 { 1249 TRACE("%u, %p\n", index, lpguid); 1250 1251 if (!lpguid) return ERROR_INVALID_PARAMETER; 1252 1253 return MsiEnumComponentsExW( szAllSid, MSIINSTALLCONTEXT_ALL, index, lpguid, NULL, NULL, NULL ); 1254 } 1255 1256 UINT WINAPI MsiEnumComponentsExA( LPCSTR user_sid, DWORD ctx, DWORD index, CHAR guid[39], 1257 MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len ) 1258 { 1259 UINT r; 1260 WCHAR *user_sidW = NULL, *sidW = NULL, guidW[GUID_SIZE]; 1261 1262 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_a(user_sid), ctx, index, guid, installed_ctx, 1263 sid, sid_len); 1264 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) ))) 1268 { 1269 msi_free( user_sidW ); 1270 return ERROR_OUTOFMEMORY; 1271 } 1272 r = MsiEnumComponentsExW( user_sidW, ctx, index, guidW, installed_ctx, sidW, sid_len ); 1273 if (r == ERROR_SUCCESS) 1274 { 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 ); 1277 } 1278 msi_free( user_sidW ); 1279 msi_free( sidW ); 1280 return r; 1281 } 1282 1283 static UINT fetch_machine_component( DWORD ctx, DWORD index, DWORD *idx, WCHAR guid[39], 1284 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len ) 1285 { 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; 1296 1297 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, componentsW, 0, access, &key_components )) 1298 return ERROR_NO_MORE_ITEMS; 1299 1300 len_component = sizeof(component)/sizeof(component[0]); 1301 while (!RegEnumKeyExW( key_components, i, component, &len_component, NULL, NULL, NULL, NULL )) 1302 { 1303 if (*idx == index) goto found; 1304 (*idx)++; 1305 len_component = sizeof(component)/sizeof(component[0]); 1306 i++; 1307 } 1308 RegCloseKey( key_components ); 1309 return ERROR_NO_MORE_ITEMS; 1310 1311 found: 1312 if (sid_len) 1313 { 1314 if (*sid_len < 1) 1315 { 1316 *sid_len = 1; 1317 r = ERROR_MORE_DATA; 1318 } 1319 else if (sid) 1320 { 1321 *sid_len = 0; 1322 sid[0] = 0; 1323 } 1324 } 1325 if (guid) unsquash_guid( component, guid ); 1326 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE; 1327 RegCloseKey( key_components ); 1328 return r; 1329 } 1330 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 ) 1334 { 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; 1345 1346 if (ctx == MSIINSTALLCONTEXT_USERMANAGED) /* FIXME: where to find these? */ 1347 return ERROR_NO_MORE_ITEMS; 1348 1349 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, userdataW, 0, access, &key_users )) 1350 return ERROR_NO_MORE_ITEMS; 1351 1352 len_user = sizeof(user)/sizeof(user[0]); 1353 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL )) 1354 { 1355 if ((strcmpW( usersid, szAllSid ) && strcmpW( usersid, user )) || 1356 !strcmpW( szLocalSid, user )) 1357 { 1358 i++; 1359 len_user = sizeof(user)/sizeof(user[0]); 1360 continue; 1361 } 1362 strcpyW( path, user ); 1363 strcatW( path, componentsW ); 1364 if (RegOpenKeyExW( key_users, path, 0, access, &key_components )) 1365 { 1366 i++; 1367 len_user = sizeof(user)/sizeof(user[0]); 1368 continue; 1369 } 1370 len_component = sizeof(component)/sizeof(component[0]); 1371 while (!RegEnumKeyExW( key_components, j, component, &len_component, NULL, NULL, NULL, NULL )) 1372 { 1373 if (*idx == index) goto found; 1374 (*idx)++; 1375 len_component = sizeof(component)/sizeof(component[0]); 1376 j++; 1377 } 1378 RegCloseKey( key_components ); 1379 len_user = sizeof(user)/sizeof(user[0]); 1380 i++; 1381 } 1382 RegCloseKey( key_users ); 1383 return ERROR_NO_MORE_ITEMS; 1384 1385 found: 1386 if (sid_len) 1387 { 1388 if (*sid_len < len_user + 1) 1389 { 1390 *sid_len = len_user + 1; 1391 r = ERROR_MORE_DATA; 1392 } 1393 else if (sid) 1394 { 1395 *sid_len = len_user; 1396 strcpyW( sid, user ); 1397 } 1398 } 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; 1404 } 1405 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 ) 1408 { 1409 UINT r = ERROR_NO_MORE_ITEMS; 1410 WCHAR *user = NULL; 1411 1412 if (!usersid) 1413 { 1414 usersid = user = get_user_sid(); 1415 if (!user) return ERROR_FUNCTION_FAILED; 1416 } 1417 if (ctx & MSIINSTALLCONTEXT_USERMANAGED) 1418 { 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; 1422 } 1423 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED) 1424 { 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; 1428 } 1429 if (ctx & MSIINSTALLCONTEXT_MACHINE) 1430 { 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; 1434 } 1435 1436 done: 1437 LocalFree( user ); 1438 return r; 1439 } 1440 1441 UINT WINAPI MsiEnumComponentsExW( LPCWSTR user_sid, DWORD ctx, DWORD index, WCHAR guid[39], 1442 MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len ) 1443 { 1444 UINT r; 1445 DWORD idx = 0; 1446 static DWORD last_index; 1447 1448 TRACE("%s, %u, %u, %p, %p, %p, %p\n", debugstr_w(user_sid), ctx, index, guid, installed_ctx, 1449 sid, sid_len); 1450 1451 if ((sid && !sid_len) || !ctx || (user_sid && ctx == MSIINSTALLCONTEXT_MACHINE)) 1452 return ERROR_INVALID_PARAMETER; 1453 1454 if (index && index - last_index != 1) 1455 return ERROR_INVALID_PARAMETER; 1456 1457 if (!index) last_index = 0; 1458 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; 1464 1465 return r; 1466 } 1467 1468 UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct) 1469 { 1470 DWORD r; 1471 WCHAR szwProduct[GUID_SIZE]; 1472 LPWSTR szwComponent = NULL; 1473 1474 TRACE("%s %d %p\n", debugstr_a(szComponent), index, szProduct); 1475 1476 if ( !szProduct ) 1477 return ERROR_INVALID_PARAMETER; 1478 1479 if( szComponent ) 1480 { 1481 szwComponent = strdupAtoW( szComponent ); 1482 if( !szwComponent ) 1483 return ERROR_OUTOFMEMORY; 1484 } 1485 1486 r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct); 1487 if( r == ERROR_SUCCESS ) 1488 { 1489 WideCharToMultiByte(CP_ACP, 0, szwProduct, -1, 1490 szProduct, GUID_SIZE, NULL, NULL); 1491 } 1492 1493 msi_free( szwComponent); 1494 1495 return r; 1496 } 1497 1498 UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) 1499 { 1500 HKEY hkeyComp = 0; 1501 DWORD r, sz; 1502 WCHAR szValName[SQUASHED_GUID_SIZE]; 1503 1504 TRACE("%s %d %p\n", debugstr_w(szComponent), index, szProduct); 1505 1506 if (!szComponent || !*szComponent || !szProduct) 1507 return ERROR_INVALID_PARAMETER; 1508 1509 if (MSIREG_OpenUserDataComponentKey(szComponent, NULL, &hkeyComp, FALSE) != ERROR_SUCCESS && 1510 MSIREG_OpenUserDataComponentKey(szComponent, szLocalSid, &hkeyComp, FALSE) != ERROR_SUCCESS) 1511 return ERROR_UNKNOWN_COMPONENT; 1512 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) 1517 { 1518 RegCloseKey(hkeyComp); 1519 1520 if (index != 0) 1521 return ERROR_INVALID_PARAMETER; 1522 1523 return ERROR_UNKNOWN_COMPONENT; 1524 } 1525 1526 sz = SQUASHED_GUID_SIZE; 1527 r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL); 1528 if( r == ERROR_SUCCESS ) 1529 { 1530 unsquash_guid(szValName, szProduct); 1531 TRACE("-> %s\n", debugstr_w(szProduct)); 1532 } 1533 RegCloseKey(hkeyComp); 1534 return r; 1535 } 1536 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) 1540 { 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; 1544 } 1545 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) 1549 { 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; 1553 } 1554 1555 static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, 1556 awstring *lpQualBuf, LPDWORD pcchQual, 1557 awstring *lpAppBuf, LPDWORD pcchAppBuf ) 1558 { 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; 1563 1564 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex, 1565 lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf); 1566 1567 if (!szComponent) 1568 return ERROR_INVALID_PARAMETER; 1569 1570 r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE ); 1571 if (r != ERROR_SUCCESS) 1572 return ERROR_UNKNOWN_COMPONENT; 1573 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; 1580 1581 val_max = 0x10; 1582 r = ERROR_OUTOFMEMORY; 1583 val = msi_alloc( val_max ); 1584 if (!val) 1585 goto end; 1586 1587 /* loop until we allocate enough memory */ 1588 while (1) 1589 { 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; 1598 1599 if (type != REG_MULTI_SZ) 1600 { 1601 ERR("component data has wrong type (%d)\n", type); 1602 goto end; 1603 } 1604 1605 r = ERROR_OUTOFMEMORY; 1606 if (name_sz + 1 >= name_max) 1607 { 1608 name_max *= 2; 1609 msi_free( name ); 1610 name = msi_alloc( name_max * sizeof (WCHAR) ); 1611 if (!name) 1612 goto end; 1613 continue; 1614 } 1615 if (val_sz > val_max) 1616 { 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; 1623 } 1624 ERR("should be enough data, but isn't %d %d\n", name_sz, val_sz ); 1625 goto end; 1626 } 1627 1628 ofs = 0; 1629 r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs ); 1630 if (r != ERROR_SUCCESS) 1631 goto end; 1632 1633 TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs)); 1634 1635 r = msi_strcpy_to_awstring( name, -1, lpQualBuf, pcchQual ); 1636 r2 = msi_strcpy_to_awstring( val+ofs, -1, lpAppBuf, pcchAppBuf ); 1637 1638 if (r2 != ERROR_SUCCESS) 1639 r = r2; 1640 1641 end: 1642 msi_free(val); 1643 msi_free(name); 1644 RegCloseKey(key); 1645 return r; 1646 } 1647 1648 /************************************************************************* 1649 * MsiEnumComponentQualifiersA [MSI.@] 1650 */ 1651 UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex, 1652 LPSTR lpQualifierBuf, LPDWORD pcchQualifierBuf, 1653 LPSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf ) 1654 { 1655 awstring qual, appdata; 1656 LPWSTR comp; 1657 UINT r; 1658 1659 TRACE("%s %08x %p %p %p %p\n", debugstr_a(szComponent), iIndex, 1660 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, 1661 pcchApplicationDataBuf); 1662 1663 comp = strdupAtoW( szComponent ); 1664 if (szComponent && !comp) 1665 return ERROR_OUTOFMEMORY; 1666 1667 qual.unicode = FALSE; 1668 qual.str.a = lpQualifierBuf; 1669 1670 appdata.unicode = FALSE; 1671 appdata.str.a = lpApplicationDataBuf; 1672 1673 r = MSI_EnumComponentQualifiers( comp, iIndex, 1674 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf ); 1675 msi_free( comp ); 1676 return r; 1677 } 1678 1679 /************************************************************************* 1680 * MsiEnumComponentQualifiersW [MSI.@] 1681 */ 1682 UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex, 1683 LPWSTR lpQualifierBuf, LPDWORD pcchQualifierBuf, 1684 LPWSTR lpApplicationDataBuf, LPDWORD pcchApplicationDataBuf ) 1685 { 1686 awstring qual, appdata; 1687 1688 TRACE("%s %08x %p %p %p %p\n", debugstr_w(szComponent), iIndex, 1689 lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, 1690 pcchApplicationDataBuf); 1691 1692 qual.unicode = TRUE; 1693 qual.str.w = lpQualifierBuf; 1694 1695 appdata.unicode = TRUE; 1696 appdata.str.w = lpApplicationDataBuf; 1697 1698 return MSI_EnumComponentQualifiers( szComponent, iIndex, 1699 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf ); 1700 } 1701 1702 /************************************************************************* 1703 * MsiEnumRelatedProductsW [MSI.@] 1704 * 1705 */ 1706 UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, 1707 DWORD iProductIndex, LPWSTR lpProductBuf) 1708 { 1709 UINT r; 1710 HKEY hkey; 1711 WCHAR szKeyName[SQUASHED_GUID_SIZE]; 1712 DWORD dwSize = sizeof(szKeyName)/sizeof(szKeyName[0]); 1713 1714 TRACE("%s %u %u %p\n", debugstr_w(szUpgradeCode), dwReserved, 1715 iProductIndex, lpProductBuf); 1716 1717 if (NULL == szUpgradeCode) 1718 return ERROR_INVALID_PARAMETER; 1719 if (NULL == lpProductBuf) 1720 return ERROR_INVALID_PARAMETER; 1721 1722 r = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE); 1723 if (r != ERROR_SUCCESS) 1724 return ERROR_NO_MORE_ITEMS; 1725 1726 r = RegEnumValueW(hkey, iProductIndex, szKeyName, &dwSize, NULL, NULL, NULL, NULL); 1727 if( r == ERROR_SUCCESS ) 1728 unsquash_guid(szKeyName, lpProductBuf); 1729 RegCloseKey(hkey); 1730 1731 return r; 1732 } 1733 1734 /************************************************************************* 1735 * MsiEnumRelatedProductsA [MSI.@] 1736 * 1737 */ 1738 UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, 1739 DWORD iProductIndex, LPSTR lpProductBuf) 1740 { 1741 LPWSTR szwUpgradeCode = NULL; 1742 WCHAR productW[GUID_SIZE]; 1743 UINT r; 1744 1745 TRACE("%s %u %u %p\n", debugstr_a(szUpgradeCode), dwReserved, 1746 iProductIndex, lpProductBuf); 1747 1748 if (szUpgradeCode) 1749 { 1750 szwUpgradeCode = strdupAtoW( szUpgradeCode ); 1751 if( !szwUpgradeCode ) 1752 return ERROR_OUTOFMEMORY; 1753 } 1754 1755 r = MsiEnumRelatedProductsW( szwUpgradeCode, dwReserved, 1756 iProductIndex, productW ); 1757 if (r == ERROR_SUCCESS) 1758 { 1759 WideCharToMultiByte( CP_ACP, 0, productW, GUID_SIZE, 1760 lpProductBuf, GUID_SIZE, NULL, NULL ); 1761 } 1762 msi_free( szwUpgradeCode); 1763 return r; 1764 } 1765 1766 /*********************************************************************** 1767 * MsiEnumPatchesExA [MSI.@] 1768 */ 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) 1773 { 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; 1781 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); 1786 1787 if (szTargetUserSid && !pcchTargetUserSid) 1788 return ERROR_INVALID_PARAMETER; 1789 1790 if (szProductCode) prodcode = strdupAtoW(szProductCode); 1791 if (szUserSid) usersid = strdupAtoW(szUserSid); 1792 1793 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex, 1794 patch, targprod, pdwTargetProductContext, 1795 NULL, &len); 1796 if (r != ERROR_SUCCESS) 1797 goto done; 1798 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); 1803 1804 if (!szTargetUserSid) 1805 { 1806 if (pcchTargetUserSid) 1807 *pcchTargetUserSid = len; 1808 1809 goto done; 1810 } 1811 1812 targsid = msi_alloc(++len * sizeof(WCHAR)); 1813 if (!targsid) 1814 { 1815 r = ERROR_OUTOFMEMORY; 1816 goto done; 1817 } 1818 1819 r = MsiEnumPatchesExW(prodcode, usersid, dwContext, dwFilter, dwIndex, 1820 patch, targprod, pdwTargetProductContext, 1821 targsid, &len); 1822 if (r != ERROR_SUCCESS || !szTargetUserSid) 1823 goto done; 1824 1825 WideCharToMultiByte(CP_ACP, 0, targsid, -1, szTargetUserSid, 1826 *pcchTargetUserSid, NULL, NULL); 1827 1828 len = lstrlenW(targsid); 1829 if (*pcchTargetUserSid < len + 1) 1830 { 1831 r = ERROR_MORE_DATA; 1832 *pcchTargetUserSid = len * sizeof(WCHAR); 1833 } 1834 else 1835 *pcchTargetUserSid = len; 1836 1837 done: 1838 msi_free(prodcode); 1839 msi_free(usersid); 1840 msi_free(targsid); 1841 1842 return r; 1843 } 1844 1845 static UINT msi_get_patch_state(LPCWSTR prodcode, LPCWSTR usersid, 1846 MSIINSTALLCONTEXT context, 1847 LPWSTR patch, MSIPATCHSTATE *state) 1848 { 1849 DWORD type, val, size; 1850 HKEY prod, hkey = 0; 1851 HKEY udpatch = 0; 1852 LONG res; 1853 UINT r = ERROR_NO_MORE_ITEMS; 1854 1855 *state = MSIPATCHSTATE_INVALID; 1856 1857 r = MSIREG_OpenUserDataProductKey(prodcode, context, 1858 usersid, &prod, FALSE); 1859 if (r != ERROR_SUCCESS) 1860 return ERROR_NO_MORE_ITEMS; 1861 1862 res = RegOpenKeyExW(prod, szPatches, 0, KEY_READ, &hkey); 1863 if (res != ERROR_SUCCESS) 1864 goto done; 1865 1866 res = RegOpenKeyExW(hkey, patch, 0, KEY_READ, &udpatch); 1867 if (res != ERROR_SUCCESS) 1868 goto done; 1869 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) 1874 { 1875 r = ERROR_BAD_CONFIGURATION; 1876 goto done; 1877 } 1878 1879 *state = val; 1880 r = ERROR_SUCCESS; 1881 1882 done: 1883 RegCloseKey(udpatch); 1884 RegCloseKey(hkey); 1885 RegCloseKey(prod); 1886 1887 return r; 1888 } 1889 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) 1894 { 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; 1902 1903 if (MSIREG_OpenProductKey(prodcode, usersid, context, 1904 &prod, FALSE) != ERROR_SUCCESS) 1905 return ERROR_NO_MORE_ITEMS; 1906 1907 size = 0; 1908 res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, NULL, 1909 &size); 1910 if (res != ERROR_SUCCESS) 1911 goto done; 1912 1913 if (type != REG_MULTI_SZ) 1914 { 1915 r = ERROR_BAD_CONFIGURATION; 1916 goto done; 1917 } 1918 1919 patches = msi_alloc(size); 1920 if (!patches) 1921 { 1922 r = ERROR_OUTOFMEMORY; 1923 goto done; 1924 } 1925 1926 res = RegGetValueW(prod, szPatches, szPatches, RRF_RT_ANY, &type, 1927 patches, &size); 1928 if (res != ERROR_SUCCESS) 1929 goto done; 1930 1931 for (ptr = patches; *ptr && r == ERROR_NO_MORE_ITEMS; ptr += lstrlenW(ptr) + 1) 1932 { 1933 if (!unsquash_guid(ptr, patch)) 1934 { 1935 r = ERROR_BAD_CONFIGURATION; 1936 goto done; 1937 } 1938 1939 size = 0; 1940 res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ, 1941 &type, NULL, &size); 1942 if (res != ERROR_SUCCESS) 1943 continue; 1944 1945 if (transforms) 1946 { 1947 *transforms = msi_alloc(size); 1948 if (!*transforms) 1949 { 1950 r = ERROR_OUTOFMEMORY; 1951 goto done; 1952 } 1953 1954 res = RegGetValueW(prod, szPatches, ptr, RRF_RT_REG_SZ, 1955 &type, *transforms, &size); 1956 if (res != ERROR_SUCCESS) 1957 continue; 1958 } 1959 1960 if (context == MSIINSTALLCONTEXT_USERMANAGED) 1961 { 1962 if (!(filter & MSIPATCHSTATE_APPLIED)) 1963 { 1964 temp = msi_get_patch_state(prodcode, usersid, context, 1965 ptr, &state); 1966 if (temp == ERROR_BAD_CONFIGURATION) 1967 { 1968 r = ERROR_BAD_CONFIGURATION; 1969 goto done; 1970 } 1971 1972 if (temp != ERROR_SUCCESS || !(filter & state)) 1973 continue; 1974 } 1975 } 1976 else if (context == MSIINSTALLCONTEXT_USERUNMANAGED) 1977 { 1978 if (!(filter & MSIPATCHSTATE_APPLIED)) 1979 { 1980 temp = msi_get_patch_state(prodcode, usersid, context, 1981 ptr, &state); 1982 if (temp == ERROR_BAD_CONFIGURATION) 1983 { 1984 r = ERROR_BAD_CONFIGURATION; 1985 goto done; 1986 } 1987 1988 if (temp != ERROR_SUCCESS || !(filter & state)) 1989 continue; 1990 } 1991 else 1992 { 1993 temp = MSIREG_OpenUserDataPatchKey(patch, context, 1994 &patchkey, FALSE); 1995 RegCloseKey(patchkey); 1996 if (temp != ERROR_SUCCESS) 1997 continue; 1998 } 1999 } 2000 else if (context == MSIINSTALLCONTEXT_MACHINE) 2001 { 2002 usersid = szEmpty; 2003 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) 2007 { 2008 res = RegGetValueW(patchkey, NULL, szState, RRF_RT_REG_DWORD, 2009 &type, &state, &size); 2010 2011 if (!(filter & state)) 2012 res = ERROR_NO_MORE_ITEMS; 2013 2014 RegCloseKey(patchkey); 2015 } 2016 2017 RegCloseKey(localpatch); 2018 RegCloseKey(localprod); 2019 2020 if (res != ERROR_SUCCESS) 2021 continue; 2022 } 2023 2024 if (*idx < index) 2025 { 2026 (*idx)++; 2027 continue; 2028 } 2029 2030 r = ERROR_SUCCESS; 2031 if (targetprod) 2032 lstrcpyW(targetprod, prodcode); 2033 2034 if (targetctx) 2035 *targetctx = context; 2036 2037 if (targetsid) 2038 { 2039 lstrcpynW(targetsid, usersid, *sidsize); 2040 if (lstrlenW(usersid) >= *sidsize) 2041 r = ERROR_MORE_DATA; 2042 } 2043 2044 if (sidsize) 2045 { 2046 *sidsize = lstrlenW(usersid); 2047 if (!targetsid) 2048 *sidsize *= sizeof(WCHAR); 2049 } 2050 } 2051 2052 done: 2053 RegCloseKey(prod); 2054 msi_free(patches); 2055 2056 return r; 2057 } 2058 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) 2064 { 2065 LPWSTR usersid = NULL; 2066 UINT r = ERROR_INVALID_PARAMETER; 2067 2068 if (!szUserSid) 2069 { 2070 szUserSid = usersid = get_user_sid(); 2071 if (!usersid) return ERROR_FUNCTION_FAILED; 2072 } 2073 2074 if (dwContext & MSIINSTALLCONTEXT_USERMANAGED) 2075 { 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; 2084 } 2085 2086 if (dwContext & MSIINSTALLCONTEXT_USERUNMANAGED) 2087 { 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; 2096 } 2097 2098 if (dwContext & MSIINSTALLCONTEXT_MACHINE) 2099 { 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; 2108 } 2109 2110 done: 2111 LocalFree(usersid); 2112 return r; 2113 } 2114 2115 /*********************************************************************** 2116 * MsiEnumPatchesExW [MSI.@] 2117 */ 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) 2122 { 2123 WCHAR squashed_pc[SQUASHED_GUID_SIZE]; 2124 DWORD idx = 0; 2125 UINT r; 2126 2127 static DWORD last_index; 2128 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); 2133 2134 if (!szProductCode || !squash_guid( szProductCode, squashed_pc )) 2135 return ERROR_INVALID_PARAMETER; 2136 2137 if (szUserSid && !strcmpW( szUserSid, szLocalSid )) 2138 return ERROR_INVALID_PARAMETER; 2139 2140 if (dwContext & MSIINSTALLCONTEXT_MACHINE && szUserSid) 2141 return ERROR_INVALID_PARAMETER; 2142 2143 if (dwContext <= MSIINSTALLCONTEXT_NONE || 2144 dwContext > MSIINSTALLCONTEXT_ALL) 2145 return ERROR_INVALID_PARAMETER; 2146 2147 if (dwFilter <= MSIPATCHSTATE_INVALID || dwFilter > MSIPATCHSTATE_ALL) 2148 return ERROR_INVALID_PARAMETER; 2149 2150 if (dwIndex && dwIndex - last_index != 1) 2151 return ERROR_INVALID_PARAMETER; 2152 2153 if (dwIndex == 0) 2154 last_index = 0; 2155 2156 r = msi_enum_patches(szProductCode, szUserSid, dwContext, dwFilter, 2157 dwIndex, &idx, szPatchCode, szTargetProductCode, 2158 pdwTargetProductContext, szTargetUserSid, 2159 pcchTargetUserSid, NULL); 2160 2161 if (r == ERROR_SUCCESS) 2162 last_index = dwIndex; 2163 else 2164 last_index = 0; 2165 2166 return r; 2167 } 2168 2169 /*********************************************************************** 2170 * MsiEnumPatchesA [MSI.@] 2171 */ 2172 UINT WINAPI MsiEnumPatchesA(LPCSTR szProduct, DWORD iPatchIndex, 2173 LPSTR lpPatchBuf, LPSTR lpTransformsBuf, LPDWORD pcchTransformsBuf) 2174 { 2175 LPWSTR product, transforms; 2176 WCHAR patch[GUID_SIZE]; 2177 DWORD len; 2178 UINT r; 2179 2180 TRACE("(%s %d %p %p %p)\n", debugstr_a(szProduct), iPatchIndex, 2181 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf); 2182 2183 if (!szProduct || !lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf) 2184 return ERROR_INVALID_PARAMETER; 2185 2186 product = strdupAtoW(szProduct); 2187 if (!product) 2188 return ERROR_OUTOFMEMORY; 2189 2190 len = *pcchTransformsBuf; 2191 transforms = msi_alloc( len * sizeof(WCHAR) ); 2192 if (!transforms) 2193 { 2194 r = ERROR_OUTOFMEMORY; 2195 goto done; 2196 } 2197 2198 r = MsiEnumPatchesW(product, iPatchIndex, patch, transforms, &len); 2199 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) 2200 goto done; 2201 2202 WideCharToMultiByte(CP_ACP, 0, patch, -1, lpPatchBuf, 2203 GUID_SIZE, NULL, NULL); 2204 2205 if (!WideCharToMultiByte(CP_ACP, 0, transforms, -1, lpTransformsBuf, 2206 *pcchTransformsBuf, NULL, NULL)) 2207 r = ERROR_MORE_DATA; 2208 2209 if (r == ERROR_MORE_DATA) 2210 { 2211 lpTransformsBuf[*pcchTransformsBuf - 1] = '\0'; 2212 *pcchTransformsBuf = len * 2; 2213 } 2214 else 2215 *pcchTransformsBuf = strlen( lpTransformsBuf ); 2216 2217 done: 2218 msi_free(transforms); 2219 msi_free(product); 2220 2221 return r; 2222 } 2223 2224 /*********************************************************************** 2225 * MsiEnumPatchesW [MSI.@] 2226 */ 2227 UINT WINAPI MsiEnumPatchesW(LPCWSTR szProduct, DWORD iPatchIndex, 2228 LPWSTR lpPatchBuf, LPWSTR lpTransformsBuf, LPDWORD pcchTransformsBuf) 2229 { 2230 WCHAR *transforms = NULL, squashed_pc[SQUASHED_GUID_SIZE]; 2231 HKEY prod; 2232 DWORD idx = 0; 2233 UINT r; 2234 2235 TRACE("(%s %d %p %p %p)\n", debugstr_w(szProduct), iPatchIndex, 2236 lpPatchBuf, lpTransformsBuf, pcchTransformsBuf); 2237 2238 if (!szProduct || !squash_guid( szProduct, squashed_pc )) 2239 return ERROR_INVALID_PARAMETER; 2240 2241 if (!lpPatchBuf || !lpTransformsBuf || !pcchTransformsBuf) 2242 return ERROR_INVALID_PARAMETER; 2243 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; 2251 2252 RegCloseKey(prod); 2253 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; 2259 2260 lstrcpynW(lpTransformsBuf, transforms, *pcchTransformsBuf); 2261 if (*pcchTransformsBuf <= lstrlenW(transforms)) 2262 { 2263 r = ERROR_MORE_DATA; 2264 *pcchTransformsBuf = lstrlenW(transforms); 2265 } 2266 else 2267 *pcchTransformsBuf = lstrlenW(transforms); 2268 2269 done: 2270 msi_free(transforms); 2271 return r; 2272 } 2273 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 ) 2277 { 2278 UINT r; 2279 WCHAR installed_productW[GUID_SIZE], *productW = NULL, *usersidW = NULL, *sidW = NULL; 2280 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); 2283 2284 if (sid && !sid_len) return ERROR_INVALID_PARAMETER; 2285 if (product && !(productW = strdupAtoW( product ))) return ERROR_OUTOFMEMORY; 2286 if (usersid && !(usersidW = strdupAtoW( usersid ))) 2287 { 2288 msi_free( productW ); 2289 return ERROR_OUTOFMEMORY; 2290 } 2291 if (sid && !(sidW = msi_alloc( *sid_len * sizeof(WCHAR) ))) 2292 { 2293 msi_free( usersidW ); 2294 msi_free( productW ); 2295 return ERROR_OUTOFMEMORY; 2296 } 2297 r = MsiEnumProductsExW( productW, usersidW, ctx, index, installed_productW, 2298 installed_ctx, sidW, sid_len ); 2299 if (r == ERROR_SUCCESS) 2300 { 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 ); 2304 } 2305 msi_free( productW ); 2306 msi_free( usersidW ); 2307 msi_free( sidW ); 2308 return r; 2309 } 2310 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 ) 2314 { 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; 2323 2324 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, productsW, 0, access, &key )) 2325 return ERROR_NO_MORE_ITEMS; 2326 2327 len = sizeof(product)/sizeof(product[0]); 2328 while (!RegEnumKeyExW( key, i, product, &len, NULL, NULL, NULL, NULL )) 2329 { 2330 if (match && strcmpW( match, product )) 2331 { 2332 i++; 2333 len = sizeof(product)/sizeof(product[0]); 2334 continue; 2335 } 2336 if (*idx == index) goto found; 2337 (*idx)++; 2338 len = sizeof(product)/sizeof(product[0]); 2339 i++; 2340 } 2341 RegCloseKey( key ); 2342 return ERROR_NO_MORE_ITEMS; 2343 2344 found: 2345 if (sid_len && *sid_len < 1) 2346 { 2347 *sid_len = 1; 2348 r = ERROR_MORE_DATA; 2349 } 2350 else 2351 { 2352 if (installed_product) unsquash_guid( product, installed_product ); 2353 if (installed_ctx) *installed_ctx = MSIINSTALLCONTEXT_MACHINE; 2354 if (sid) 2355 { 2356 sid[0] = 0; 2357 *sid_len = 0; 2358 } 2359 r = ERROR_SUCCESS; 2360 } 2361 RegCloseKey( key ); 2362 return r; 2363 } 2364 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 ) 2368 { 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; 2384 2385 if (ctx == MSIINSTALLCONTEXT_USERMANAGED) 2386 { 2387 subkey = managed_productsW; 2388 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, managedW, 0, access, &key_users )) 2389 return ERROR_NO_MORE_ITEMS; 2390 } 2391 else if (ctx == MSIINSTALLCONTEXT_USERUNMANAGED) 2392 { 2393 subkey = unmanaged_productsW; 2394 if (RegOpenKeyExW( HKEY_USERS, NULL, 0, access, &key_users )) 2395 return ERROR_NO_MORE_ITEMS; 2396 } 2397 else return ERROR_INVALID_PARAMETER; 2398 2399 len_user = sizeof(user)/sizeof(user[0]); 2400 while (!RegEnumKeyExW( key_users, i, user, &len_user, NULL, NULL, NULL, NULL )) 2401 { 2402 if (strcmpW( usersid, user ) && strcmpW( usersid, szAllSid )) 2403 { 2404 i++; 2405 len_user = sizeof(user)/sizeof(user[0]); 2406 continue; 2407 } 2408 strcpyW( path, user ); 2409 strcatW( path, subkey ); 2410 if (RegOpenKeyExW( key_users, path, 0, access, &key_products )) 2411 { 2412 i++; 2413 len_user = sizeof(user)/sizeof(user[0]); 2414 continue; 2415 } 2416 len_product = sizeof(product)/sizeof(product[0]); 2417 while (!RegEnumKeyExW( key_products, j, product, &len_product, NULL, NULL, NULL, NULL )) 2418 { 2419 if (match && strcmpW( match, product )) 2420 { 2421 j++; 2422 len_product = sizeof(product)/sizeof(product[0]); 2423 continue; 2424 } 2425 if (*idx == index) goto found; 2426 (*idx)++; 2427 len_product = sizeof(product)/sizeof(product[0]); 2428 j++; 2429 } 2430 RegCloseKey( key_products ); 2431 len_user = sizeof(user)/sizeof(user[0]); 2432 i++; 2433 } 2434 RegCloseKey( key_users ); 2435 return ERROR_NO_MORE_ITEMS; 2436 2437 found: 2438 if (sid_len && *sid_len <= len_user) 2439 { 2440 *sid_len = len_user; 2441 r = ERROR_MORE_DATA; 2442 } 2443 else 2444 { 2445 if (installed_product) unsquash_guid( product, installed_product ); 2446 if (installed_ctx) *installed_ctx = ctx; 2447 if (sid) 2448 { 2449 strcpyW( sid, user ); 2450 *sid_len = len_user; 2451 } 2452 r = ERROR_SUCCESS; 2453 } 2454 RegCloseKey( key_products ); 2455 RegCloseKey( key_users ); 2456 return r; 2457 } 2458 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 ) 2462 { 2463 UINT r = ERROR_NO_MORE_ITEMS; 2464 WCHAR *user = NULL; 2465 2466 if (!usersid) 2467 { 2468 usersid = user = get_user_sid(); 2469 if (!user) return ERROR_FUNCTION_FAILED; 2470 } 2471 if (ctx & MSIINSTALLCONTEXT_MACHINE) 2472 { 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; 2476 } 2477 if (ctx & MSIINSTALLCONTEXT_USERUNMANAGED) 2478 { 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; 2482 } 2483 if (ctx & MSIINSTALLCONTEXT_USERMANAGED) 2484 { 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; 2488 } 2489 2490 done: 2491 LocalFree( user ); 2492 return r; 2493 } 2494 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 ) 2498 { 2499 UINT r; 2500 DWORD idx = 0; 2501 static DWORD last_index; 2502 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); 2505 2506 if ((sid && !sid_len) || !ctx || (usersid && ctx == MSIINSTALLCONTEXT_MACHINE)) 2507 return ERROR_INVALID_PARAMETER; 2508 2509 if (index && index - last_index != 1) 2510 return ERROR_INVALID_PARAMETER; 2511 2512 if (!index) last_index = 0; 2513 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; 2520 2521 return r; 2522 } 2523