aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/regutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/regutil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/regutil.cpp1035
1 files changed, 1035 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/regutil.cpp b/src/libs/dutil/WixToolset.DUtil/regutil.cpp
new file mode 100644
index 00000000..cb617932
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/regutil.cpp
@@ -0,0 +1,1035 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define RegExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__)
8#define RegExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(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__)
11#define RegExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_REGUTIL, x, s, __VA_ARGS__)
12#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 RegExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_REGUTIL, p, x, s, __VA_ARGS__)
15#define RegExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_REGUTIL, p, x, e, s, __VA_ARGS__)
16#define RegExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_REGUTIL, p, x, s, __VA_ARGS__)
17#define RegExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_REGUTIL, e, x, s, __VA_ARGS__)
18#define RegExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_REGUTIL, g, x, s, __VA_ARGS__)
19
20static PFN_REGCREATEKEYEXW vpfnRegCreateKeyExW = ::RegCreateKeyExW;
21static PFN_REGOPENKEYEXW vpfnRegOpenKeyExW = ::RegOpenKeyExW;
22static PFN_REGDELETEKEYEXW vpfnRegDeleteKeyExW = NULL;
23static PFN_REGDELETEKEYEXW vpfnRegDeleteKeyExWFromLibrary = NULL;
24static PFN_REGDELETEKEYW vpfnRegDeleteKeyW = ::RegDeleteKeyW;
25static PFN_REGENUMKEYEXW vpfnRegEnumKeyExW = ::RegEnumKeyExW;
26static PFN_REGENUMVALUEW vpfnRegEnumValueW = ::RegEnumValueW;
27static PFN_REGQUERYINFOKEYW vpfnRegQueryInfoKeyW = ::RegQueryInfoKeyW;
28static PFN_REGQUERYVALUEEXW vpfnRegQueryValueExW = ::RegQueryValueExW;
29static PFN_REGSETVALUEEXW vpfnRegSetValueExW = ::RegSetValueExW;
30static PFN_REGDELETEVALUEW vpfnRegDeleteValueW = ::RegDeleteValueW;
31
32static HMODULE vhAdvApi32Dll = NULL;
33static BOOL vfRegInitialized = FALSE;
34
35static HRESULT WriteStringToRegistry(
36 __in HKEY hk,
37 __in_z_opt LPCWSTR wzName,
38 __in_z_opt LPCWSTR wzValue,
39 __in DWORD dwType
40);
41
42/********************************************************************
43 RegInitialize - initializes regutil
44
45*********************************************************************/
46extern "C" HRESULT DAPI RegInitialize(
47 )
48{
49 HRESULT hr = S_OK;
50
51 hr = LoadSystemLibrary(L"AdvApi32.dll", &vhAdvApi32Dll);
52 RegExitOnFailure(hr, "Failed to load AdvApi32.dll");
53
54 // ignore failures - if this doesn't exist, we'll fall back to RegDeleteKeyW
55 vpfnRegDeleteKeyExWFromLibrary = reinterpret_cast<PFN_REGDELETEKEYEXW>(::GetProcAddress(vhAdvApi32Dll, "RegDeleteKeyExW"));
56
57 if (NULL == vpfnRegDeleteKeyExW)
58 {
59 vpfnRegDeleteKeyExW = vpfnRegDeleteKeyExWFromLibrary;
60 }
61
62 vfRegInitialized = TRUE;
63
64LExit:
65 return hr;
66}
67
68
69/********************************************************************
70 RegUninitialize - uninitializes regutil
71
72*********************************************************************/
73extern "C" void DAPI RegUninitialize(
74 )
75{
76 if (vhAdvApi32Dll)
77 {
78 ::FreeLibrary(vhAdvApi32Dll);
79 vhAdvApi32Dll = NULL;
80 vpfnRegDeleteKeyExWFromLibrary = NULL;
81 vpfnRegDeleteKeyExW = NULL;
82 }
83
84 vfRegInitialized = FALSE;
85}
86
87
88/********************************************************************
89 RegFunctionOverride - overrides the registry functions. Typically used
90 for unit testing.
91
92*********************************************************************/
93extern "C" void DAPI RegFunctionOverride(
94 __in_opt PFN_REGCREATEKEYEXW pfnRegCreateKeyExW,
95 __in_opt PFN_REGOPENKEYEXW pfnRegOpenKeyExW,
96 __in_opt PFN_REGDELETEKEYEXW pfnRegDeleteKeyExW,
97 __in_opt PFN_REGENUMKEYEXW pfnRegEnumKeyExW,
98 __in_opt PFN_REGENUMVALUEW pfnRegEnumValueW,
99 __in_opt PFN_REGQUERYINFOKEYW pfnRegQueryInfoKeyW,
100 __in_opt PFN_REGQUERYVALUEEXW pfnRegQueryValueExW,
101 __in_opt PFN_REGSETVALUEEXW pfnRegSetValueExW,
102 __in_opt PFN_REGDELETEVALUEW pfnRegDeleteValueW
103 )
104{
105 vpfnRegCreateKeyExW = pfnRegCreateKeyExW ? pfnRegCreateKeyExW : ::RegCreateKeyExW;
106 vpfnRegOpenKeyExW = pfnRegOpenKeyExW ? pfnRegOpenKeyExW : ::RegOpenKeyExW;
107 vpfnRegDeleteKeyExW = pfnRegDeleteKeyExW ? pfnRegDeleteKeyExW : vpfnRegDeleteKeyExWFromLibrary;
108 vpfnRegEnumKeyExW = pfnRegEnumKeyExW ? pfnRegEnumKeyExW : ::RegEnumKeyExW;
109 vpfnRegEnumValueW = pfnRegEnumValueW ? pfnRegEnumValueW : ::RegEnumValueW;
110 vpfnRegQueryInfoKeyW = pfnRegQueryInfoKeyW ? pfnRegQueryInfoKeyW : ::RegQueryInfoKeyW;
111 vpfnRegQueryValueExW = pfnRegQueryValueExW ? pfnRegQueryValueExW : ::RegQueryValueExW;
112 vpfnRegSetValueExW = pfnRegSetValueExW ? pfnRegSetValueExW : ::RegSetValueExW;
113 vpfnRegDeleteValueW = pfnRegDeleteValueW ? pfnRegDeleteValueW : ::RegDeleteValueW;
114}
115
116
117/********************************************************************
118 RegCreate - creates a registry key.
119
120*********************************************************************/
121extern "C" HRESULT DAPI RegCreate(
122 __in HKEY hkRoot,
123 __in_z LPCWSTR wzSubKey,
124 __in DWORD dwAccess,
125 __out HKEY* phk
126 )
127{
128 HRESULT hr = S_OK;
129 DWORD er = ERROR_SUCCESS;
130
131 er = vpfnRegCreateKeyExW(hkRoot, wzSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, dwAccess, NULL, phk, NULL);
132 RegExitOnWin32Error(er, hr, "Failed to create registry key.");
133
134LExit:
135 return hr;
136}
137
138
139/********************************************************************
140 RegCreate - creates a registry key with extra options.
141
142*********************************************************************/
143HRESULT DAPI RegCreateEx(
144 __in HKEY hkRoot,
145 __in_z LPCWSTR wzSubKey,
146 __in DWORD dwAccess,
147 __in BOOL fVolatile,
148 __in_opt SECURITY_ATTRIBUTES* pSecurityAttributes,
149 __out HKEY* phk,
150 __out_opt BOOL* pfCreated
151 )
152{
153 HRESULT hr = S_OK;
154 DWORD er = ERROR_SUCCESS;
155 DWORD dwDisposition;
156
157 er = vpfnRegCreateKeyExW(hkRoot, wzSubKey, 0, NULL, fVolatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE, dwAccess, pSecurityAttributes, phk, &dwDisposition);
158 RegExitOnWin32Error(er, hr, "Failed to create registry key.");
159
160 if (pfCreated)
161 {
162 *pfCreated = (REG_CREATED_NEW_KEY == dwDisposition);
163 }
164
165LExit:
166 return hr;
167}
168
169
170/********************************************************************
171 RegOpen - opens a registry key.
172
173*********************************************************************/
174extern "C" HRESULT DAPI RegOpen(
175 __in HKEY hkRoot,
176 __in_z LPCWSTR wzSubKey,
177 __in DWORD dwAccess,
178 __out HKEY* phk
179 )
180{
181 HRESULT hr = S_OK;
182 DWORD er = ERROR_SUCCESS;
183
184 er = vpfnRegOpenKeyExW(hkRoot, wzSubKey, 0, dwAccess, phk);
185 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
186 {
187 ExitFunction1(hr = E_FILENOTFOUND);
188 }
189 RegExitOnWin32Error(er, hr, "Failed to open registry key.");
190
191LExit:
192 return hr;
193}
194
195
196/********************************************************************
197 RegDelete - deletes a registry key (and optionally it's whole tree).
198
199*********************************************************************/
200extern "C" HRESULT DAPI RegDelete(
201 __in HKEY hkRoot,
202 __in_z LPCWSTR wzSubKey,
203 __in REG_KEY_BITNESS kbKeyBitness,
204 __in BOOL fDeleteTree
205 )
206{
207 HRESULT hr = S_OK;
208 DWORD er = ERROR_SUCCESS;
209 LPWSTR pszEnumeratedSubKey = NULL;
210 LPWSTR pszRecursiveSubKey = NULL;
211 HKEY hkKey = NULL;
212 REGSAM samDesired = 0;
213
214 if (!vfRegInitialized && REG_KEY_DEFAULT != kbKeyBitness)
215 {
216 hr = E_INVALIDARG;
217 RegExitOnFailure(hr, "RegInitialize must be called first in order to RegDelete() a key with non-default bit attributes!");
218 }
219
220 switch (kbKeyBitness)
221 {
222 case REG_KEY_32BIT:
223 samDesired = KEY_WOW64_32KEY;
224 break;
225 case REG_KEY_64BIT:
226 samDesired = KEY_WOW64_64KEY;
227 break;
228 case REG_KEY_DEFAULT:
229 // Nothing to do
230 break;
231 }
232
233 if (fDeleteTree)
234 {
235 hr = RegOpen(hkRoot, wzSubKey, KEY_READ | samDesired, &hkKey);
236 if (E_FILENOTFOUND == hr)
237 {
238 ExitFunction1(hr = S_OK);
239 }
240 RegExitOnFailure(hr, "Failed to open this key for enumerating subkeys: %ls", wzSubKey);
241
242 // Yes, keep enumerating the 0th item, because we're deleting it every time
243 while (E_NOMOREITEMS != (hr = RegKeyEnum(hkKey, 0, &pszEnumeratedSubKey)))
244 {
245 RegExitOnFailure(hr, "Failed to enumerate key 0");
246
247 hr = PathConcat(wzSubKey, pszEnumeratedSubKey, &pszRecursiveSubKey);
248 RegExitOnFailure(hr, "Failed to concatenate paths while recursively deleting subkeys. Path1: %ls, Path2: %ls", wzSubKey, pszEnumeratedSubKey);
249
250 hr = RegDelete(hkRoot, pszRecursiveSubKey, kbKeyBitness, fDeleteTree);
251 RegExitOnFailure(hr, "Failed to recursively delete subkey: %ls", pszRecursiveSubKey);
252 }
253
254 hr = S_OK;
255 }
256
257 if (NULL != vpfnRegDeleteKeyExW)
258 {
259 er = vpfnRegDeleteKeyExW(hkRoot, wzSubKey, samDesired, 0);
260 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
261 {
262 ExitFunction1(hr = E_FILENOTFOUND);
263 }
264 RegExitOnWin32Error(er, hr, "Failed to delete registry key (ex).");
265 }
266 else
267 {
268 er = vpfnRegDeleteKeyW(hkRoot, wzSubKey);
269 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
270 {
271 ExitFunction1(hr = E_FILENOTFOUND);
272 }
273 RegExitOnWin32Error(er, hr, "Failed to delete registry key.");
274 }
275
276LExit:
277 ReleaseRegKey(hkKey);
278 ReleaseStr(pszEnumeratedSubKey);
279 ReleaseStr(pszRecursiveSubKey);
280
281 return hr;
282}
283
284
285/********************************************************************
286 RegKeyEnum - enumerates child registry keys.
287
288*********************************************************************/
289extern "C" HRESULT DAPI RegKeyEnum(
290 __in HKEY hk,
291 __in DWORD dwIndex,
292 __deref_out_z LPWSTR* psczKey
293 )
294{
295 HRESULT hr = S_OK;
296 DWORD er = ERROR_SUCCESS;
297 SIZE_T cb = 0;
298 DWORD cch = 0;
299
300 if (psczKey && *psczKey)
301 {
302 hr = StrMaxLength(*psczKey, &cb);
303 RegExitOnFailure(hr, "Failed to determine length of string.");
304
305 cch = (DWORD)min(DWORD_MAX, cb);
306 }
307
308 if (2 > cch)
309 {
310 cch = 2;
311
312 hr = StrAlloc(psczKey, cch);
313 RegExitOnFailure(hr, "Failed to allocate string to minimum size.");
314 }
315
316 er = vpfnRegEnumKeyExW(hk, dwIndex, *psczKey, &cch, NULL, NULL, NULL, NULL);
317 if (ERROR_MORE_DATA == er)
318 {
319 er = vpfnRegQueryInfoKeyW(hk, NULL, NULL, NULL, NULL, &cch, NULL, NULL, NULL, NULL, NULL, NULL);
320 RegExitOnWin32Error(er, hr, "Failed to get max size of subkey name under registry key.");
321
322 ++cch; // add one because RegQueryInfoKeyW() returns the length of the subkeys without the null terminator.
323 hr = StrAlloc(psczKey, cch);
324 RegExitOnFailure(hr, "Failed to allocate string bigger for enum registry key.");
325
326 er = vpfnRegEnumKeyExW(hk, dwIndex, *psczKey, &cch, NULL, NULL, NULL, NULL);
327 }
328 else if (ERROR_NO_MORE_ITEMS == er)
329 {
330 ExitFunction1(hr = E_NOMOREITEMS);
331 }
332 RegExitOnWin32Error(er, hr, "Failed to enum registry key.");
333
334 // Always ensure the registry key name is null terminated.
335#pragma prefast(push)
336#pragma prefast(disable:26018)
337 (*psczKey)[cch] = L'\0'; // note that cch will always be one less than the size of the buffer because that's how RegEnumKeyExW() works.
338#pragma prefast(pop)
339
340LExit:
341 return hr;
342}
343
344
345/********************************************************************
346 RegValueEnum - enumerates registry values.
347
348*********************************************************************/
349HRESULT DAPI RegValueEnum(
350 __in HKEY hk,
351 __in DWORD dwIndex,
352 __deref_out_z LPWSTR* psczName,
353 __out_opt DWORD *pdwType
354 )
355{
356 HRESULT hr = S_OK;
357 DWORD er = ERROR_SUCCESS;
358 DWORD cbValueName = 0;
359
360 er = vpfnRegQueryInfoKeyW(hk, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cbValueName, NULL, NULL, NULL);
361 RegExitOnWin32Error(er, hr, "Failed to get max size of value name under registry key.");
362
363 // Add one for null terminator
364 ++cbValueName;
365
366 hr = StrAlloc(psczName, cbValueName);
367 RegExitOnFailure(hr, "Failed to allocate array for registry value name");
368
369 er = vpfnRegEnumValueW(hk, dwIndex, *psczName, &cbValueName, NULL, pdwType, NULL, NULL);
370 if (ERROR_NO_MORE_ITEMS == er)
371 {
372 ExitFunction1(hr = E_NOMOREITEMS);
373 }
374 RegExitOnWin32Error(er, hr, "Failed to enumerate registry value");
375
376LExit:
377 return hr;
378}
379
380/********************************************************************
381 RegGetType - reads a registry key value type.
382 *********************************************************************/
383HRESULT DAPI RegGetType(
384 __in HKEY hk,
385 __in_z_opt LPCWSTR wzName,
386 __out DWORD *pdwType
387 )
388{
389 HRESULT hr = S_OK;
390 DWORD er = ERROR_SUCCESS;
391
392 er = vpfnRegQueryValueExW(hk, wzName, NULL, pdwType, NULL, NULL);
393 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
394 {
395 ExitFunction1(hr = E_FILENOTFOUND);
396 }
397 RegExitOnWin32Error(er, hr, "Failed to read registry value.");
398LExit:
399
400 return hr;
401}
402
403/********************************************************************
404 RegReadBinary - reads a registry key binary value.
405 NOTE: caller is responsible for freeing *ppbBuffer
406*********************************************************************/
407HRESULT DAPI RegReadBinary(
408 __in HKEY hk,
409 __in_z_opt LPCWSTR wzName,
410 __deref_out_bcount_opt(*pcbBuffer) BYTE** ppbBuffer,
411 __out SIZE_T *pcbBuffer
412 )
413{
414 HRESULT hr = S_OK;
415 LPBYTE pbBuffer = NULL;
416 DWORD er = ERROR_SUCCESS;
417 DWORD cb = 0;
418 DWORD dwType = 0;
419
420 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, NULL, &cb);
421 RegExitOnWin32Error(er, hr, "Failed to get size of registry value.");
422
423 // Zero-length binary values can exist
424 if (0 < cb)
425 {
426 pbBuffer = static_cast<LPBYTE>(MemAlloc(cb, FALSE));
427 RegExitOnNull(pbBuffer, hr, E_OUTOFMEMORY, "Failed to allocate buffer for binary registry value.");
428
429 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, pbBuffer, &cb);
430 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
431 {
432 ExitFunction1(hr = E_FILENOTFOUND);
433 }
434 RegExitOnWin32Error(er, hr, "Failed to read registry value.");
435 }
436
437 if (REG_BINARY == dwType)
438 {
439 *ppbBuffer = pbBuffer;
440 pbBuffer = NULL;
441 *pcbBuffer = cb;
442 }
443 else
444 {
445 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
446 RegExitOnRootFailure(hr, "Error reading binary registry value due to unexpected data type: %u", dwType);
447 }
448
449LExit:
450 ReleaseMem(pbBuffer);
451
452 return hr;
453}
454
455
456/********************************************************************
457 RegReadString - reads a registry key value as a string.
458
459*********************************************************************/
460extern "C" HRESULT DAPI RegReadString(
461 __in HKEY hk,
462 __in_z_opt LPCWSTR wzName,
463 __deref_out_z LPWSTR* psczValue
464 )
465{
466 HRESULT hr = S_OK;
467 DWORD er = ERROR_SUCCESS;
468 SIZE_T cbValue = 0;
469 DWORD cch = 0;
470 DWORD cb = 0;
471 DWORD dwType = 0;
472 LPWSTR sczExpand = NULL;
473
474 if (psczValue && *psczValue)
475 {
476 hr = StrMaxLength(*psczValue, &cbValue);
477 RegExitOnFailure(hr, "Failed to determine length of string.");
478
479 cch = (DWORD)min(DWORD_MAX, cbValue);
480 }
481
482 if (2 > cch)
483 {
484 cch = 2;
485
486 hr = StrAlloc(psczValue, cch);
487 RegExitOnFailure(hr, "Failed to allocate string to minimum size.");
488 }
489
490 cb = sizeof(WCHAR) * (cch - 1); // subtract one to ensure there will be a space at the end of the string for the null terminator.
491 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(*psczValue), &cb);
492 if (ERROR_MORE_DATA == er)
493 {
494 cch = cb / sizeof(WCHAR) + 1; // add one to ensure there will be space at the end for the null terminator
495 hr = StrAlloc(psczValue, cch);
496 RegExitOnFailure(hr, "Failed to allocate string bigger for registry value.");
497
498 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(*psczValue), &cb);
499 }
500 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
501 {
502 ExitFunction1(hr = E_FILENOTFOUND);
503 }
504 RegExitOnWin32Error(er, hr, "Failed to read registry key.");
505
506 if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
507 {
508 // Always ensure the registry value is null terminated.
509 (*psczValue)[cch - 1] = L'\0';
510
511 if (REG_EXPAND_SZ == dwType)
512 {
513 hr = StrAllocString(&sczExpand, *psczValue, 0);
514 RegExitOnFailure(hr, "Failed to copy registry value to expand.");
515
516 hr = PathExpand(psczValue, sczExpand, PATH_EXPAND_ENVIRONMENT);
517 RegExitOnFailure(hr, "Failed to expand registry value: %ls", *psczValue);
518 }
519 }
520 else
521 {
522 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
523 RegExitOnRootFailure(hr, "Error reading string registry value due to unexpected data type: %u", dwType);
524 }
525
526LExit:
527 ReleaseStr(sczExpand);
528
529 return hr;
530}
531
532
533/********************************************************************
534 RegReadStringArray - reads a registry key value REG_MULTI_SZ value as a string array.
535
536*********************************************************************/
537HRESULT DAPI RegReadStringArray(
538 __in HKEY hk,
539 __in_z_opt LPCWSTR wzName,
540 __deref_out_ecount_opt(*pcStrings) LPWSTR** prgsczStrings,
541 __out DWORD *pcStrings
542 )
543{
544 HRESULT hr = S_OK;
545 DWORD er = ERROR_SUCCESS;
546 DWORD dwNullCharacters = 0;
547 DWORD dwType = 0;
548 DWORD cb = 0;
549 DWORD cch = 0;
550 LPCWSTR wzSource = NULL;
551 LPWSTR sczValue = NULL;
552
553 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(sczValue), &cb);
554 if (0 < cb)
555 {
556 cch = cb / sizeof(WCHAR);
557 hr = StrAlloc(&sczValue, cch);
558 RegExitOnFailure(hr, "Failed to allocate string for registry value.");
559
560 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(sczValue), &cb);
561 }
562 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
563 {
564 ExitFunction1(hr = E_FILENOTFOUND);
565 }
566 RegExitOnWin32Error(er, hr, "Failed to read registry key.");
567
568 if (cb / sizeof(WCHAR) != cch)
569 {
570 hr = E_UNEXPECTED;
571 RegExitOnFailure(hr, "The size of registry value %ls unexpected changed between 2 reads", wzName);
572 }
573
574 if (REG_MULTI_SZ != dwType)
575 {
576 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
577 RegExitOnRootFailure(hr, "Tried to read string array, but registry value %ls is of an incorrect type", wzName);
578 }
579
580 // Value exists, but is empty, so no strings to return.
581 if (2 > cch)
582 {
583 *prgsczStrings = NULL;
584 *pcStrings = 0;
585 ExitFunction1(hr = S_OK);
586 }
587
588 // The docs specifically say if the value was written without double-null-termination, it'll get read back without it too.
589 if (L'\0' != sczValue[cch-1] || L'\0' != sczValue[cch-2])
590 {
591 hr = E_INVALIDARG;
592 RegExitOnFailure(hr, "Tried to read string array, but registry value %ls is invalid (isn't double-null-terminated)", wzName);
593 }
594
595 cch = cb / sizeof(WCHAR);
596 for (DWORD i = 0; i < cch; ++i)
597 {
598 if (L'\0' == sczValue[i])
599 {
600 ++dwNullCharacters;
601 }
602 }
603
604 // There's one string for every null character encountered (except the extra 1 at the end of the string)
605 *pcStrings = dwNullCharacters - 1;
606 hr = MemEnsureArraySize(reinterpret_cast<LPVOID *>(prgsczStrings), *pcStrings, sizeof(LPWSTR), 0);
607 RegExitOnFailure(hr, "Failed to resize array while reading REG_MULTI_SZ value");
608
609#pragma prefast(push)
610#pragma prefast(disable:26010)
611 wzSource = sczValue;
612 for (DWORD i = 0; i < *pcStrings; ++i)
613 {
614 hr = StrAllocString(&(*prgsczStrings)[i], wzSource, 0);
615 RegExitOnFailure(hr, "Failed to allocate copy of string");
616
617 // Skip past this string
618 wzSource += lstrlenW(wzSource) + 1;
619 }
620#pragma prefast(pop)
621
622LExit:
623 ReleaseStr(sczValue);
624
625 return hr;
626}
627
628
629/********************************************************************
630 RegReadVersion - reads a registry key value as a version.
631
632*********************************************************************/
633extern "C" HRESULT DAPI RegReadVersion(
634 __in HKEY hk,
635 __in_z_opt LPCWSTR wzName,
636 __out DWORD64* pdw64Version
637 )
638{
639 HRESULT hr = S_OK;
640 DWORD er = ERROR_SUCCESS;
641 DWORD dwType = 0;
642 DWORD cb = 0;
643 LPWSTR sczVersion = NULL;
644
645 cb = sizeof(DWORD64);
646 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(*pdw64Version), &cb);
647 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
648 {
649 ExitFunction1(hr = E_FILENOTFOUND);
650 }
651 if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
652 {
653 hr = RegReadString(hk, wzName, &sczVersion);
654 RegExitOnFailure(hr, "Failed to read registry version as string.");
655
656 hr = FileVersionFromStringEx(sczVersion, 0, pdw64Version);
657 RegExitOnFailure(hr, "Failed to convert registry string to version.");
658 }
659 else if (REG_QWORD == dwType)
660 {
661 RegExitOnWin32Error(er, hr, "Failed to read registry key.");
662 }
663 else // unexpected data type
664 {
665 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
666 RegExitOnRootFailure(hr, "Error reading version registry value due to unexpected data type: %u", dwType);
667 }
668
669LExit:
670 ReleaseStr(sczVersion);
671
672 return hr;
673}
674
675
676/********************************************************************
677 RegReadNumber - reads a DWORD registry key value as a number.
678
679*********************************************************************/
680extern "C" HRESULT DAPI RegReadNumber(
681 __in HKEY hk,
682 __in_z_opt LPCWSTR wzName,
683 __out DWORD* pdwValue
684 )
685{
686 HRESULT hr = S_OK;
687 DWORD er = ERROR_SUCCESS;
688 DWORD dwType = 0;
689 DWORD cb = sizeof(DWORD);
690
691 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(pdwValue), &cb);
692 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
693 {
694 ExitFunction1(hr = E_FILENOTFOUND);
695 }
696 RegExitOnWin32Error(er, hr, "Failed to query registry key value.");
697
698 if (REG_DWORD != dwType)
699 {
700 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
701 RegExitOnRootFailure(hr, "Error reading version registry value due to unexpected data type: %u", dwType);
702 }
703
704LExit:
705 return hr;
706}
707
708
709/********************************************************************
710 RegReadQword - reads a QWORD registry key value as a number.
711
712*********************************************************************/
713extern "C" HRESULT DAPI RegReadQword(
714 __in HKEY hk,
715 __in_z_opt LPCWSTR wzName,
716 __out DWORD64* pqwValue
717 )
718{
719 HRESULT hr = S_OK;
720 DWORD er = ERROR_SUCCESS;
721 DWORD dwType = 0;
722 DWORD cb = sizeof(DWORD64);
723
724 er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(pqwValue), &cb);
725 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
726 {
727 ExitFunction1(hr = E_FILENOTFOUND);
728 }
729 RegExitOnWin32Error(er, hr, "Failed to query registry key value.");
730
731 if (REG_QWORD != dwType)
732 {
733 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
734 RegExitOnRootFailure(hr, "Error reading version registry value due to unexpected data type: %u", dwType);
735 }
736
737LExit:
738 return hr;
739}
740
741
742/********************************************************************
743 RegWriteBinary - writes a registry key value as a binary.
744
745*********************************************************************/
746HRESULT DAPI RegWriteBinary(
747 __in HKEY hk,
748 __in_z_opt LPCWSTR wzName,
749 __in_bcount(cbBuffer) const BYTE *pbBuffer,
750 __in DWORD cbBuffer
751 )
752{
753 HRESULT hr = S_OK;
754 DWORD er = ERROR_SUCCESS;
755
756 er = vpfnRegSetValueExW(hk, wzName, 0, REG_BINARY, pbBuffer, cbBuffer);
757 RegExitOnWin32Error(er, hr, "Failed to write binary registry value with name: %ls", wzName);
758
759LExit:
760 return hr;
761}
762
763
764/********************************************************************
765RegWriteExpandString - writes a registry key value as an expand string.
766
767Note: if wzValue is NULL the value will be removed.
768*********************************************************************/
769extern "C" HRESULT DAPI RegWriteExpandString(
770 __in HKEY hk,
771 __in_z_opt LPCWSTR wzName,
772 __in_z_opt LPCWSTR wzValue
773)
774{
775 return WriteStringToRegistry(hk, wzName, wzValue, REG_EXPAND_SZ);
776}
777
778
779/********************************************************************
780 RegWriteString - writes a registry key value as a string.
781
782 Note: if wzValue is NULL the value will be removed.
783*********************************************************************/
784extern "C" HRESULT DAPI RegWriteString(
785 __in HKEY hk,
786 __in_z_opt LPCWSTR wzName,
787 __in_z_opt LPCWSTR wzValue
788 )
789{
790 return WriteStringToRegistry(hk, wzName, wzValue, REG_SZ);
791}
792
793
794/********************************************************************
795 RegWriteStringFormatted - writes a registry key value as a formatted string.
796
797*********************************************************************/
798extern "C" HRESULT DAPI RegWriteStringFormatted(
799 __in HKEY hk,
800 __in_z_opt LPCWSTR wzName,
801 __in __format_string LPCWSTR szFormat,
802 ...
803 )
804{
805 HRESULT hr = S_OK;
806 LPWSTR sczValue = NULL;
807 va_list args;
808
809 va_start(args, szFormat);
810 hr = StrAllocFormattedArgs(&sczValue, szFormat, args);
811 va_end(args);
812 RegExitOnFailure(hr, "Failed to allocate %ls value.", wzName);
813
814 hr = WriteStringToRegistry(hk, wzName, sczValue, REG_SZ);
815
816LExit:
817 ReleaseStr(sczValue);
818
819 return hr;
820}
821
822
823/********************************************************************
824 RegWriteStringArray - writes an array of strings as a REG_MULTI_SZ value
825
826*********************************************************************/
827HRESULT DAPI RegWriteStringArray(
828 __in HKEY hk,
829 __in_z_opt LPCWSTR wzName,
830 __in_ecount(cValues) LPWSTR *rgwzValues,
831 __in DWORD cValues
832 )
833{
834 HRESULT hr = S_OK;
835 DWORD er = ERROR_SUCCESS;
836 LPWSTR wzCopyDestination = NULL;
837 LPCWSTR wzWriteValue = NULL;
838 LPWSTR sczWriteValue = NULL;
839 DWORD dwTotalStringSize = 0;
840 DWORD cbTotalStringSize = 0;
841 DWORD dwTemp = 0;
842
843 if (0 == cValues)
844 {
845 wzWriteValue = L"\0";
846 }
847 else
848 {
849 // Add space for the null terminator
850 dwTotalStringSize = 1;
851
852 for (DWORD i = 0; i < cValues; ++i)
853 {
854 dwTemp = dwTotalStringSize;
855 hr = ::DWordAdd(dwTemp, 1 + lstrlenW(rgwzValues[i]), &dwTotalStringSize);
856 RegExitOnFailure(hr, "DWORD Overflow while adding length of string to write REG_MULTI_SZ");
857 }
858
859 hr = StrAlloc(&sczWriteValue, dwTotalStringSize);
860 RegExitOnFailure(hr, "Failed to allocate space for string while writing REG_MULTI_SZ");
861
862 wzCopyDestination = sczWriteValue;
863 dwTemp = dwTotalStringSize;
864 for (DWORD i = 0; i < cValues; ++i)
865 {
866 hr = ::StringCchCopyW(wzCopyDestination, dwTotalStringSize, rgwzValues[i]);
867 RegExitOnFailure(hr, "failed to copy string: %ls", rgwzValues[i]);
868
869 dwTemp -= lstrlenW(rgwzValues[i]) + 1;
870 wzCopyDestination += lstrlenW(rgwzValues[i]) + 1;
871 }
872
873 wzWriteValue = sczWriteValue;
874 }
875
876 hr = ::DWordMult(dwTotalStringSize, sizeof(WCHAR), &cbTotalStringSize);
877 RegExitOnFailure(hr, "Failed to get total string size in bytes");
878
879 er = vpfnRegSetValueExW(hk, wzName, 0, REG_MULTI_SZ, reinterpret_cast<const BYTE *>(wzWriteValue), cbTotalStringSize);
880 RegExitOnWin32Error(er, hr, "Failed to set registry value to array of strings (first string of which is): %ls", wzWriteValue);
881
882LExit:
883 ReleaseStr(sczWriteValue);
884
885 return hr;
886}
887
888/********************************************************************
889 RegWriteNumber - writes a registry key value as a number.
890
891*********************************************************************/
892extern "C" HRESULT DAPI RegWriteNumber(
893 __in HKEY hk,
894 __in_z_opt LPCWSTR wzName,
895 __in DWORD dwValue
896 )
897{
898 HRESULT hr = S_OK;
899 DWORD er = ERROR_SUCCESS;
900
901 er = vpfnRegSetValueExW(hk, wzName, 0, REG_DWORD, reinterpret_cast<const BYTE *>(&dwValue), sizeof(dwValue));
902 RegExitOnWin32Error(er, hr, "Failed to set %ls value.", wzName);
903
904LExit:
905 return hr;
906}
907
908/********************************************************************
909 RegWriteQword - writes a registry key value as a Qword.
910
911*********************************************************************/
912extern "C" HRESULT DAPI RegWriteQword(
913 __in HKEY hk,
914 __in_z_opt LPCWSTR wzName,
915 __in DWORD64 qwValue
916 )
917{
918 HRESULT hr = S_OK;
919 DWORD er = ERROR_SUCCESS;
920
921 er = vpfnRegSetValueExW(hk, wzName, 0, REG_QWORD, reinterpret_cast<const BYTE *>(&qwValue), sizeof(qwValue));
922 RegExitOnWin32Error(er, hr, "Failed to set %ls value.", wzName);
923
924LExit:
925 return hr;
926}
927
928/********************************************************************
929 RegQueryKey - queries the key for the number of subkeys and values.
930
931*********************************************************************/
932extern "C" HRESULT DAPI RegQueryKey(
933 __in HKEY hk,
934 __out_opt DWORD* pcSubKeys,
935 __out_opt DWORD* pcValues
936 )
937{
938 HRESULT hr = S_OK;
939 DWORD er = ERROR_SUCCESS;
940
941 er = vpfnRegQueryInfoKeyW(hk, NULL, NULL, NULL, pcSubKeys, NULL, NULL, pcValues, NULL, NULL, NULL, NULL);
942 RegExitOnWin32Error(er, hr, "Failed to get the number of subkeys and values under registry key.");
943
944LExit:
945 return hr;
946}
947
948/********************************************************************
949RegKeyReadNumber - reads a DWORD registry key value as a number from
950a specified subkey.
951
952*********************************************************************/
953extern "C" HRESULT DAPI RegKeyReadNumber(
954 __in HKEY hk,
955 __in_z LPCWSTR wzSubKey,
956 __in_z_opt LPCWSTR wzName,
957 __in BOOL f64Bit,
958 __out DWORD* pdwValue
959 )
960{
961 HRESULT hr = S_OK;
962 HKEY hkKey = NULL;
963
964 hr = RegOpen(hk, wzSubKey, KEY_READ | f64Bit ? KEY_WOW64_64KEY : 0, &hkKey);
965 RegExitOnFailure(hr, "Failed to open key: %ls", wzSubKey);
966
967 hr = RegReadNumber(hkKey, wzName, pdwValue);
968 RegExitOnFailure(hr, "Failed to read value: %ls/@%ls", wzSubKey, wzName);
969
970LExit:
971 ReleaseRegKey(hkKey);
972
973 return hr;
974}
975
976/********************************************************************
977RegValueExists - determines whether a named value exists in a
978specified subkey.
979
980*********************************************************************/
981extern "C" BOOL DAPI RegValueExists(
982 __in HKEY hk,
983 __in_z LPCWSTR wzSubKey,
984 __in_z_opt LPCWSTR wzName,
985 __in BOOL f64Bit
986 )
987{
988 HRESULT hr = S_OK;
989 HKEY hkKey = NULL;
990 DWORD dwType = 0;
991
992 hr = RegOpen(hk, wzSubKey, KEY_READ | f64Bit ? KEY_WOW64_64KEY : 0, &hkKey);
993 RegExitOnFailure(hr, "Failed to open key: %ls", wzSubKey);
994
995 hr = RegGetType(hkKey, wzName, &dwType);
996 RegExitOnFailure(hr, "Failed to read value type: %ls/@%ls", wzSubKey, wzName);
997
998LExit:
999 ReleaseRegKey(hkKey);
1000
1001 return SUCCEEDED(hr);
1002}
1003
1004static HRESULT WriteStringToRegistry(
1005 __in HKEY hk,
1006 __in_z_opt LPCWSTR wzName,
1007 __in_z_opt LPCWSTR wzValue,
1008 __in DWORD dwType
1009 )
1010{
1011 HRESULT hr = S_OK;
1012 DWORD er = ERROR_SUCCESS;
1013 size_t cbValue = 0;
1014
1015 if (wzValue)
1016 {
1017 hr = ::StringCbLengthW(wzValue, STRSAFE_MAX_CCH * sizeof(TCHAR), &cbValue);
1018 RegExitOnFailure(hr, "Failed to determine length of registry value: %ls", wzName);
1019
1020 er = vpfnRegSetValueExW(hk, wzName, 0, dwType, reinterpret_cast<const BYTE *>(wzValue), static_cast<DWORD>(cbValue));
1021 RegExitOnWin32Error(er, hr, "Failed to set registry value: %ls", wzName);
1022 }
1023 else
1024 {
1025 er = vpfnRegDeleteValueW(hk, wzName);
1026 if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er)
1027 {
1028 er = ERROR_SUCCESS;
1029 }
1030 RegExitOnWin32Error(er, hr, "Failed to delete registry value: %ls", wzName);
1031 }
1032
1033LExit:
1034 return hr;
1035}