diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/regutil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/regutil.cpp | 1035 |
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 | |||
20 | static PFN_REGCREATEKEYEXW vpfnRegCreateKeyExW = ::RegCreateKeyExW; | ||
21 | static PFN_REGOPENKEYEXW vpfnRegOpenKeyExW = ::RegOpenKeyExW; | ||
22 | static PFN_REGDELETEKEYEXW vpfnRegDeleteKeyExW = NULL; | ||
23 | static PFN_REGDELETEKEYEXW vpfnRegDeleteKeyExWFromLibrary = NULL; | ||
24 | static PFN_REGDELETEKEYW vpfnRegDeleteKeyW = ::RegDeleteKeyW; | ||
25 | static PFN_REGENUMKEYEXW vpfnRegEnumKeyExW = ::RegEnumKeyExW; | ||
26 | static PFN_REGENUMVALUEW vpfnRegEnumValueW = ::RegEnumValueW; | ||
27 | static PFN_REGQUERYINFOKEYW vpfnRegQueryInfoKeyW = ::RegQueryInfoKeyW; | ||
28 | static PFN_REGQUERYVALUEEXW vpfnRegQueryValueExW = ::RegQueryValueExW; | ||
29 | static PFN_REGSETVALUEEXW vpfnRegSetValueExW = ::RegSetValueExW; | ||
30 | static PFN_REGDELETEVALUEW vpfnRegDeleteValueW = ::RegDeleteValueW; | ||
31 | |||
32 | static HMODULE vhAdvApi32Dll = NULL; | ||
33 | static BOOL vfRegInitialized = FALSE; | ||
34 | |||
35 | static 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 | *********************************************************************/ | ||
46 | extern "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 | |||
64 | LExit: | ||
65 | return hr; | ||
66 | } | ||
67 | |||
68 | |||
69 | /******************************************************************** | ||
70 | RegUninitialize - uninitializes regutil | ||
71 | |||
72 | *********************************************************************/ | ||
73 | extern "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 | *********************************************************************/ | ||
93 | extern "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 | *********************************************************************/ | ||
121 | extern "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 | |||
134 | LExit: | ||
135 | return hr; | ||
136 | } | ||
137 | |||
138 | |||
139 | /******************************************************************** | ||
140 | RegCreate - creates a registry key with extra options. | ||
141 | |||
142 | *********************************************************************/ | ||
143 | HRESULT 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 | |||
165 | LExit: | ||
166 | return hr; | ||
167 | } | ||
168 | |||
169 | |||
170 | /******************************************************************** | ||
171 | RegOpen - opens a registry key. | ||
172 | |||
173 | *********************************************************************/ | ||
174 | extern "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 | |||
191 | LExit: | ||
192 | return hr; | ||
193 | } | ||
194 | |||
195 | |||
196 | /******************************************************************** | ||
197 | RegDelete - deletes a registry key (and optionally it's whole tree). | ||
198 | |||
199 | *********************************************************************/ | ||
200 | extern "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 | |||
276 | LExit: | ||
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 | *********************************************************************/ | ||
289 | extern "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 | |||
340 | LExit: | ||
341 | return hr; | ||
342 | } | ||
343 | |||
344 | |||
345 | /******************************************************************** | ||
346 | RegValueEnum - enumerates registry values. | ||
347 | |||
348 | *********************************************************************/ | ||
349 | HRESULT 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 | |||
376 | LExit: | ||
377 | return hr; | ||
378 | } | ||
379 | |||
380 | /******************************************************************** | ||
381 | RegGetType - reads a registry key value type. | ||
382 | *********************************************************************/ | ||
383 | HRESULT 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."); | ||
398 | LExit: | ||
399 | |||
400 | return hr; | ||
401 | } | ||
402 | |||
403 | /******************************************************************** | ||
404 | RegReadBinary - reads a registry key binary value. | ||
405 | NOTE: caller is responsible for freeing *ppbBuffer | ||
406 | *********************************************************************/ | ||
407 | HRESULT 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 | |||
449 | LExit: | ||
450 | ReleaseMem(pbBuffer); | ||
451 | |||
452 | return hr; | ||
453 | } | ||
454 | |||
455 | |||
456 | /******************************************************************** | ||
457 | RegReadString - reads a registry key value as a string. | ||
458 | |||
459 | *********************************************************************/ | ||
460 | extern "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 | |||
526 | LExit: | ||
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 | *********************************************************************/ | ||
537 | HRESULT 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 | |||
622 | LExit: | ||
623 | ReleaseStr(sczValue); | ||
624 | |||
625 | return hr; | ||
626 | } | ||
627 | |||
628 | |||
629 | /******************************************************************** | ||
630 | RegReadVersion - reads a registry key value as a version. | ||
631 | |||
632 | *********************************************************************/ | ||
633 | extern "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 | |||
669 | LExit: | ||
670 | ReleaseStr(sczVersion); | ||
671 | |||
672 | return hr; | ||
673 | } | ||
674 | |||
675 | |||
676 | /******************************************************************** | ||
677 | RegReadNumber - reads a DWORD registry key value as a number. | ||
678 | |||
679 | *********************************************************************/ | ||
680 | extern "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 | |||
704 | LExit: | ||
705 | return hr; | ||
706 | } | ||
707 | |||
708 | |||
709 | /******************************************************************** | ||
710 | RegReadQword - reads a QWORD registry key value as a number. | ||
711 | |||
712 | *********************************************************************/ | ||
713 | extern "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 | |||
737 | LExit: | ||
738 | return hr; | ||
739 | } | ||
740 | |||
741 | |||
742 | /******************************************************************** | ||
743 | RegWriteBinary - writes a registry key value as a binary. | ||
744 | |||
745 | *********************************************************************/ | ||
746 | HRESULT 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 | |||
759 | LExit: | ||
760 | return hr; | ||
761 | } | ||
762 | |||
763 | |||
764 | /******************************************************************** | ||
765 | RegWriteExpandString - writes a registry key value as an expand string. | ||
766 | |||
767 | Note: if wzValue is NULL the value will be removed. | ||
768 | *********************************************************************/ | ||
769 | extern "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 | *********************************************************************/ | ||
784 | extern "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 | *********************************************************************/ | ||
798 | extern "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 | |||
816 | LExit: | ||
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 | *********************************************************************/ | ||
827 | HRESULT 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 | |||
882 | LExit: | ||
883 | ReleaseStr(sczWriteValue); | ||
884 | |||
885 | return hr; | ||
886 | } | ||
887 | |||
888 | /******************************************************************** | ||
889 | RegWriteNumber - writes a registry key value as a number. | ||
890 | |||
891 | *********************************************************************/ | ||
892 | extern "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 | |||
904 | LExit: | ||
905 | return hr; | ||
906 | } | ||
907 | |||
908 | /******************************************************************** | ||
909 | RegWriteQword - writes a registry key value as a Qword. | ||
910 | |||
911 | *********************************************************************/ | ||
912 | extern "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 | |||
924 | LExit: | ||
925 | return hr; | ||
926 | } | ||
927 | |||
928 | /******************************************************************** | ||
929 | RegQueryKey - queries the key for the number of subkeys and values. | ||
930 | |||
931 | *********************************************************************/ | ||
932 | extern "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 | |||
944 | LExit: | ||
945 | return hr; | ||
946 | } | ||
947 | |||
948 | /******************************************************************** | ||
949 | RegKeyReadNumber - reads a DWORD registry key value as a number from | ||
950 | a specified subkey. | ||
951 | |||
952 | *********************************************************************/ | ||
953 | extern "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 | |||
970 | LExit: | ||
971 | ReleaseRegKey(hkKey); | ||
972 | |||
973 | return hr; | ||
974 | } | ||
975 | |||
976 | /******************************************************************** | ||
977 | RegValueExists - determines whether a named value exists in a | ||
978 | specified subkey. | ||
979 | |||
980 | *********************************************************************/ | ||
981 | extern "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 | |||
998 | LExit: | ||
999 | ReleaseRegKey(hkKey); | ||
1000 | |||
1001 | return SUCCEEDED(hr); | ||
1002 | } | ||
1003 | |||
1004 | static 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 | |||
1033 | LExit: | ||
1034 | return hr; | ||
1035 | } | ||