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 | |
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')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/inc/regutil.h | 44 | ||||
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/regutil.cpp | 420 |
2 files changed, 308 insertions, 156 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/regutil.h b/src/libs/dutil/WixToolset.DUtil/inc/regutil.h index 76d2d7cb..f5b40291 100644 --- a/src/libs/dutil/WixToolset.DUtil/inc/regutil.h +++ b/src/libs/dutil/WixToolset.DUtil/inc/regutil.h | |||
@@ -99,6 +99,15 @@ typedef LSTATUS (APIENTRY *PFN_REGDELETEVALUEW)( | |||
99 | __in HKEY hKey, | 99 | __in HKEY hKey, |
100 | __in_opt LPCWSTR lpValueName | 100 | __in_opt LPCWSTR lpValueName |
101 | ); | 101 | ); |
102 | typedef LSTATUS(APIENTRY *PFN_REGGETVALUEW)( | ||
103 | __in HKEY hkey, | ||
104 | __in_opt LPCWSTR lpSubKey, | ||
105 | __in_opt LPCWSTR lpValue, | ||
106 | __in DWORD dwFlags, | ||
107 | __out_opt LPDWORD pdwType, | ||
108 | __out_bcount_part_opt(*pcbData, *pcbData) __out_data_source(REGISTRY) PVOID pvData, | ||
109 | __inout_opt LPDWORD pcbData | ||
110 | ); | ||
102 | 111 | ||
103 | /******************************************************************** | 112 | /******************************************************************** |
104 | RegInitialize - initializes regutil | 113 | RegInitialize - initializes regutil |
@@ -126,10 +135,18 @@ void DAPI RegFunctionOverride( | |||
126 | __in_opt PFN_REGQUERYINFOKEYW pfnRegQueryInfoKeyW, | 135 | __in_opt PFN_REGQUERYINFOKEYW pfnRegQueryInfoKeyW, |
127 | __in_opt PFN_REGQUERYVALUEEXW pfnRegQueryValueExW, | 136 | __in_opt PFN_REGQUERYVALUEEXW pfnRegQueryValueExW, |
128 | __in_opt PFN_REGSETVALUEEXW pfnRegSetValueExW, | 137 | __in_opt PFN_REGSETVALUEEXW pfnRegSetValueExW, |
129 | __in_opt PFN_REGDELETEVALUEW pfnRegDeleteValueW | 138 | __in_opt PFN_REGDELETEVALUEW pfnRegDeleteValueW, |
139 | __in_opt PFN_REGGETVALUEW pfnRegGetValueW | ||
130 | ); | 140 | ); |
131 | 141 | ||
132 | /******************************************************************** | 142 | /******************************************************************** |
143 | RegFunctionForceFallback - ignore functions only available in newer versions of Windows. | ||
144 | Typically used for unit testing. | ||
145 | |||
146 | *********************************************************************/ | ||
147 | void DAPI RegFunctionForceFallback(); | ||
148 | |||
149 | /******************************************************************** | ||
133 | RegCreate - creates a registry key. | 150 | RegCreate - creates a registry key. |
134 | 151 | ||
135 | *********************************************************************/ | 152 | *********************************************************************/ |
@@ -220,6 +237,20 @@ HRESULT DAPI RegGetType( | |||
220 | ); | 237 | ); |
221 | 238 | ||
222 | /******************************************************************** | 239 | /******************************************************************** |
240 | RegReadBinary - reads a registry key value. | ||
241 | If fExpand is TRUE and the value is REG_EXPAND_SZ then it will be expanded. | ||
242 | NOTE: caller is responsible for freeing *ppbBuffer | ||
243 | *********************************************************************/ | ||
244 | HRESULT DAPI RegReadValue( | ||
245 | __in HKEY hk, | ||
246 | __in_z_opt LPCWSTR wzName, | ||
247 | __in BOOL fExpand, | ||
248 | __deref_out_bcount_opt(*pcbBuffer) BYTE** ppbBuffer, | ||
249 | __inout SIZE_T* pcbBuffer, | ||
250 | __out DWORD* pdwType | ||
251 | ); | ||
252 | |||
253 | /******************************************************************** | ||
223 | RegReadBinary - reads a registry key binary value. | 254 | RegReadBinary - reads a registry key binary value. |
224 | NOTE: caller is responsible for freeing *ppbBuffer | 255 | NOTE: caller is responsible for freeing *ppbBuffer |
225 | *********************************************************************/ | 256 | *********************************************************************/ |
@@ -241,6 +272,17 @@ HRESULT DAPI RegReadString( | |||
241 | ); | 272 | ); |
242 | 273 | ||
243 | /******************************************************************** | 274 | /******************************************************************** |
275 | RegReadUnexpandedString - reads a registry key value as a string without expanding it. | ||
276 | |||
277 | *********************************************************************/ | ||
278 | HRESULT DAPI RegReadUnexpandedString( | ||
279 | __in HKEY hk, | ||
280 | __in_z_opt LPCWSTR wzName, | ||
281 | __inout BOOL* pfNeedsExpansion, | ||
282 | __deref_out_z LPWSTR* psczValue | ||
283 | ); | ||
284 | |||
285 | /******************************************************************** | ||
244 | RegReadStringArray - reads a registry key value REG_MULTI_SZ value as a string array. | 286 | RegReadStringArray - reads a registry key value REG_MULTI_SZ value as a string array. |
245 | 287 | ||
246 | *********************************************************************/ | 288 | *********************************************************************/ |
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 | } |