diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-06-03 17:49:15 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-06-07 19:44:36 -0500 |
| commit | 584213c5ffeca09b3fe24bd5e92f73fd057ac642 (patch) | |
| tree | 45619273a56248d662dda598bca3076efa8a5135 /src/libs/dutil/WixToolset.DUtil/regutil.cpp | |
| parent | 648f370f7966b2738c1446601057d888bbd2c70f (diff) | |
| download | wix-584213c5ffeca09b3fe24bd5e92f73fd057ac642.tar.gz wix-584213c5ffeca09b3fe24bd5e92f73fd057ac642.tar.bz2 wix-584213c5ffeca09b3fe24bd5e92f73fd057ac642.zip | |
Add RegReadUnexpandedString to get an unexpanded REG_EXPAND_SZ value.
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/regutil.cpp')
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/regutil.cpp | 420 |
1 files changed, 265 insertions, 155 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/regutil.cpp b/src/libs/dutil/WixToolset.DUtil/regutil.cpp index 64224d42..584966ed 100644 --- a/src/libs/dutil/WixToolset.DUtil/regutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/regutil.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #define RegExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) | 9 | #define RegExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) |
| 10 | #define RegExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) | 10 | #define RegExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) |
| 11 | #define RegExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) | 11 | #define RegExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) |
| 12 | #define RegExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_REGUTIL, x, e, s, __VA_ARGS__) | ||
| 12 | #define RegExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) | 13 | #define RegExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__) |
| 13 | #define RegExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_REGUTIL, p, x, e, s, __VA_ARGS__) | 14 | #define RegExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_REGUTIL, p, x, e, s, __VA_ARGS__) |
| 14 | #define RegExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_REGUTIL, p, x, s, __VA_ARGS__) | 15 | #define RegExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_REGUTIL, p, x, s, __VA_ARGS__) |
| @@ -28,10 +29,19 @@ static PFN_REGQUERYINFOKEYW vpfnRegQueryInfoKeyW = ::RegQueryInfoKeyW; | |||
| 28 | static PFN_REGQUERYVALUEEXW vpfnRegQueryValueExW = ::RegQueryValueExW; | 29 | static PFN_REGQUERYVALUEEXW vpfnRegQueryValueExW = ::RegQueryValueExW; |
| 29 | static PFN_REGSETVALUEEXW vpfnRegSetValueExW = ::RegSetValueExW; | 30 | static PFN_REGSETVALUEEXW vpfnRegSetValueExW = ::RegSetValueExW; |
| 30 | static PFN_REGDELETEVALUEW vpfnRegDeleteValueW = ::RegDeleteValueW; | 31 | static PFN_REGDELETEVALUEW vpfnRegDeleteValueW = ::RegDeleteValueW; |
| 32 | static PFN_REGGETVALUEW vpfnRegGetValueW = NULL; | ||
| 33 | static PFN_REGGETVALUEW vpfnRegGetValueWFromLibrary = NULL; | ||
| 31 | 34 | ||
| 32 | static HMODULE vhAdvApi32Dll = NULL; | 35 | static HMODULE vhAdvApi32Dll = NULL; |
| 33 | static BOOL vfRegInitialized = FALSE; | 36 | static BOOL vfRegInitialized = FALSE; |
| 34 | 37 | ||
| 38 | static HRESULT GetRegValue( | ||
| 39 | __in HKEY hk, | ||
| 40 | __in_z_opt LPCWSTR wzName, | ||
| 41 | __deref_out_bcount_opt(*pcbBuffer) BYTE* pbBuffer, | ||
| 42 | __inout SIZE_T* pcbBuffer, | ||
| 43 | __out DWORD* pdwType | ||
| 44 | ); | ||
| 35 | static HRESULT WriteStringToRegistry( | 45 | static HRESULT WriteStringToRegistry( |
| 36 | __in HKEY hk, | 46 | __in HKEY hk, |
| 37 | __in_z_opt LPCWSTR wzName, | 47 | __in_z_opt LPCWSTR wzName, |
| @@ -46,14 +56,22 @@ DAPI_(HRESULT) RegInitialize() | |||
| 46 | hr = LoadSystemLibrary(L"AdvApi32.dll", &vhAdvApi32Dll); | 56 | hr = LoadSystemLibrary(L"AdvApi32.dll", &vhAdvApi32Dll); |
| 47 | RegExitOnFailure(hr, "Failed to load AdvApi32.dll"); | 57 | RegExitOnFailure(hr, "Failed to load AdvApi32.dll"); |
| 48 | 58 | ||
| 49 | // ignore failures - if this doesn't exist, we'll fall back to RegDeleteKeyW | 59 | // Ignore failures - if this doesn't exist, we'll fall back to RegDeleteKeyW. |
| 50 | vpfnRegDeleteKeyExWFromLibrary = reinterpret_cast<PFN_REGDELETEKEYEXW>(::GetProcAddress(vhAdvApi32Dll, "RegDeleteKeyExW")); | 60 | vpfnRegDeleteKeyExWFromLibrary = reinterpret_cast<PFN_REGDELETEKEYEXW>(::GetProcAddress(vhAdvApi32Dll, "RegDeleteKeyExW")); |
| 51 | 61 | ||
| 52 | if (NULL == vpfnRegDeleteKeyExW) | 62 | // Ignore failures - if this doesn't exist, we'll fall back to RegQueryValueExW. |
| 63 | vpfnRegGetValueWFromLibrary = reinterpret_cast<PFN_REGGETVALUEW>(::GetProcAddress(vhAdvApi32Dll, "RegGetValueW")); | ||
| 64 | |||
| 65 | if (!vpfnRegDeleteKeyExW) | ||
| 53 | { | 66 | { |
| 54 | vpfnRegDeleteKeyExW = vpfnRegDeleteKeyExWFromLibrary; | 67 | vpfnRegDeleteKeyExW = vpfnRegDeleteKeyExWFromLibrary; |
| 55 | } | 68 | } |
| 56 | 69 | ||
| 70 | if (!vpfnRegGetValueW) | ||
| 71 | { | ||
| 72 | vpfnRegGetValueW = vpfnRegGetValueWFromLibrary; | ||
| 73 | } | ||
| 74 | |||
| 57 | vfRegInitialized = TRUE; | 75 | vfRegInitialized = TRUE; |
| 58 | 76 | ||
| 59 | LExit: | 77 | LExit: |
| @@ -68,7 +86,9 @@ DAPI_(void) RegUninitialize() | |||
| 68 | ::FreeLibrary(vhAdvApi32Dll); | 86 | ::FreeLibrary(vhAdvApi32Dll); |
| 69 | vhAdvApi32Dll = NULL; | 87 | vhAdvApi32Dll = NULL; |
| 70 | vpfnRegDeleteKeyExWFromLibrary = NULL; | 88 | vpfnRegDeleteKeyExWFromLibrary = NULL; |
| 89 | vpfnRegGetValueWFromLibrary = NULL; | ||
| 71 | vpfnRegDeleteKeyExW = NULL; | 90 | vpfnRegDeleteKeyExW = NULL; |
| 91 | vpfnRegGetValueW = NULL; | ||
| 72 | } | 92 | } |
| 73 | 93 | ||
| 74 | vfRegInitialized = FALSE; | 94 | vfRegInitialized = FALSE; |
| @@ -84,7 +104,8 @@ DAPI_(void) RegFunctionOverride( | |||
| 84 | __in_opt PFN_REGQUERYINFOKEYW pfnRegQueryInfoKeyW, | 104 | __in_opt PFN_REGQUERYINFOKEYW pfnRegQueryInfoKeyW, |
| 85 | __in_opt PFN_REGQUERYVALUEEXW pfnRegQueryValueExW, | 105 | __in_opt PFN_REGQUERYVALUEEXW pfnRegQueryValueExW, |
| 86 | __in_opt PFN_REGSETVALUEEXW pfnRegSetValueExW, | 106 | __in_opt PFN_REGSETVALUEEXW pfnRegSetValueExW, |
| 87 | __in_opt PFN_REGDELETEVALUEW pfnRegDeleteValueW | 107 | __in_opt PFN_REGDELETEVALUEW pfnRegDeleteValueW, |
| 108 | __in_opt PFN_REGGETVALUEW pfnRegGetValueW | ||
| 88 | ) | 109 | ) |
| 89 | { | 110 | { |
| 90 | vpfnRegCreateKeyExW = pfnRegCreateKeyExW ? pfnRegCreateKeyExW : ::RegCreateKeyExW; | 111 | vpfnRegCreateKeyExW = pfnRegCreateKeyExW ? pfnRegCreateKeyExW : ::RegCreateKeyExW; |
| @@ -96,6 +117,14 @@ DAPI_(void) RegFunctionOverride( | |||
| 96 | vpfnRegQueryValueExW = pfnRegQueryValueExW ? pfnRegQueryValueExW : ::RegQueryValueExW; | 117 | vpfnRegQueryValueExW = pfnRegQueryValueExW ? pfnRegQueryValueExW : ::RegQueryValueExW; |
| 97 | vpfnRegSetValueExW = pfnRegSetValueExW ? pfnRegSetValueExW : ::RegSetValueExW; | 118 | vpfnRegSetValueExW = pfnRegSetValueExW ? pfnRegSetValueExW : ::RegSetValueExW; |
| 98 | vpfnRegDeleteValueW = pfnRegDeleteValueW ? pfnRegDeleteValueW : ::RegDeleteValueW; | 119 | vpfnRegDeleteValueW = pfnRegDeleteValueW ? pfnRegDeleteValueW : ::RegDeleteValueW; |
| 120 | vpfnRegGetValueW = pfnRegGetValueW ? pfnRegGetValueW : vpfnRegGetValueWFromLibrary; | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | DAPI_(void) RegFunctionForceFallback() | ||
| 125 | { | ||
| 126 | vpfnRegDeleteKeyExW = NULL; | ||
| 127 | vpfnRegGetValueW = NULL; | ||
| 99 | } | 128 | } |
| 100 | 129 | ||
| 101 | 130 | ||
| @@ -358,54 +387,104 @@ LExit: | |||
| 358 | return hr; | 387 | return hr; |
| 359 | } | 388 | } |
| 360 | 389 | ||
| 361 | DAPI_(HRESULT) RegReadBinary( | 390 | DAPI_(HRESULT) RegReadValue( |
| 362 | __in HKEY hk, | 391 | __in HKEY hk, |
| 363 | __in_z_opt LPCWSTR wzName, | 392 | __in_z_opt LPCWSTR wzName, |
| 393 | __in BOOL fExpand, | ||
| 364 | __deref_out_bcount_opt(*pcbBuffer) BYTE** ppbBuffer, | 394 | __deref_out_bcount_opt(*pcbBuffer) BYTE** ppbBuffer, |
| 365 | __out SIZE_T *pcbBuffer | 395 | __inout SIZE_T* pcbBuffer, |
| 366 | ) | 396 | __out DWORD* pdwType |
| 397 | ) | ||
| 367 | { | 398 | { |
| 368 | HRESULT hr = S_OK; | 399 | HRESULT hr = S_OK; |
| 369 | LPBYTE pbBuffer = NULL; | 400 | DWORD dwAttempts = 0; |
| 370 | DWORD er = ERROR_SUCCESS; | 401 | LPWSTR sczExpand = NULL; |
| 371 | DWORD cb = 0; | ||
| 372 | DWORD dwType = 0; | ||
| 373 | |||
| 374 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, NULL, &cb); | ||
| 375 | RegExitOnWin32Error(er, hr, "Failed to get size of registry value."); | ||
| 376 | 402 | ||
| 377 | // Zero-length binary values can exist | 403 | hr = GetRegValue(hk, wzName, *ppbBuffer, pcbBuffer, pdwType); |
| 378 | if (0 < cb) | 404 | if (E_FILENOTFOUND == hr) |
| 379 | { | 405 | { |
| 380 | pbBuffer = static_cast<LPBYTE>(MemAlloc(cb, FALSE)); | 406 | ExitFunction(); |
| 381 | RegExitOnNull(pbBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for binary registry value."); | 407 | } |
| 408 | else if (E_MOREDATA != hr) | ||
| 409 | { | ||
| 410 | RegExitOnFailure(hr, "Failed to get size of raw registry value."); | ||
| 382 | 411 | ||
| 383 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, pbBuffer, &cb); | 412 | // Zero-length raw values can exist |
| 384 | if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) | 413 | if (!*ppbBuffer && 0 < *pcbBuffer) |
| 385 | { | 414 | { |
| 386 | ExitFunction1(hr = E_FILENOTFOUND); | 415 | hr = E_MOREDATA; |
| 387 | } | 416 | } |
| 388 | RegExitOnWin32Error(er, hr, "Failed to read registry value."); | ||
| 389 | } | 417 | } |
| 390 | 418 | ||
| 391 | if (REG_BINARY == dwType) | 419 | while (E_MOREDATA == hr && dwAttempts < 10) |
| 392 | { | 420 | { |
| 393 | *ppbBuffer = pbBuffer; | 421 | ++dwAttempts; |
| 394 | pbBuffer = NULL; | 422 | |
| 395 | *pcbBuffer = cb; | 423 | if (*ppbBuffer) |
| 424 | { | ||
| 425 | *ppbBuffer = static_cast<LPBYTE>(MemReAlloc(*ppbBuffer, *pcbBuffer, FALSE)); | ||
| 426 | } | ||
| 427 | else | ||
| 428 | { | ||
| 429 | *ppbBuffer = static_cast<LPBYTE>(MemAlloc(*pcbBuffer, FALSE)); | ||
| 430 | } | ||
| 431 | RegExitOnNull(*ppbBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for raw registry value."); | ||
| 432 | |||
| 433 | hr = GetRegValue(hk, wzName, *ppbBuffer, pcbBuffer, pdwType); | ||
| 434 | if (E_FILENOTFOUND == hr) | ||
| 435 | { | ||
| 436 | ExitFunction(); | ||
| 437 | } | ||
| 438 | else if (E_MOREDATA != hr) | ||
| 439 | { | ||
| 440 | RegExitOnFailure(hr, "Failed to read raw registry value."); | ||
| 441 | } | ||
| 396 | } | 442 | } |
| 397 | else | 443 | |
| 444 | if (fExpand && SUCCEEDED(hr) && REG_EXPAND_SZ == *pdwType) | ||
| 398 | { | 445 | { |
| 399 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); | 446 | LPWSTR sczValue = reinterpret_cast<LPWSTR>(*ppbBuffer); |
| 400 | RegExitOnRootFailure(hr, "Error reading binary registry value due to unexpected data type: %u", dwType); | 447 | hr = PathExpand(&sczExpand, sczValue, PATH_EXPAND_ENVIRONMENT); |
| 448 | RegExitOnFailure(hr, "Failed to expand registry value: %ls", sczValue); | ||
| 449 | |||
| 450 | *ppbBuffer = reinterpret_cast<LPBYTE>(sczExpand); | ||
| 451 | *pcbBuffer = (lstrlenW(sczExpand) + 1) * sizeof(WCHAR); | ||
| 452 | sczExpand = NULL; | ||
| 453 | ReleaseMem(sczValue); | ||
| 401 | } | 454 | } |
| 402 | 455 | ||
| 403 | LExit: | 456 | LExit: |
| 404 | ReleaseMem(pbBuffer); | 457 | ReleaseStr(sczExpand); |
| 405 | 458 | ||
| 406 | return hr; | 459 | return hr; |
| 407 | } | 460 | } |
| 408 | 461 | ||
| 462 | DAPI_(HRESULT) RegReadBinary( | ||
| 463 | __in HKEY hk, | ||
| 464 | __in_z_opt LPCWSTR wzName, | ||
| 465 | __deref_out_bcount_opt(*pcbBuffer) BYTE** ppbBuffer, | ||
| 466 | __out SIZE_T* pcbBuffer | ||
| 467 | ) | ||
| 468 | { | ||
| 469 | HRESULT hr = S_OK; | ||
| 470 | DWORD dwType = 0; | ||
| 471 | |||
| 472 | hr = RegReadValue(hk, wzName, FALSE, ppbBuffer, pcbBuffer, &dwType); | ||
| 473 | if (E_FILENOTFOUND == hr) | ||
| 474 | { | ||
| 475 | ExitFunction(); | ||
| 476 | } | ||
| 477 | RegExitOnFailure(hr, "Failed to read binary registry value."); | ||
| 478 | |||
| 479 | if (REG_BINARY != dwType) | ||
| 480 | { | ||
| 481 | RegExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE), "Error reading binary registry value due to unexpected data type: %u", dwType); | ||
| 482 | } | ||
| 483 | |||
| 484 | LExit: | ||
| 485 | return hr; | ||
| 486 | } | ||
| 487 | |||
| 409 | 488 | ||
| 410 | DAPI_(HRESULT) RegReadString( | 489 | DAPI_(HRESULT) RegReadString( |
| 411 | __in HKEY hk, | 490 | __in HKEY hk, |
| @@ -414,65 +493,64 @@ DAPI_(HRESULT) RegReadString( | |||
| 414 | ) | 493 | ) |
| 415 | { | 494 | { |
| 416 | HRESULT hr = S_OK; | 495 | HRESULT hr = S_OK; |
| 417 | DWORD er = ERROR_SUCCESS; | ||
| 418 | SIZE_T cbValue = 0; | 496 | SIZE_T cbValue = 0; |
| 419 | DWORD cch = 0; | ||
| 420 | DWORD cb = 0; | ||
| 421 | DWORD dwType = 0; | 497 | DWORD dwType = 0; |
| 422 | LPWSTR sczExpand = NULL; | ||
| 423 | 498 | ||
| 424 | if (psczValue && *psczValue) | 499 | if (psczValue && *psczValue) |
| 425 | { | 500 | { |
| 426 | hr = StrMaxLength(*psczValue, &cbValue); | 501 | hr = MemSizeChecked(*psczValue, &cbValue); |
| 427 | RegExitOnFailure(hr, "Failed to determine length of string."); | 502 | RegExitOnFailure(hr, "Failed to get size of input buffer."); |
| 428 | |||
| 429 | cch = (DWORD)min(DWORD_MAX, cbValue); | ||
| 430 | } | 503 | } |
| 431 | 504 | ||
| 432 | if (2 > cch) | 505 | hr = RegReadValue(hk, wzName, TRUE, reinterpret_cast<LPBYTE*>(psczValue), &cbValue, &dwType); |
| 506 | if (E_FILENOTFOUND == hr) | ||
| 433 | { | 507 | { |
| 434 | cch = 2; | 508 | ExitFunction(); |
| 435 | |||
| 436 | hr = StrAlloc(psczValue, cch); | ||
| 437 | RegExitOnFailure(hr, "Failed to allocate string to minimum size."); | ||
| 438 | } | 509 | } |
| 510 | RegExitOnFailure(hr, "Failed to read string registry value."); | ||
| 439 | 511 | ||
| 440 | cb = sizeof(WCHAR) * (cch - 1); // subtract one to ensure there will be a space at the end of the string for the null terminator. | 512 | if (REG_EXPAND_SZ != dwType && REG_SZ != dwType) |
| 441 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(*psczValue), &cb); | ||
| 442 | if (ERROR_MORE_DATA == er) | ||
| 443 | { | 513 | { |
| 444 | cch = cb / sizeof(WCHAR) + 1; // add one to ensure there will be space at the end for the null terminator | 514 | RegExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE), "Error reading string registry value due to unexpected data type: %u", dwType); |
| 445 | hr = StrAlloc(psczValue, cch); | ||
| 446 | RegExitOnFailure(hr, "Failed to allocate string bigger for registry value."); | ||
| 447 | |||
| 448 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(*psczValue), &cb); | ||
| 449 | } | 515 | } |
| 450 | if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) | 516 | |
| 517 | LExit: | ||
| 518 | return hr; | ||
| 519 | } | ||
| 520 | |||
| 521 | |||
| 522 | DAPI_(HRESULT) RegReadUnexpandedString( | ||
| 523 | __in HKEY hk, | ||
| 524 | __in_z_opt LPCWSTR wzName, | ||
| 525 | __inout BOOL* pfNeedsExpansion, | ||
| 526 | __deref_out_z LPWSTR* psczValue | ||
| 527 | ) | ||
| 528 | { | ||
| 529 | HRESULT hr = S_OK; | ||
| 530 | SIZE_T cbValue = 0; | ||
| 531 | DWORD dwType = 0; | ||
| 532 | LPWSTR sczExpand = NULL; | ||
| 533 | |||
| 534 | if (psczValue && *psczValue) | ||
| 451 | { | 535 | { |
| 452 | ExitFunction1(hr = E_FILENOTFOUND); | 536 | hr = MemSizeChecked(*psczValue, &cbValue); |
| 537 | RegExitOnFailure(hr, "Failed to get size of input buffer."); | ||
| 453 | } | 538 | } |
| 454 | RegExitOnWin32Error(er, hr, "Failed to read registry key."); | ||
| 455 | 539 | ||
| 456 | if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) | 540 | hr = RegReadValue(hk, wzName, FALSE, reinterpret_cast<LPBYTE*>(psczValue), &cbValue, &dwType); |
| 541 | if (E_FILENOTFOUND == hr) | ||
| 457 | { | 542 | { |
| 458 | // Always ensure the registry value is null terminated. | 543 | ExitFunction(); |
| 459 | (*psczValue)[cch - 1] = L'\0'; | ||
| 460 | |||
| 461 | if (REG_EXPAND_SZ == dwType) | ||
| 462 | { | ||
| 463 | hr = StrAllocString(&sczExpand, *psczValue, 0); | ||
| 464 | RegExitOnFailure(hr, "Failed to copy registry value to expand."); | ||
| 465 | |||
| 466 | hr = PathExpand(psczValue, sczExpand, PATH_EXPAND_ENVIRONMENT); | ||
| 467 | RegExitOnFailure(hr, "Failed to expand registry value: %ls", *psczValue); | ||
| 468 | } | ||
| 469 | } | 544 | } |
| 470 | else | 545 | RegExitOnFailure(hr, "Failed to read expand string registry value."); |
| 546 | |||
| 547 | if (REG_EXPAND_SZ != dwType && REG_SZ != dwType) | ||
| 471 | { | 548 | { |
| 472 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); | 549 | RegExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE), "Error reading expand string registry value due to unexpected data type: %u", dwType); |
| 473 | RegExitOnRootFailure(hr, "Error reading string registry value due to unexpected data type: %u", dwType); | ||
| 474 | } | 550 | } |
| 475 | 551 | ||
| 552 | *pfNeedsExpansion = REG_EXPAND_SZ == dwType; | ||
| 553 | |||
| 476 | LExit: | 554 | LExit: |
| 477 | ReleaseStr(sczExpand); | 555 | ReleaseStr(sczExpand); |
| 478 | 556 | ||
| @@ -488,67 +566,57 @@ DAPI_(HRESULT) RegReadStringArray( | |||
| 488 | ) | 566 | ) |
| 489 | { | 567 | { |
| 490 | HRESULT hr = S_OK; | 568 | HRESULT hr = S_OK; |
| 491 | DWORD er = ERROR_SUCCESS; | ||
| 492 | DWORD dwNullCharacters = 0; | 569 | DWORD dwNullCharacters = 0; |
| 493 | DWORD dwType = 0; | 570 | DWORD dwType = 0; |
| 494 | DWORD cb = 0; | 571 | SIZE_T cb = 0; |
| 495 | DWORD cch = 0; | 572 | SIZE_T cch = 0; |
| 496 | LPCWSTR wzSource = NULL; | 573 | LPCWSTR wzSource = NULL; |
| 497 | LPWSTR sczValue = NULL; | 574 | LPWSTR sczValue = NULL; |
| 498 | 575 | ||
| 499 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(sczValue), &cb); | 576 | hr = RegReadValue(hk, wzName, FALSE, reinterpret_cast<LPBYTE*>(&sczValue), &cb, &dwType); |
| 500 | if (0 < cb) | 577 | if (E_FILENOTFOUND == hr) |
| 501 | { | ||
| 502 | cch = cb / sizeof(WCHAR); | ||
| 503 | hr = StrAlloc(&sczValue, cch); | ||
| 504 | RegExitOnFailure(hr, "Failed to allocate string for registry value."); | ||
| 505 | |||
| 506 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(sczValue), &cb); | ||
| 507 | } | ||
| 508 | if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) | ||
| 509 | { | 578 | { |
| 510 | ExitFunction1(hr = E_FILENOTFOUND); | 579 | ExitFunction(); |
| 511 | } | 580 | } |
| 512 | RegExitOnWin32Error(er, hr, "Failed to read registry key."); | 581 | RegExitOnFailure(hr, "Failed to read string array registry value."); |
| 513 | 582 | ||
| 514 | if (cb / sizeof(WCHAR) != cch) | 583 | if (REG_MULTI_SZ != dwType) |
| 515 | { | 584 | { |
| 516 | hr = E_UNEXPECTED; | 585 | RegExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE), "Tried to read string array, but registry value %ls is of an incorrect type", wzName); |
| 517 | RegExitOnFailure(hr, "The size of registry value %ls unexpected changed between 2 reads", wzName); | ||
| 518 | } | 586 | } |
| 519 | 587 | ||
| 520 | if (REG_MULTI_SZ != dwType) | 588 | cch = cb / sizeof(WCHAR); |
| 589 | |||
| 590 | for (DWORD i = 0; i < cch; ++i) | ||
| 521 | { | 591 | { |
| 522 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); | 592 | if (L'\0' == sczValue[i]) |
| 523 | RegExitOnRootFailure(hr, "Tried to read string array, but registry value %ls is of an incorrect type", wzName); | 593 | { |
| 594 | ++dwNullCharacters; | ||
| 595 | } | ||
| 524 | } | 596 | } |
| 525 | 597 | ||
| 526 | // Value exists, but is empty, so no strings to return. | 598 | // Value exists, but is empty, so no strings to return. |
| 527 | if (2 > cch) | 599 | if (!cb || 1 == dwNullCharacters && 1 == cch || 2 == dwNullCharacters && 2 == cch) |
| 528 | { | 600 | { |
| 529 | *prgsczStrings = NULL; | 601 | *prgsczStrings = NULL; |
| 530 | *pcStrings = 0; | 602 | *pcStrings = 0; |
| 531 | ExitFunction1(hr = S_OK); | 603 | ExitFunction1(hr = S_OK); |
| 532 | } | 604 | } |
| 533 | 605 | ||
| 534 | // The docs specifically say if the value was written without double-null-termination, it'll get read back without it too. | 606 | if (sczValue[cch - 1] != L'\0') |
| 535 | if (L'\0' != sczValue[cch-1] || L'\0' != sczValue[cch-2]) | ||
| 536 | { | 607 | { |
| 537 | hr = E_INVALIDARG; | 608 | // Count the terminating null character that RegReadValue added past the end. |
| 538 | RegExitOnFailure(hr, "Tried to read string array, but registry value %ls is invalid (isn't double-null-terminated)", wzName); | 609 | ++dwNullCharacters; |
| 610 | Assert(!sczValue[cch]); | ||
| 539 | } | 611 | } |
| 540 | 612 | else if (cch > 1 && sczValue[cch - 2] == L'\0') | |
| 541 | cch = cb / sizeof(WCHAR); | ||
| 542 | for (DWORD i = 0; i < cch; ++i) | ||
| 543 | { | 613 | { |
| 544 | if (L'\0' == sczValue[i]) | 614 | // Don't count the extra 1 at the end of the properly double-null terminated string. |
| 545 | { | 615 | --dwNullCharacters; |
| 546 | ++dwNullCharacters; | ||
| 547 | } | ||
| 548 | } | 616 | } |
| 549 | 617 | ||
| 550 | // There's one string for every null character encountered (except the extra 1 at the end of the string) | 618 | // There's one string for every null character encountered. |
| 551 | *pcStrings = dwNullCharacters - 1; | 619 | *pcStrings = dwNullCharacters; |
| 552 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID *>(prgsczStrings), *pcStrings, sizeof(LPWSTR), 0); | 620 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID *>(prgsczStrings), *pcStrings, sizeof(LPWSTR), 0); |
| 553 | RegExitOnFailure(hr, "Failed to resize array while reading REG_MULTI_SZ value"); | 621 | RegExitOnFailure(hr, "Failed to resize array while reading REG_MULTI_SZ value"); |
| 554 | 622 | ||
| @@ -557,11 +625,13 @@ DAPI_(HRESULT) RegReadStringArray( | |||
| 557 | wzSource = sczValue; | 625 | wzSource = sczValue; |
| 558 | for (DWORD i = 0; i < *pcStrings; ++i) | 626 | for (DWORD i = 0; i < *pcStrings; ++i) |
| 559 | { | 627 | { |
| 560 | hr = StrAllocString(&(*prgsczStrings)[i], wzSource, 0); | 628 | cch = lstrlenW(wzSource); |
| 629 | |||
| 630 | hr = StrAllocString(&(*prgsczStrings)[i], wzSource, cch); | ||
| 561 | RegExitOnFailure(hr, "Failed to allocate copy of string"); | 631 | RegExitOnFailure(hr, "Failed to allocate copy of string"); |
| 562 | 632 | ||
| 563 | // Skip past this string | 633 | // Skip past this string |
| 564 | wzSource += lstrlenW(wzSource) + 1; | 634 | wzSource += cch + 1; |
| 565 | } | 635 | } |
| 566 | #pragma prefast(pop) | 636 | #pragma prefast(pop) |
| 567 | 637 | ||
| @@ -579,38 +649,36 @@ DAPI_(HRESULT) RegReadVersion( | |||
| 579 | ) | 649 | ) |
| 580 | { | 650 | { |
| 581 | HRESULT hr = S_OK; | 651 | HRESULT hr = S_OK; |
| 582 | DWORD er = ERROR_SUCCESS; | ||
| 583 | DWORD dwType = 0; | 652 | DWORD dwType = 0; |
| 584 | DWORD cb = 0; | 653 | SIZE_T cb = 0; |
| 585 | LPWSTR sczVersion = NULL; | 654 | LPWSTR sczValue = NULL; |
| 586 | 655 | ||
| 587 | cb = sizeof(DWORD64); | 656 | hr = RegReadValue(hk, wzName, TRUE, reinterpret_cast<LPBYTE*>(&sczValue), &cb, &dwType); |
| 588 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(*pdw64Version), &cb); | 657 | if (E_FILENOTFOUND == hr) |
| 589 | if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) | ||
| 590 | { | 658 | { |
| 591 | ExitFunction1(hr = E_FILENOTFOUND); | 659 | ExitFunction(); |
| 592 | } | 660 | } |
| 661 | RegExitOnFailure(hr, "Failed to read version registry value."); | ||
| 593 | 662 | ||
| 594 | if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) | 663 | if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) |
| 595 | { | 664 | { |
| 596 | hr = RegReadString(hk, wzName, &sczVersion); | 665 | hr = FileVersionFromStringEx(sczValue, 0, pdw64Version); |
| 597 | RegExitOnFailure(hr, "Failed to read registry version as string."); | ||
| 598 | |||
| 599 | hr = FileVersionFromStringEx(sczVersion, 0, pdw64Version); | ||
| 600 | RegExitOnFailure(hr, "Failed to convert registry string to version."); | 666 | RegExitOnFailure(hr, "Failed to convert registry string to version."); |
| 601 | } | 667 | } |
| 602 | else if (REG_QWORD == dwType) | 668 | else if (REG_QWORD == dwType) |
| 603 | { | 669 | { |
| 604 | RegExitOnWin32Error(er, hr, "Failed to read registry key."); | 670 | if (memcpy_s(pdw64Version, sizeof(DWORD64), sczValue, cb)) |
| 671 | { | ||
| 672 | RegExitWithRootFailure(hr, E_INVALIDARG, "Failed to copy QWORD version value."); | ||
| 673 | } | ||
| 605 | } | 674 | } |
| 606 | else // unexpected data type | 675 | else // unexpected data type |
| 607 | { | 676 | { |
| 608 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); | 677 | RegExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE), "Error reading version registry value due to unexpected data type: %u", dwType); |
| 609 | RegExitOnRootFailure(hr, "Error reading version registry value due to unexpected data type: %u", dwType); | ||
| 610 | } | 678 | } |
| 611 | 679 | ||
| 612 | LExit: | 680 | LExit: |
| 613 | ReleaseStr(sczVersion); | 681 | ReleaseStr(sczValue); |
| 614 | 682 | ||
| 615 | return hr; | 683 | return hr; |
| 616 | } | 684 | } |
| @@ -623,37 +691,38 @@ DAPI_(HRESULT) RegReadWixVersion( | |||
| 623 | ) | 691 | ) |
| 624 | { | 692 | { |
| 625 | HRESULT hr = S_OK; | 693 | HRESULT hr = S_OK; |
| 626 | DWORD er = ERROR_SUCCESS; | ||
| 627 | DWORD dwType = 0; | 694 | DWORD dwType = 0; |
| 628 | DWORD cb = 0; | 695 | SIZE_T cb = 0; |
| 629 | DWORD64 dw64Version = 0; | 696 | DWORD64 dw64Version = 0; |
| 630 | LPWSTR sczVersion = NULL; | 697 | LPWSTR sczValue = NULL; |
| 631 | VERUTIL_VERSION* pVersion = NULL; | 698 | VERUTIL_VERSION* pVersion = NULL; |
| 632 | 699 | ||
| 633 | cb = sizeof(DWORD64); | 700 | hr = RegReadValue(hk, wzName, TRUE, reinterpret_cast<LPBYTE*>(&sczValue), &cb, &dwType); |
| 634 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(&dw64Version), &cb); | 701 | if (E_FILENOTFOUND == hr) |
| 635 | if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) | ||
| 636 | { | 702 | { |
| 637 | ExitFunction1(hr = E_FILENOTFOUND); | 703 | ExitFunction(); |
| 638 | } | 704 | } |
| 705 | RegExitOnFailure(hr, "Failed to read wix version registry value."); | ||
| 639 | 706 | ||
| 640 | if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) | 707 | if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) |
| 641 | { | 708 | { |
| 642 | hr = RegReadString(hk, wzName, &sczVersion); | 709 | hr = VerParseVersion(sczValue, 0, FALSE, &pVersion); |
| 643 | RegExitOnFailure(hr, "Failed to read registry version as string."); | 710 | RegExitOnFailure(hr, "Failed to convert registry string to wix version."); |
| 644 | |||
| 645 | hr = VerParseVersion(sczVersion, 0, FALSE, &pVersion); | ||
| 646 | RegExitOnFailure(hr, "Failed to convert registry string to version."); | ||
| 647 | } | 711 | } |
| 648 | else if (REG_QWORD == dwType) | 712 | else if (REG_QWORD == dwType) |
| 649 | { | 713 | { |
| 714 | if (memcpy_s(&dw64Version, sizeof(DWORD64), sczValue, cb)) | ||
| 715 | { | ||
| 716 | RegExitWithRootFailure(hr, E_INVALIDARG, "Failed to copy QWORD wix version value."); | ||
| 717 | } | ||
| 718 | |||
| 650 | hr = VerVersionFromQword(dw64Version, &pVersion); | 719 | hr = VerVersionFromQword(dw64Version, &pVersion); |
| 651 | RegExitOnFailure(hr, "Failed to convert registry string to version."); | 720 | RegExitOnFailure(hr, "Failed to convert registry string to wix version."); |
| 652 | } | 721 | } |
| 653 | else // unexpected data type | 722 | else // unexpected data type |
| 654 | { | 723 | { |
| 655 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); | 724 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); |
| 656 | RegExitOnRootFailure(hr, "Error reading version registry value due to unexpected data type: %u", dwType); | 725 | RegExitOnRootFailure(hr, "Error reading wix version registry value due to unexpected data type: %u", dwType); |
| 657 | } | 726 | } |
| 658 | 727 | ||
| 659 | *ppVersion = pVersion; | 728 | *ppVersion = pVersion; |
| @@ -661,7 +730,7 @@ DAPI_(HRESULT) RegReadWixVersion( | |||
| 661 | 730 | ||
| 662 | LExit: | 731 | LExit: |
| 663 | ReleaseVerutilVersion(pVersion); | 732 | ReleaseVerutilVersion(pVersion); |
| 664 | ReleaseStr(sczVersion); | 733 | ReleaseStr(sczValue); |
| 665 | 734 | ||
| 666 | return hr; | 735 | return hr; |
| 667 | } | 736 | } |
| @@ -673,20 +742,18 @@ DAPI_(HRESULT) RegReadNone( | |||
| 673 | ) | 742 | ) |
| 674 | { | 743 | { |
| 675 | HRESULT hr = S_OK; | 744 | HRESULT hr = S_OK; |
| 676 | DWORD er = ERROR_SUCCESS; | ||
| 677 | DWORD dwType = 0; | 745 | DWORD dwType = 0; |
| 678 | 746 | ||
| 679 | er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, NULL, NULL); | 747 | hr = RegGetType(hk, wzName, &dwType); |
| 680 | if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) | 748 | if (E_FILENOTFOUND == hr) |
| 681 | { | 749 | { |
| 682 | ExitFunction1(hr = E_FILENOTFOUND); | 750 | ExitFunction(); |
| 683 | } | 751 | } |
| 684 | RegExitOnWin32Error(er, hr, "Failed to query registry key value."); | 752 | RegExitOnFailure(hr, "Error reading none registry value type."); |
| 685 | 753 | ||
| 686 | if (REG_NONE != dwType) | 754 | if (REG_NONE != dwType) |
| 687 | { | 755 | { |
| 688 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE); | 756 | RegExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE), "Error reading none registry value due to unexpected data type: %u", dwType); |
| 689 | RegExitOnRootFailure(hr, "Error reading none registry value due to unexpected data type: %u", dwType); | ||
| 690 | } | 757 | } |
| 691 | 758 | ||
| 692 | LExit: | 759 | LExit: |
| @@ -829,12 +896,9 @@ DAPI_(HRESULT) RegWriteStringArray( | |||
| 829 | DWORD dwTotalStringSize = 0; | 896 | DWORD dwTotalStringSize = 0; |
| 830 | DWORD cbTotalStringSize = 0; | 897 | DWORD cbTotalStringSize = 0; |
| 831 | DWORD dwTemp = 0; | 898 | DWORD dwTemp = 0; |
| 899 | DWORD dwRemainingStringSize = 0; | ||
| 832 | 900 | ||
| 833 | if (0 == cValues) | 901 | if (cValues) |
| 834 | { | ||
| 835 | wzWriteValue = L"\0"; | ||
| 836 | } | ||
| 837 | else | ||
| 838 | { | 902 | { |
| 839 | // Add space for the null terminator | 903 | // Add space for the null terminator |
| 840 | dwTotalStringSize = 1; | 904 | dwTotalStringSize = 1; |
| @@ -850,21 +914,22 @@ DAPI_(HRESULT) RegWriteStringArray( | |||
| 850 | RegExitOnFailure(hr, "Failed to allocate space for string while writing REG_MULTI_SZ"); | 914 | RegExitOnFailure(hr, "Failed to allocate space for string while writing REG_MULTI_SZ"); |
| 851 | 915 | ||
| 852 | wzCopyDestination = sczWriteValue; | 916 | wzCopyDestination = sczWriteValue; |
| 853 | dwTemp = dwTotalStringSize; | 917 | dwRemainingStringSize = dwTotalStringSize; |
| 854 | for (DWORD i = 0; i < cValues; ++i) | 918 | for (DWORD i = 0; i < cValues; ++i) |
| 855 | { | 919 | { |
| 856 | hr = ::StringCchCopyW(wzCopyDestination, dwTotalStringSize, rgwzValues[i]); | 920 | hr = ::StringCchCopyW(wzCopyDestination, dwRemainingStringSize, rgwzValues[i]); |
| 857 | RegExitOnFailure(hr, "failed to copy string: %ls", rgwzValues[i]); | 921 | RegExitOnFailure(hr, "failed to copy string: %ls", rgwzValues[i]); |
| 858 | 922 | ||
| 859 | dwTemp -= lstrlenW(rgwzValues[i]) + 1; | 923 | dwTemp = lstrlenW(rgwzValues[i]) + 1; |
| 860 | wzCopyDestination += lstrlenW(rgwzValues[i]) + 1; | 924 | dwRemainingStringSize -= dwTemp; |
| 925 | wzCopyDestination += dwTemp; | ||
| 861 | } | 926 | } |
| 862 | 927 | ||
| 863 | wzWriteValue = sczWriteValue; | 928 | wzWriteValue = sczWriteValue; |
| 864 | } | ||
| 865 | 929 | ||
| 866 | hr = ::DWordMult(dwTotalStringSize, sizeof(WCHAR), &cbTotalStringSize); | 930 | hr = ::DWordMult(dwTotalStringSize, sizeof(WCHAR), &cbTotalStringSize); |
| 867 | RegExitOnFailure(hr, "Failed to get total string size in bytes"); | 931 | RegExitOnFailure(hr, "Failed to get total string size in bytes"); |
| 932 | } | ||
| 868 | 933 | ||
| 869 | er = vpfnRegSetValueExW(hk, wzName, 0, REG_MULTI_SZ, reinterpret_cast<const BYTE *>(wzWriteValue), cbTotalStringSize); | 934 | er = vpfnRegSetValueExW(hk, wzName, 0, REG_MULTI_SZ, reinterpret_cast<const BYTE *>(wzWriteValue), cbTotalStringSize); |
| 870 | RegExitOnWin32Error(er, hr, "Failed to set registry value to array of strings (first string of which is): %ls", wzWriteValue); | 935 | RegExitOnWin32Error(er, hr, "Failed to set registry value to array of strings (first string of which is): %ls", wzWriteValue); |
| @@ -1000,6 +1065,48 @@ DAPI_(REGSAM) RegTranslateKeyBitness( | |||
| 1000 | } | 1065 | } |
| 1001 | } | 1066 | } |
| 1002 | 1067 | ||
| 1068 | static HRESULT GetRegValue( | ||
| 1069 | __in HKEY hk, | ||
| 1070 | __in_z_opt LPCWSTR wzName, | ||
| 1071 | __deref_out_bcount_opt(*pcbBuffer) BYTE* pbBuffer, | ||
| 1072 | __inout SIZE_T* pcbBuffer, | ||
| 1073 | __out DWORD* pdwType | ||
| 1074 | ) | ||
| 1075 | { | ||
| 1076 | HRESULT hr = S_OK; | ||
| 1077 | DWORD cb = (DWORD)min(DWORD_MAX, *pcbBuffer); | ||
| 1078 | |||
| 1079 | if (vpfnRegGetValueW) | ||
| 1080 | { | ||
| 1081 | hr = HRESULT_FROM_WIN32(vpfnRegGetValueW(hk, NULL, wzName, RRF_RT_ANY | RRF_NOEXPAND, pdwType, pbBuffer, &cb)); | ||
| 1082 | } | ||
| 1083 | else | ||
| 1084 | { | ||
| 1085 | hr = HRESULT_FROM_WIN32(vpfnRegQueryValueExW(hk, wzName, NULL, pdwType, pbBuffer, &cb)); | ||
| 1086 | |||
| 1087 | if (REG_SZ == *pdwType || REG_EXPAND_SZ == *pdwType || REG_MULTI_SZ == *pdwType) | ||
| 1088 | { | ||
| 1089 | if (E_MOREDATA == hr || S_OK == hr && (cb + sizeof(WCHAR)) > *pcbBuffer) | ||
| 1090 | { | ||
| 1091 | // Make sure there's room for a null terminator at the end. | ||
| 1092 | HRESULT hrAdd = ::DWordAdd(cb, sizeof(WCHAR), &cb); | ||
| 1093 | |||
| 1094 | hr = FAILED(hrAdd) ? hrAdd : (pbBuffer ? E_MOREDATA : S_OK); | ||
| 1095 | } | ||
| 1096 | else if (S_OK == hr && pbBuffer) | ||
| 1097 | { | ||
| 1098 | // Always ensure the registry value is null terminated. | ||
| 1099 | WCHAR* pch = reinterpret_cast<WCHAR*>(pbBuffer + cb); | ||
| 1100 | *pch = L'\0'; | ||
| 1101 | } | ||
| 1102 | } | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | *pcbBuffer = cb; | ||
| 1106 | |||
| 1107 | return hr; | ||
| 1108 | } | ||
| 1109 | |||
| 1003 | static HRESULT WriteStringToRegistry( | 1110 | static HRESULT WriteStringToRegistry( |
| 1004 | __in HKEY hk, | 1111 | __in HKEY hk, |
| 1005 | __in_z_opt LPCWSTR wzName, | 1112 | __in_z_opt LPCWSTR wzName, |
| @@ -1013,9 +1120,12 @@ static HRESULT WriteStringToRegistry( | |||
| 1013 | 1120 | ||
| 1014 | if (wzValue) | 1121 | if (wzValue) |
| 1015 | { | 1122 | { |
| 1016 | hr = ::StringCbLengthW(wzValue, STRSAFE_MAX_CCH * sizeof(TCHAR), &cbValue); | 1123 | hr = ::StringCbLengthW(wzValue, DWORD_MAX, &cbValue); |
| 1017 | RegExitOnFailure(hr, "Failed to determine length of registry value: %ls", wzName); | 1124 | RegExitOnFailure(hr, "Failed to determine length of registry value: %ls", wzName); |
| 1018 | 1125 | ||
| 1126 | // Need to include the null terminator. | ||
| 1127 | cbValue += sizeof(WCHAR); | ||
| 1128 | |||
| 1019 | er = vpfnRegSetValueExW(hk, wzName, 0, dwType, reinterpret_cast<const BYTE *>(wzValue), static_cast<DWORD>(cbValue)); | 1129 | er = vpfnRegSetValueExW(hk, wzName, 0, dwType, reinterpret_cast<const BYTE *>(wzValue), static_cast<DWORD>(cbValue)); |
| 1020 | RegExitOnWin32Error(er, hr, "Failed to set registry value: %ls", wzName); | 1130 | RegExitOnWin32Error(er, hr, "Failed to set registry value: %ls", wzName); |
| 1021 | } | 1131 | } |
