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