1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/win/registry.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <iterator>
11 #include <memory>
12 #include <string>
13 #include <utility>
14 #include <vector>
15
16 #include "base/check_op.h"
17 #include "base/containers/fixed_flat_map.h"
18 #include "base/functional/callback.h"
19 #include "base/native_library.h"
20 #include "base/notreached.h"
21 #include "base/strings/string_piece.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/string_util_win.h"
24 #include "base/threading/thread_restrictions.h"
25 #include "base/win/object_watcher.h"
26 #include "base/win/pe_image.h"
27 #include "base/win/scoped_handle.h"
28 #include "base/win/shlwapi.h"
29
30 namespace base::win {
31
32 namespace {
33
34 // RegEnumValue() reports the number of characters from the name that were
35 // written to the buffer, not how many there are. This constant is the maximum
36 // name size, such that a buffer with this size should read any name.
37 constexpr DWORD MAX_REGISTRY_NAME_SIZE = 16384;
38
39 // Registry values are read as BYTE* but can have wchar_t* data whose last
40 // wchar_t is truncated. This function converts the reported |byte_size| to
41 // a size in wchar_t that can store a truncated wchar_t if necessary.
to_wchar_size(DWORD byte_size)42 inline DWORD to_wchar_size(DWORD byte_size) {
43 return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
44 }
45
46 // Mask to pull WOW64 access flags out of REGSAM access.
47 constexpr REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
48
49 constexpr DWORD kInvalidIterValue = static_cast<DWORD>(-1);
50
51 } // namespace
52
53 namespace internal {
54
55 // A forwarder to the normal delayloaded Windows Registry API.
56 class Standard {
57 public:
CreateKey(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition)58 static inline LSTATUS CreateKey(HKEY hKey,
59 LPCWSTR lpSubKey,
60 DWORD Reserved,
61 LPWSTR lpClass,
62 DWORD dwOptions,
63 REGSAM samDesired,
64 CONST LPSECURITY_ATTRIBUTES
65 lpSecurityAttributes,
66 PHKEY phkResult,
67 LPDWORD lpdwDisposition) {
68 return ::RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions,
69 samDesired, lpSecurityAttributes, phkResult,
70 lpdwDisposition);
71 }
72
OpenKey(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)73 static inline LSTATUS OpenKey(HKEY hKey,
74 LPCWSTR lpSubKey,
75 DWORD ulOptions,
76 REGSAM samDesired,
77 PHKEY phkResult) {
78 return ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
79 }
80
DeleteKey(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved)81 static inline LSTATUS DeleteKey(HKEY hKey,
82 LPCWSTR lpSubKey,
83 REGSAM samDesired,
84 DWORD Reserved) {
85 return ::RegDeleteKeyExW(hKey, lpSubKey, samDesired, Reserved);
86 }
87
QueryInfoKey(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime)88 static inline LSTATUS QueryInfoKey(HKEY hKey,
89 LPWSTR lpClass,
90 LPDWORD lpcchClass,
91 LPDWORD lpReserved,
92 LPDWORD lpcSubKeys,
93 LPDWORD lpcbMaxSubKeyLen,
94 LPDWORD lpcbMaxClassLen,
95 LPDWORD lpcValues,
96 LPDWORD lpcbMaxValueNameLen,
97 LPDWORD lpcbMaxValueLen,
98 LPDWORD lpcbSecurityDescriptor,
99 PFILETIME lpftLastWriteTime) {
100 return ::RegQueryInfoKeyW(hKey, lpClass, lpcchClass, lpReserved, lpcSubKeys,
101 lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues,
102 lpcbMaxValueNameLen, lpcbMaxValueLen,
103 lpcbSecurityDescriptor, lpftLastWriteTime);
104 }
105
EnumKey(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime)106 static inline LSTATUS EnumKey(HKEY hKey,
107 DWORD dwIndex,
108 LPWSTR lpName,
109 LPDWORD lpcchName,
110 LPDWORD lpReserved,
111 LPWSTR lpClass,
112 LPDWORD lpcchClass,
113 PFILETIME lpftLastWriteTime) {
114 return ::RegEnumKeyExW(hKey, dwIndex, lpName, lpcchName, lpReserved,
115 lpClass, lpcchClass, lpftLastWriteTime);
116 }
117
CloseKey(HKEY hKey)118 static inline LSTATUS CloseKey(HKEY hKey) { return ::RegCloseKey(hKey); }
119
QueryValue(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData)120 static inline LSTATUS QueryValue(HKEY hKey,
121 LPCWSTR lpValueName,
122 LPDWORD lpReserved,
123 LPDWORD lpType,
124 LPBYTE lpData,
125 LPDWORD lpcbData) {
126 return ::RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData,
127 lpcbData);
128 }
129
SetValue(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE * lpData,DWORD cbData)130 static inline LSTATUS SetValue(HKEY hKey,
131 LPCWSTR lpValueName,
132 DWORD Reserved,
133 DWORD dwType,
134 CONST BYTE* lpData,
135 DWORD cbData) {
136 return ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData,
137 cbData);
138 }
139
DeleteValue(HKEY hKey,LPCWSTR lpValueName)140 static inline LSTATUS DeleteValue(HKEY hKey, LPCWSTR lpValueName) {
141 return ::RegDeleteValueW(hKey, lpValueName);
142 }
143
EnumValue(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData)144 static inline LSTATUS EnumValue(HKEY hKey,
145 DWORD dwIndex,
146 LPWSTR lpValueName,
147 LPDWORD lpcchValueName,
148 LPDWORD lpReserved,
149 LPDWORD lpType,
150 LPBYTE lpData,
151 LPDWORD lpcbData) {
152 return ::RegEnumValueW(hKey, dwIndex, lpValueName, lpcchValueName,
153 lpReserved, lpType, lpData, lpcbData);
154 }
155 };
156
157 // An implementation derived from the export table of advapi32.
158 class ExportDerived {
159 public:
CreateKey(HKEY hKey,LPCWSTR lpSubKey,DWORD Reserved,LPWSTR lpClass,DWORD dwOptions,REGSAM samDesired,CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,PHKEY phkResult,LPDWORD lpdwDisposition)160 static LSTATUS CreateKey(HKEY hKey,
161 LPCWSTR lpSubKey,
162 DWORD Reserved,
163 LPWSTR lpClass,
164 DWORD dwOptions,
165 REGSAM samDesired,
166 CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
167 PHKEY phkResult,
168 LPDWORD lpdwDisposition) {
169 if (!ResolveRegistryFunctions() || !reg_create_key_ex_) {
170 return ERROR_ERRORS_ENCOUNTERED;
171 }
172 return reg_create_key_ex_(hKey, lpSubKey, Reserved, lpClass, dwOptions,
173 samDesired, lpSecurityAttributes, phkResult,
174 lpdwDisposition);
175 }
176
OpenKey(HKEY hKey,LPCWSTR lpSubKey,DWORD ulOptions,REGSAM samDesired,PHKEY phkResult)177 static LSTATUS OpenKey(HKEY hKey,
178 LPCWSTR lpSubKey,
179 DWORD ulOptions,
180 REGSAM samDesired,
181 PHKEY phkResult) {
182 if (!ResolveRegistryFunctions() || !reg_open_key_ex_) {
183 return ERROR_ERRORS_ENCOUNTERED;
184 }
185 return reg_open_key_ex_(hKey, lpSubKey, ulOptions, samDesired, phkResult);
186 }
187
DeleteKey(HKEY hKey,LPCWSTR lpSubKey,REGSAM samDesired,DWORD Reserved)188 static LSTATUS DeleteKey(HKEY hKey,
189 LPCWSTR lpSubKey,
190 REGSAM samDesired,
191 DWORD Reserved) {
192 if (!ResolveRegistryFunctions() || !reg_delete_key_ex_) {
193 return ERROR_ERRORS_ENCOUNTERED;
194 }
195 return reg_delete_key_ex_(hKey, lpSubKey, samDesired, Reserved);
196 }
197
QueryInfoKey(HKEY hKey,LPWSTR lpClass,LPDWORD lpcchClass,LPDWORD lpReserved,LPDWORD lpcSubKeys,LPDWORD lpcbMaxSubKeyLen,LPDWORD lpcbMaxClassLen,LPDWORD lpcValues,LPDWORD lpcbMaxValueNameLen,LPDWORD lpcbMaxValueLen,LPDWORD lpcbSecurityDescriptor,PFILETIME lpftLastWriteTime)198 static LSTATUS QueryInfoKey(HKEY hKey,
199 LPWSTR lpClass,
200 LPDWORD lpcchClass,
201 LPDWORD lpReserved,
202 LPDWORD lpcSubKeys,
203 LPDWORD lpcbMaxSubKeyLen,
204 LPDWORD lpcbMaxClassLen,
205 LPDWORD lpcValues,
206 LPDWORD lpcbMaxValueNameLen,
207 LPDWORD lpcbMaxValueLen,
208 LPDWORD lpcbSecurityDescriptor,
209 PFILETIME lpftLastWriteTime) {
210 if (!ResolveRegistryFunctions() || !reg_query_info_key_) {
211 return ERROR_ERRORS_ENCOUNTERED;
212 }
213 return reg_query_info_key_(hKey, lpClass, lpcchClass, lpReserved,
214 lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen,
215 lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen,
216 lpcbSecurityDescriptor, lpftLastWriteTime);
217 }
218
EnumKey(HKEY hKey,DWORD dwIndex,LPWSTR lpName,LPDWORD lpcchName,LPDWORD lpReserved,LPWSTR lpClass,LPDWORD lpcchClass,PFILETIME lpftLastWriteTime)219 static LSTATUS EnumKey(HKEY hKey,
220 DWORD dwIndex,
221 LPWSTR lpName,
222 LPDWORD lpcchName,
223 LPDWORD lpReserved,
224 LPWSTR lpClass,
225 LPDWORD lpcchClass,
226 PFILETIME lpftLastWriteTime) {
227 if (!ResolveRegistryFunctions() || !reg_enum_key_ex_) {
228 return ERROR_ERRORS_ENCOUNTERED;
229 }
230 return reg_enum_key_ex_(hKey, dwIndex, lpName, lpcchName, lpReserved,
231 lpClass, lpcchClass, lpftLastWriteTime);
232 }
233
CloseKey(HKEY hKey)234 static LSTATUS CloseKey(HKEY hKey) {
235 if (!ResolveRegistryFunctions() || !reg_close_key_) {
236 return ERROR_ERRORS_ENCOUNTERED;
237 }
238 return reg_close_key_(hKey);
239 }
240
QueryValue(HKEY hKey,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData)241 static LSTATUS QueryValue(HKEY hKey,
242 LPCWSTR lpValueName,
243 LPDWORD lpReserved,
244 LPDWORD lpType,
245 LPBYTE lpData,
246 LPDWORD lpcbData) {
247 if (!ResolveRegistryFunctions() || !reg_query_value_ex_) {
248 return ERROR_ERRORS_ENCOUNTERED;
249 }
250 return reg_query_value_ex_(hKey, lpValueName, lpReserved, lpType, lpData,
251 lpcbData);
252 }
253
SetValue(HKEY hKey,LPCWSTR lpValueName,DWORD Reserved,DWORD dwType,CONST BYTE * lpData,DWORD cbData)254 static LSTATUS SetValue(HKEY hKey,
255 LPCWSTR lpValueName,
256 DWORD Reserved,
257 DWORD dwType,
258 CONST BYTE* lpData,
259 DWORD cbData) {
260 if (!ResolveRegistryFunctions() || !reg_set_value_ex_) {
261 return ERROR_ERRORS_ENCOUNTERED;
262 }
263 return reg_set_value_ex_(hKey, lpValueName, Reserved, dwType, lpData,
264 cbData);
265 }
266
DeleteValue(HKEY hKey,LPCWSTR lpValueName)267 static LSTATUS DeleteValue(HKEY hKey, LPCWSTR lpValueName) {
268 if (!ResolveRegistryFunctions() || !reg_delete_value_) {
269 return ERROR_ERRORS_ENCOUNTERED;
270 }
271 return reg_delete_value_(hKey, lpValueName);
272 }
EnumValue(HKEY hKey,DWORD dwIndex,LPWSTR lpValueName,LPDWORD lpcchValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData)273 static LSTATUS EnumValue(HKEY hKey,
274 DWORD dwIndex,
275 LPWSTR lpValueName,
276 LPDWORD lpcchValueName,
277 LPDWORD lpReserved,
278 LPDWORD lpType,
279 LPBYTE lpData,
280 LPDWORD lpcbData) {
281 if (!ResolveRegistryFunctions() || !reg_enum_value_) {
282 return ERROR_ERRORS_ENCOUNTERED;
283 }
284
285 return reg_enum_value_(hKey, dwIndex, lpValueName, lpcchValueName,
286 lpReserved, lpType, lpData, lpcbData);
287 }
288
289 private:
ProcessOneExport(const base::win::PEImage & image,DWORD ordinal,DWORD hint,LPCSTR name,PVOID function_addr,LPCSTR forward,PVOID cookie)290 static bool ProcessOneExport(const base::win::PEImage& image,
291 DWORD ordinal,
292 DWORD hint,
293 LPCSTR name,
294 PVOID function_addr,
295 LPCSTR forward,
296 PVOID cookie) {
297 if (!name || !function_addr) {
298 return true;
299 }
300
301 static const auto kMap =
302 base::MakeFixedFlatMapSorted<base::StringPiece, void**>({
303 {"RegCloseKey", reinterpret_cast<void**>(®_close_key_)},
304 {"RegCreateKeyExW", reinterpret_cast<void**>(®_create_key_ex_)},
305 {"RegDeleteKeyExW", reinterpret_cast<void**>(®_delete_key_ex_)},
306 {"RegDeleteValueW", reinterpret_cast<void**>(®_delete_value_)},
307 {"RegEnumKeyExW", reinterpret_cast<void**>(®_enum_key_ex_)},
308 {"RegEnumValueW", reinterpret_cast<void**>(®_enum_value_)},
309 {"RegOpenKeyExW", reinterpret_cast<void**>(®_open_key_ex_)},
310 {"RegQueryInfoKeyW",
311 reinterpret_cast<void**>(®_query_info_key_)},
312 {"RegQueryValueExW",
313 reinterpret_cast<void**>(®_query_value_ex_)},
314 {"RegSetValueExW", reinterpret_cast<void**>(®_set_value_ex_)},
315 });
316
317 auto* entry = kMap.find(name);
318 if (entry == kMap.end()) {
319 return true;
320 }
321
322 static size_t num_init_functions = 0;
323 if (!std::exchange(*(entry->second), function_addr)) {
324 ++num_init_functions;
325 }
326
327 bool& fully_resolved = *static_cast<bool*>(cookie);
328 fully_resolved = num_init_functions == kMap.size();
329 return !fully_resolved;
330 }
331
ResolveRegistryFunctions()332 static bool ResolveRegistryFunctions() {
333 static bool initialized = []() {
334 base::NativeLibraryLoadError error;
335 HMODULE advapi32 = base::PinSystemLibrary(L"advapi32.dll", &error);
336 if (!advapi32 || error.code) {
337 return false;
338 }
339 bool fully_resolved = false;
340 base::win::PEImage(advapi32).EnumExports(&ProcessOneExport,
341 &fully_resolved);
342 return fully_resolved;
343 }();
344 return initialized;
345 }
346
347 static decltype(::RegCreateKeyExW)* reg_create_key_ex_;
348 static decltype(::RegOpenKeyExW)* reg_open_key_ex_;
349 static decltype(::RegDeleteKeyExW)* reg_delete_key_ex_;
350 static decltype(::RegQueryInfoKeyW)* reg_query_info_key_;
351 static decltype(::RegEnumKeyExW)* reg_enum_key_ex_;
352 static decltype(::RegCloseKey)* reg_close_key_;
353 static decltype(::RegQueryValueExW)* reg_query_value_ex_;
354 static decltype(::RegSetValueExW)* reg_set_value_ex_;
355 static decltype(::RegDeleteValueW)* reg_delete_value_;
356 static decltype(::RegEnumValueW)* reg_enum_value_;
357 };
358
359 decltype(::RegCreateKeyEx)* ExportDerived::reg_create_key_ex_ = nullptr;
360 decltype(::RegOpenKeyExW)* ExportDerived::reg_open_key_ex_ = nullptr;
361 decltype(::RegDeleteKeyExW)* ExportDerived::reg_delete_key_ex_ = nullptr;
362 decltype(::RegQueryInfoKeyW)* ExportDerived::reg_query_info_key_ = nullptr;
363 decltype(::RegEnumKeyExW)* ExportDerived::reg_enum_key_ex_ = nullptr;
364 decltype(::RegCloseKey)* ExportDerived::reg_close_key_ = nullptr;
365 decltype(::RegQueryValueEx)* ExportDerived::reg_query_value_ex_ = nullptr;
366 decltype(::RegSetValueExW)* ExportDerived::reg_set_value_ex_ = nullptr;
367 decltype(::RegDeleteValueW)* ExportDerived::reg_delete_value_ = nullptr;
368 decltype(::RegEnumValueW)* ExportDerived::reg_enum_value_ = nullptr;
369
370 // Watches for modifications to a key.
371 template <typename Reg>
372 class GenericRegKey<Reg>::Watcher : public ObjectWatcher::Delegate {
373 public:
374 Watcher() = default;
375
376 Watcher(const Watcher&) = delete;
377 Watcher& operator=(const Watcher&) = delete;
378
379 ~Watcher() override = default;
380
381 bool StartWatching(HKEY key, ChangeCallback callback);
382
383 // ObjectWatcher::Delegate:
OnObjectSignaled(HANDLE object)384 void OnObjectSignaled(HANDLE object) override {
385 DCHECK(watch_event_.is_valid());
386 DCHECK_EQ(watch_event_.get(), object);
387 std::move(callback_).Run();
388 }
389
390 private:
391 ScopedHandle watch_event_;
392 ObjectWatcher object_watcher_;
393 ChangeCallback callback_;
394 };
395
396 template <typename Reg>
StartWatching(HKEY key,ChangeCallback callback)397 bool GenericRegKey<Reg>::Watcher::StartWatching(HKEY key,
398 ChangeCallback callback) {
399 DCHECK(key);
400 DCHECK(callback_.is_null());
401
402 if (!watch_event_.is_valid()) {
403 watch_event_.Set(CreateEvent(nullptr, TRUE, FALSE, nullptr));
404 }
405
406 if (!watch_event_.is_valid()) {
407 return false;
408 }
409
410 DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
411 REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY |
412 REG_NOTIFY_THREAD_AGNOSTIC;
413 // Watch the registry key for a change of value.
414 LONG result =
415 RegNotifyChangeKeyValue(key, /*bWatchSubtree=*/TRUE, filter,
416 watch_event_.get(), /*fAsynchronous=*/TRUE);
417 if (result != ERROR_SUCCESS) {
418 watch_event_.Close();
419 return false;
420 }
421
422 callback_ = std::move(callback);
423 return object_watcher_.StartWatchingOnce(watch_event_.get(), this);
424 }
425
426 // GenericRegKey<Reg>
427 // ----------------------------------------------------------------------
428
429 template <typename Reg>
430 GenericRegKey<Reg>::GenericRegKey() = default;
431
432 template <typename Reg>
GenericRegKey(HKEY key)433 GenericRegKey<Reg>::GenericRegKey(HKEY key) : key_(key) {}
434
435 template <typename Reg>
GenericRegKey(HKEY rootkey,const wchar_t * subkey,REGSAM access)436 GenericRegKey<Reg>::GenericRegKey(HKEY rootkey,
437 const wchar_t* subkey,
438 REGSAM access) {
439 if (rootkey) {
440 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
441 Create(rootkey, subkey, access);
442 } else {
443 Open(rootkey, subkey, access);
444 }
445 } else {
446 DCHECK(!subkey);
447 wow64access_ = access & kWow64AccessMask;
448 }
449 }
450
451 template <typename Reg>
GenericRegKey(GenericRegKey<Reg> && other)452 GenericRegKey<Reg>::GenericRegKey(GenericRegKey<Reg>&& other) noexcept
453 : key_(other.key_),
454 wow64access_(other.wow64access_),
455 key_watcher_(std::move(other.key_watcher_)) {
456 other.key_ = nullptr;
457 other.wow64access_ = 0;
458 }
459
460 template <typename Reg>
operator =(GenericRegKey<Reg> && other)461 GenericRegKey<Reg>& GenericRegKey<Reg>::operator=(GenericRegKey<Reg>&& other) {
462 Close();
463 std::swap(key_, other.key_);
464 std::swap(wow64access_, other.wow64access_);
465 key_watcher_ = std::move(other.key_watcher_);
466 return *this;
467 }
468
469 template <typename Reg>
~GenericRegKey()470 GenericRegKey<Reg>::~GenericRegKey() {
471 Close();
472 }
473
474 template <typename Reg>
Create(HKEY rootkey,const wchar_t * subkey,REGSAM access)475 LONG GenericRegKey<Reg>::Create(HKEY rootkey,
476 const wchar_t* subkey,
477 REGSAM access) {
478 DWORD disposition_value;
479 return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
480 }
481
482 template <typename Reg>
CreateWithDisposition(HKEY rootkey,const wchar_t * subkey,DWORD * disposition,REGSAM access)483 LONG GenericRegKey<Reg>::CreateWithDisposition(HKEY rootkey,
484 const wchar_t* subkey,
485 DWORD* disposition,
486 REGSAM access) {
487 DCHECK(rootkey && subkey && access && disposition);
488 HKEY subhkey = nullptr;
489 LONG result =
490 Reg::CreateKey(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE,
491 access, nullptr, &subhkey, disposition);
492 if (result == ERROR_SUCCESS) {
493 Close();
494 key_ = subhkey;
495 wow64access_ = access & kWow64AccessMask;
496 }
497
498 return result;
499 }
500
501 template <typename Reg>
CreateKey(const wchar_t * name,REGSAM access)502 LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) {
503 DCHECK(name && access);
504 // After the application has accessed an alternate registry view using one
505 // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
506 // operations (create, delete, or open) on child registry keys must
507 // explicitly use the same flag. Otherwise, there can be unexpected
508 // behavior.
509 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
510 if ((access & kWow64AccessMask) != wow64access_) {
511 NOTREACHED();
512 return ERROR_INVALID_PARAMETER;
513 }
514 HKEY subkey = nullptr;
515 LONG result = Reg::CreateKey(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE,
516 access, nullptr, &subkey, nullptr);
517 if (result == ERROR_SUCCESS) {
518 Close();
519 key_ = subkey;
520 wow64access_ = access & kWow64AccessMask;
521 }
522
523 return result;
524 }
525
526 template <typename Reg>
Open(HKEY rootkey,const wchar_t * subkey,REGSAM access)527 LONG GenericRegKey<Reg>::Open(HKEY rootkey,
528 const wchar_t* subkey,
529 REGSAM access) {
530 DCHECK(rootkey && subkey && access);
531 HKEY subhkey = nullptr;
532
533 LONG result = Reg::OpenKey(rootkey, subkey, 0, access, &subhkey);
534 if (result == ERROR_SUCCESS) {
535 Close();
536 key_ = subhkey;
537 wow64access_ = access & kWow64AccessMask;
538 }
539
540 return result;
541 }
542
543 template <typename Reg>
OpenKey(const wchar_t * relative_key_name,REGSAM access)544 LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name,
545 REGSAM access) {
546 DCHECK(relative_key_name && access);
547 // After the application has accessed an alternate registry view using one
548 // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
549 // operations (create, delete, or open) on child registry keys must
550 // explicitly use the same flag. Otherwise, there can be unexpected
551 // behavior.
552 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
553 if ((access & kWow64AccessMask) != wow64access_) {
554 NOTREACHED();
555 return ERROR_INVALID_PARAMETER;
556 }
557 HKEY subkey = nullptr;
558 LONG result = Reg::OpenKey(key_, relative_key_name, 0, access, &subkey);
559
560 // We have to close the current opened key before replacing it with the new
561 // one.
562 if (result == ERROR_SUCCESS) {
563 Close();
564 key_ = subkey;
565 wow64access_ = access & kWow64AccessMask;
566 }
567 return result;
568 }
569
570 template <typename Reg>
Close()571 void GenericRegKey<Reg>::Close() {
572 if (key_) {
573 Reg::CloseKey(key_);
574 key_ = nullptr;
575 wow64access_ = 0;
576 }
577 }
578
579 // TODO(wfh): Remove this and other unsafe methods. See
580 // http://crbug.com/375400
581 template <typename Reg>
Set(HKEY key)582 void GenericRegKey<Reg>::Set(HKEY key) {
583 if (key_ != key) {
584 Close();
585 key_ = key;
586 }
587 }
588
589 template <typename Reg>
Take()590 HKEY GenericRegKey<Reg>::Take() {
591 DCHECK_EQ(wow64access_, 0u);
592 HKEY key = key_;
593 key_ = nullptr;
594 return key;
595 }
596
597 template <typename Reg>
HasValue(const wchar_t * name) const598 bool GenericRegKey<Reg>::HasValue(const wchar_t* name) const {
599 return Reg::QueryValue(key_, name, nullptr, nullptr, nullptr, nullptr) ==
600 ERROR_SUCCESS;
601 }
602
603 template <typename Reg>
GetValueCount() const604 DWORD GenericRegKey<Reg>::GetValueCount() const {
605 DWORD count = 0;
606 LONG result =
607 Reg::QueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
608 nullptr, &count, nullptr, nullptr, nullptr, nullptr);
609 return (result == ERROR_SUCCESS) ? count : 0;
610 }
611
612 template <typename Reg>
GetLastWriteTime() const613 FILETIME GenericRegKey<Reg>::GetLastWriteTime() const {
614 FILETIME last_write_time;
615 LONG result = Reg::QueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr,
616 nullptr, nullptr, nullptr, nullptr, nullptr,
617 nullptr, &last_write_time);
618 return (result == ERROR_SUCCESS) ? last_write_time : FILETIME{};
619 }
620
621 template <typename Reg>
GetValueNameAt(DWORD index,std::wstring * name) const622 LONG GenericRegKey<Reg>::GetValueNameAt(DWORD index, std::wstring* name) const {
623 wchar_t buf[256];
624 DWORD bufsize = std::size(buf);
625 LONG r = Reg::EnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr,
626 nullptr);
627 if (r == ERROR_SUCCESS) {
628 name->assign(buf, bufsize);
629 }
630
631 return r;
632 }
633
634 template <typename Reg>
DeleteKey(const wchar_t * name)635 LONG GenericRegKey<Reg>::DeleteKey(const wchar_t* name) {
636 DCHECK(name);
637
638 // Verify the key exists before attempting delete to replicate previous
639 // behavior.
640 // `RegOpenKeyEx()` will return an error if `key_` is invalid.
641 HKEY subkey = nullptr;
642 LONG result =
643 Reg::OpenKey(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
644 if (result != ERROR_SUCCESS) {
645 return result;
646 }
647 Reg::CloseKey(subkey);
648
649 return RegDelRecurse(key_, name, wow64access_);
650 }
651
652 template <typename Reg>
DeleteEmptyKey(const wchar_t * name)653 LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) {
654 DCHECK(name);
655
656 // `RegOpenKeyEx()` will return an error if `key_` is invalid.
657 HKEY target_key = nullptr;
658 LONG result =
659 Reg::OpenKey(key_, name, 0, KEY_READ | wow64access_, &target_key);
660
661 if (result != ERROR_SUCCESS) {
662 return result;
663 }
664
665 DWORD count = 0;
666 result =
667 Reg::QueryInfoKey(target_key, nullptr, nullptr, nullptr, nullptr, nullptr,
668 nullptr, &count, nullptr, nullptr, nullptr, nullptr);
669
670 Reg::CloseKey(target_key);
671
672 if (result != ERROR_SUCCESS) {
673 return result;
674 }
675
676 if (count == 0) {
677 return RegDeleteKeyEx(key_, name, wow64access_, 0);
678 }
679
680 return ERROR_DIR_NOT_EMPTY;
681 }
682
683 template <typename Reg>
DeleteValue(const wchar_t * value_name)684 LONG GenericRegKey<Reg>::DeleteValue(const wchar_t* value_name) {
685 // `RegDeleteValue()` will return an error if `key_` is invalid.
686 LONG result = Reg::DeleteValue(key_, value_name);
687 return result;
688 }
689
690 template <typename Reg>
ReadValueDW(const wchar_t * name,DWORD * out_value) const691 LONG GenericRegKey<Reg>::ReadValueDW(const wchar_t* name,
692 DWORD* out_value) const {
693 DCHECK(out_value);
694 DWORD type = REG_DWORD;
695 DWORD size = sizeof(DWORD);
696 DWORD local_value = 0;
697 LONG result = ReadValue(name, &local_value, &size, &type);
698 if (result == ERROR_SUCCESS) {
699 if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) {
700 *out_value = local_value;
701 } else {
702 result = ERROR_CANTREAD;
703 }
704 }
705
706 return result;
707 }
708
709 template <typename Reg>
ReadInt64(const wchar_t * name,int64_t * out_value) const710 LONG GenericRegKey<Reg>::ReadInt64(const wchar_t* name,
711 int64_t* out_value) const {
712 DCHECK(out_value);
713 DWORD type = REG_QWORD;
714 int64_t local_value = 0;
715 DWORD size = sizeof(local_value);
716 LONG result = ReadValue(name, &local_value, &size, &type);
717 if (result == ERROR_SUCCESS) {
718 if ((type == REG_QWORD || type == REG_BINARY) &&
719 size == sizeof(local_value)) {
720 *out_value = local_value;
721 } else {
722 result = ERROR_CANTREAD;
723 }
724 }
725
726 return result;
727 }
728
729 template <typename Reg>
ReadValue(const wchar_t * name,std::wstring * out_value) const730 LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name,
731 std::wstring* out_value) const {
732 DCHECK(out_value);
733 const size_t kMaxStringLength = 1024; // This is after expansion.
734 // Use the one of the other forms of ReadValue if 1024 is too small for you.
735 wchar_t raw_value[kMaxStringLength];
736 DWORD type = REG_SZ, size = sizeof(raw_value);
737 LONG result = ReadValue(name, raw_value, &size, &type);
738 if (result == ERROR_SUCCESS) {
739 if (type == REG_SZ) {
740 *out_value = raw_value;
741 } else if (type == REG_EXPAND_SZ) {
742 wchar_t expanded[kMaxStringLength];
743 size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
744 // Success: returns the number of wchar_t's copied
745 // Fail: buffer too small, returns the size required
746 // Fail: other, returns 0
747 if (size == 0 || size > kMaxStringLength) {
748 result = ERROR_MORE_DATA;
749 } else {
750 *out_value = expanded;
751 }
752 } else {
753 // Not a string. Oops.
754 result = ERROR_CANTREAD;
755 }
756 }
757
758 return result;
759 }
760
761 template <typename Reg>
ReadValue(const wchar_t * name,void * data,DWORD * dsize,DWORD * dtype) const762 LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name,
763 void* data,
764 DWORD* dsize,
765 DWORD* dtype) const {
766 LONG result = Reg::QueryValue(key_, name, nullptr, dtype,
767 reinterpret_cast<LPBYTE>(data), dsize);
768 return result;
769 }
770
771 template <typename Reg>
ReadValues(const wchar_t * name,std::vector<std::wstring> * values)772 LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name,
773 std::vector<std::wstring>* values) {
774 values->clear();
775
776 DWORD type = REG_MULTI_SZ;
777 DWORD size = 0;
778 LONG result = ReadValue(name, nullptr, &size, &type);
779 if (result != ERROR_SUCCESS || size == 0) {
780 return result;
781 }
782
783 if (type != REG_MULTI_SZ) {
784 return ERROR_CANTREAD;
785 }
786
787 std::vector<wchar_t> buffer(size / sizeof(wchar_t));
788 result = ReadValue(name, buffer.data(), &size, nullptr);
789 if (result != ERROR_SUCCESS || size == 0) {
790 return result;
791 }
792
793 // Parse the double-null-terminated list of strings.
794 // Note: This code is paranoid to not read outside of |buf|, in the case
795 // where it may not be properly terminated.
796 auto entry = buffer.cbegin();
797 auto buffer_end = buffer.cend();
798 while (entry < buffer_end && *entry != '\0') {
799 auto entry_end = std::find(entry, buffer_end, '\0');
800 values->emplace_back(entry, entry_end);
801 entry = entry_end + 1;
802 }
803 return 0;
804 }
805
806 template <typename Reg>
WriteValue(const wchar_t * name,DWORD in_value)807 LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name, DWORD in_value) {
808 return WriteValue(name, &in_value, static_cast<DWORD>(sizeof(in_value)),
809 REG_DWORD);
810 }
811
812 template <typename Reg>
WriteValue(const wchar_t * name,const wchar_t * in_value)813 LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name,
814 const wchar_t* in_value) {
815 return WriteValue(
816 name, in_value,
817 static_cast<DWORD>(sizeof(*in_value) *
818 (std::char_traits<wchar_t>::length(in_value) + 1)),
819 REG_SZ);
820 }
821
822 template <typename Reg>
WriteValue(const wchar_t * name,const void * data,DWORD dsize,DWORD dtype)823 LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name,
824 const void* data,
825 DWORD dsize,
826 DWORD dtype) {
827 DCHECK(data || !dsize);
828
829 LONG result =
830 Reg::SetValue(key_, name, 0, dtype,
831 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
832 return result;
833 }
834
835 template <typename Reg>
StartWatching(ChangeCallback callback)836 bool GenericRegKey<Reg>::StartWatching(ChangeCallback callback) {
837 if (!key_watcher_) {
838 key_watcher_ = std::make_unique<Watcher>();
839 }
840
841 if (!key_watcher_->StartWatching(key_, std::move(callback))) {
842 return false;
843 }
844
845 return true;
846 }
847
848 // static
849 template <typename Reg>
RegDelRecurse(HKEY root_key,const wchar_t * name,REGSAM access)850 LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key,
851 const wchar_t* name,
852 REGSAM access) {
853 // First, see if the key can be deleted without having to recurse.
854 LONG result = Reg::DeleteKey(root_key, name, access, 0);
855 if (result == ERROR_SUCCESS) {
856 return result;
857 }
858
859 HKEY target_key = nullptr;
860 result = Reg::OpenKey(root_key, name, 0, KEY_ENUMERATE_SUB_KEYS | access,
861 &target_key);
862
863 if (result == ERROR_FILE_NOT_FOUND) {
864 return ERROR_SUCCESS;
865 }
866 if (result != ERROR_SUCCESS)
867 return result;
868
869 std::wstring subkey_name(name);
870
871 // Check for an ending slash and add one if it is missing.
872 if (!subkey_name.empty() && subkey_name.back() != '\\') {
873 subkey_name.push_back('\\');
874 }
875
876 // Enumerate the keys
877 result = ERROR_SUCCESS;
878 const DWORD kMaxKeyNameLength = MAX_PATH;
879 const size_t base_key_length = subkey_name.length();
880 std::wstring key_name;
881 while (result == ERROR_SUCCESS) {
882 DWORD key_size = kMaxKeyNameLength;
883 result =
884 Reg::EnumKey(target_key, 0, WriteInto(&key_name, kMaxKeyNameLength),
885 &key_size, nullptr, nullptr, nullptr, nullptr);
886
887 if (result != ERROR_SUCCESS) {
888 break;
889 }
890
891 key_name.resize(key_size);
892 subkey_name.resize(base_key_length);
893 subkey_name += key_name;
894
895 if (RegDelRecurse(root_key, subkey_name.c_str(), access) != ERROR_SUCCESS) {
896 break;
897 }
898 }
899
900 Reg::CloseKey(target_key);
901
902 // Try again to delete the key.
903 result = Reg::DeleteKey(root_key, name, access, 0);
904
905 return result;
906 }
907
908 // Instantiate the only two allowed versions of GenericRegKey for use by the
909 // public base::win::RegKey and base::win::ExportDerivedRegKey.
910 template class GenericRegKey<internal::Standard>;
911 template class GenericRegKey<internal::ExportDerived>;
912
913 } // namespace internal
914
RegKey()915 RegKey::RegKey() : GenericRegKey<internal::Standard>() {}
RegKey(HKEY key)916 RegKey::RegKey(HKEY key) : GenericRegKey<internal::Standard>(key) {}
RegKey(HKEY rootkey,const wchar_t * subkey,REGSAM access)917 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
918 : GenericRegKey<internal::Standard>(rootkey, subkey, access) {}
919
RegKey(RegKey && other)920 RegKey::RegKey(RegKey&& other) noexcept
921 : GenericRegKey<internal::Standard>(std::move(other)) {}
operator =(RegKey && other)922 RegKey& RegKey::operator=(RegKey&& other) {
923 GenericRegKey<internal::Standard>::operator=(std::move(other));
924 return *this;
925 }
926
927 RegKey::~RegKey() = default;
928
ExportDerivedRegKey()929 ExportDerivedRegKey::ExportDerivedRegKey()
930 : GenericRegKey<internal::ExportDerived>() {}
ExportDerivedRegKey(HKEY key)931 ExportDerivedRegKey::ExportDerivedRegKey(HKEY key)
932 : GenericRegKey<internal::ExportDerived>(key) {}
ExportDerivedRegKey(HKEY rootkey,const wchar_t * subkey,REGSAM access)933 ExportDerivedRegKey::ExportDerivedRegKey(HKEY rootkey,
934 const wchar_t* subkey,
935 REGSAM access)
936 : GenericRegKey<internal::ExportDerived>(rootkey, subkey, access) {}
937
ExportDerivedRegKey(ExportDerivedRegKey && other)938 ExportDerivedRegKey::ExportDerivedRegKey(ExportDerivedRegKey&& other) noexcept
939 : GenericRegKey<internal::ExportDerived>(std::move(other)) {}
operator =(ExportDerivedRegKey && other)940 ExportDerivedRegKey& ExportDerivedRegKey::operator=(
941 ExportDerivedRegKey&& other) {
942 GenericRegKey<internal::ExportDerived>::operator=(std::move(other));
943 return *this;
944 }
945
946 ExportDerivedRegKey::~ExportDerivedRegKey() = default;
947
948 // RegistryValueIterator ------------------------------------------------------
949
RegistryValueIterator(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)950 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
951 const wchar_t* folder_key,
952 REGSAM wow64access)
953 : name_(MAX_PATH, '\0'), value_(MAX_PATH, '\0') {
954 Initialize(root_key, folder_key, wow64access);
955 }
956
RegistryValueIterator(HKEY root_key,const wchar_t * folder_key)957 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
958 const wchar_t* folder_key)
959 : name_(MAX_PATH, '\0'), value_(MAX_PATH, '\0') {
960 Initialize(root_key, folder_key, 0);
961 }
962
Initialize(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)963 void RegistryValueIterator::Initialize(HKEY root_key,
964 const wchar_t* folder_key,
965 REGSAM wow64access) {
966 DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
967 LONG result =
968 RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
969 if (result != ERROR_SUCCESS) {
970 key_ = nullptr;
971 } else {
972 DWORD count = 0;
973 result =
974 ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
975 nullptr, &count, nullptr, nullptr, nullptr, nullptr);
976
977 if (result != ERROR_SUCCESS) {
978 ::RegCloseKey(key_);
979 key_ = nullptr;
980 } else {
981 index_ = count - 1;
982 }
983 }
984
985 Read();
986 }
987
~RegistryValueIterator()988 RegistryValueIterator::~RegistryValueIterator() {
989 if (key_)
990 ::RegCloseKey(key_);
991 }
992
ValueCount() const993 DWORD RegistryValueIterator::ValueCount() const {
994 DWORD count = 0;
995 LONG result =
996 ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
997 nullptr, &count, nullptr, nullptr, nullptr, nullptr);
998 if (result != ERROR_SUCCESS)
999 return 0;
1000
1001 return count;
1002 }
1003
Valid() const1004 bool RegistryValueIterator::Valid() const {
1005 return key_ != nullptr && index_ != kInvalidIterValue;
1006 }
1007
operator ++()1008 void RegistryValueIterator::operator++() {
1009 if (index_ != kInvalidIterValue)
1010 --index_;
1011 Read();
1012 }
1013
Read()1014 bool RegistryValueIterator::Read() {
1015 if (Valid()) {
1016 DWORD capacity = static_cast<DWORD>(name_.capacity());
1017 DWORD name_size = capacity;
1018 // |value_size_| is in bytes. Reserve the last character for a NUL.
1019 value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
1020 LONG result = ::RegEnumValue(
1021 key_, index_, WriteInto(&name_, name_size), &name_size, nullptr, &type_,
1022 reinterpret_cast<BYTE*>(value_.data()), &value_size_);
1023
1024 if (result == ERROR_MORE_DATA) {
1025 // Registry key names are limited to 255 characters and fit within
1026 // MAX_PATH (which is 260) but registry value names can use up to 16,383
1027 // characters and the value itself is not limited
1028 // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
1029 // ms724872(v=vs.85).aspx).
1030 // Resize the buffers and retry if their size caused the failure.
1031 DWORD value_size_in_wchars = to_wchar_size(value_size_);
1032 if (value_size_in_wchars + 1 > value_.size())
1033 value_.resize(value_size_in_wchars + 1, '\0');
1034 value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
1035 name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
1036 result = ::RegEnumValue(
1037 key_, index_, WriteInto(&name_, name_size), &name_size, nullptr,
1038 &type_, reinterpret_cast<BYTE*>(value_.data()), &value_size_);
1039 }
1040
1041 if (result == ERROR_SUCCESS) {
1042 DCHECK_LT(to_wchar_size(value_size_), value_.size());
1043 value_[to_wchar_size(value_size_)] = '\0';
1044 return true;
1045 }
1046 }
1047
1048 name_[0] = '\0';
1049 value_[0] = '\0';
1050 value_size_ = 0;
1051 return false;
1052 }
1053
1054 // RegistryKeyIterator --------------------------------------------------------
1055
RegistryKeyIterator(HKEY root_key,const wchar_t * folder_key)1056 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
1057 const wchar_t* folder_key) {
1058 Initialize(root_key, folder_key, 0);
1059 }
1060
RegistryKeyIterator(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)1061 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
1062 const wchar_t* folder_key,
1063 REGSAM wow64access) {
1064 Initialize(root_key, folder_key, wow64access);
1065 }
1066
~RegistryKeyIterator()1067 RegistryKeyIterator::~RegistryKeyIterator() {
1068 if (key_)
1069 ::RegCloseKey(key_);
1070 }
1071
SubkeyCount() const1072 DWORD RegistryKeyIterator::SubkeyCount() const {
1073 DWORD count = 0;
1074 LONG result =
1075 ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, &count, nullptr,
1076 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
1077 if (result != ERROR_SUCCESS)
1078 return 0;
1079
1080 return count;
1081 }
1082
Valid() const1083 bool RegistryKeyIterator::Valid() const {
1084 return key_ != nullptr && index_ != kInvalidIterValue;
1085 }
1086
operator ++()1087 void RegistryKeyIterator::operator++() {
1088 if (index_ != kInvalidIterValue)
1089 --index_;
1090 Read();
1091 }
1092
Read()1093 bool RegistryKeyIterator::Read() {
1094 if (Valid()) {
1095 DWORD ncount = static_cast<DWORD>(std::size(name_));
1096 FILETIME written;
1097 LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, nullptr, nullptr,
1098 nullptr, &written);
1099 if (ERROR_SUCCESS == r)
1100 return true;
1101 }
1102
1103 name_[0] = '\0';
1104 return false;
1105 }
1106
Initialize(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)1107 void RegistryKeyIterator::Initialize(HKEY root_key,
1108 const wchar_t* folder_key,
1109 REGSAM wow64access) {
1110 DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
1111 LONG result =
1112 RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
1113 if (result != ERROR_SUCCESS) {
1114 key_ = nullptr;
1115 } else {
1116 DWORD count = 0;
1117 result =
1118 ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, &count, nullptr,
1119 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
1120
1121 if (result != ERROR_SUCCESS) {
1122 ::RegCloseKey(key_);
1123 key_ = nullptr;
1124 } else {
1125 index_ = count - 1;
1126 }
1127 }
1128
1129 Read();
1130 }
1131
1132 } // namespace base::win
1133