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