• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <shlwapi.h>
8 #include <stddef.h>
9 
10 #include <algorithm>
11 #include <iterator>
12 
13 #include "base/logging.h"
14 #include "base/strings/string_util.h"
15 #include "base/win/win_util.h"
16 
17 namespace base {
18 namespace win {
19 
20 namespace {
21 
22 // RegEnumValue() reports the number of characters from the name that were
23 // written to the buffer, not how many there are. This constant is the maximum
24 // name size, such that a buffer with this size should read any name.
25 const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
26 
27 // Registry values are read as BYTE* but can have char16_t* data whose last
28 // char16_t is truncated. This function converts the reported |byte_size| to
29 // a size in char16_t that can store a truncated char16_t if necessary.
to_wchar_size(DWORD byte_size)30 inline DWORD to_wchar_size(DWORD byte_size) {
31   return (byte_size + sizeof(char16_t) - 1) / sizeof(char16_t);
32 }
33 
34 // Mask to pull WOW64 access flags out of REGSAM access.
35 const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
36 
37 }  // namespace
38 
39 // RegKey ----------------------------------------------------------------------
40 
RegKey()41 RegKey::RegKey() : key_(NULL), wow64access_(0) {}
42 
RegKey(HKEY key)43 RegKey::RegKey(HKEY key) : key_(key), wow64access_(0) {}
44 
RegKey(HKEY rootkey,const char16_t * subkey,REGSAM access)45 RegKey::RegKey(HKEY rootkey, const char16_t* subkey, REGSAM access)
46     : key_(NULL), wow64access_(0) {
47   if (rootkey) {
48     if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
49       Create(rootkey, subkey, access);
50     else
51       Open(rootkey, subkey, access);
52   } else {
53     DCHECK(!subkey);
54     wow64access_ = access & kWow64AccessMask;
55   }
56 }
57 
~RegKey()58 RegKey::~RegKey() {
59   Close();
60 }
61 
Create(HKEY rootkey,const char16_t * subkey,REGSAM access)62 LONG RegKey::Create(HKEY rootkey, const char16_t* subkey, REGSAM access) {
63   DWORD disposition_value;
64   return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
65 }
66 
CreateWithDisposition(HKEY rootkey,const char16_t * subkey,DWORD * disposition,REGSAM access)67 LONG RegKey::CreateWithDisposition(HKEY rootkey,
68                                    const char16_t* subkey,
69                                    DWORD* disposition,
70                                    REGSAM access) {
71   DCHECK(rootkey && subkey && access && disposition);
72   HKEY subhkey = NULL;
73   LONG result = RegCreateKeyEx(rootkey, ToWCharT(subkey), 0, NULL,
74                                REG_OPTION_NON_VOLATILE, access, NULL, &subhkey,
75                                disposition);
76   if (result == ERROR_SUCCESS) {
77     Close();
78     key_ = subhkey;
79     wow64access_ = access & kWow64AccessMask;
80   }
81 
82   return result;
83 }
84 
CreateKey(const char16_t * name,REGSAM access)85 LONG RegKey::CreateKey(const char16_t* name, REGSAM access) {
86   DCHECK(name && access);
87   // After the application has accessed an alternate registry view using one of
88   // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
89   // (create, delete, or open) on child registry keys must explicitly use the
90   // same flag. Otherwise, there can be unexpected behavior.
91   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
92   if ((access & kWow64AccessMask) != wow64access_) {
93     NOTREACHED();
94     return ERROR_INVALID_PARAMETER;
95   }
96   HKEY subkey = NULL;
97   LONG result =
98       RegCreateKeyEx(key_, ToWCharT(name), 0, NULL, REG_OPTION_NON_VOLATILE,
99                      access, NULL, &subkey, NULL);
100   if (result == ERROR_SUCCESS) {
101     Close();
102     key_ = subkey;
103     wow64access_ = access & kWow64AccessMask;
104   }
105 
106   return result;
107 }
108 
Open(HKEY rootkey,const char16_t * subkey,REGSAM access)109 LONG RegKey::Open(HKEY rootkey, const char16_t* subkey, REGSAM access) {
110   DCHECK(rootkey && subkey && access);
111   HKEY subhkey = NULL;
112 
113   LONG result = RegOpenKeyEx(rootkey, ToWCharT(subkey), 0, access, &subhkey);
114   if (result == ERROR_SUCCESS) {
115     Close();
116     key_ = subhkey;
117     wow64access_ = access & kWow64AccessMask;
118   }
119 
120   return result;
121 }
122 
OpenKey(const char16_t * relative_key_name,REGSAM access)123 LONG RegKey::OpenKey(const char16_t* relative_key_name, REGSAM access) {
124   DCHECK(relative_key_name && access);
125   // After the application has accessed an alternate registry view using one of
126   // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
127   // (create, delete, or open) on child registry keys must explicitly use the
128   // same flag. Otherwise, there can be unexpected behavior.
129   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
130   if ((access & kWow64AccessMask) != wow64access_) {
131     NOTREACHED();
132     return ERROR_INVALID_PARAMETER;
133   }
134   HKEY subkey = NULL;
135   LONG result =
136       RegOpenKeyEx(key_, ToWCharT(relative_key_name), 0, access, &subkey);
137 
138   // We have to close the current opened key before replacing it with the new
139   // one.
140   if (result == ERROR_SUCCESS) {
141     Close();
142     key_ = subkey;
143     wow64access_ = access & kWow64AccessMask;
144   }
145   return result;
146 }
147 
Close()148 void RegKey::Close() {
149   if (key_) {
150     ::RegCloseKey(key_);
151     key_ = NULL;
152     wow64access_ = 0;
153   }
154 }
155 
156 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
Set(HKEY key)157 void RegKey::Set(HKEY key) {
158   if (key_ != key) {
159     Close();
160     key_ = key;
161   }
162 }
163 
Take()164 HKEY RegKey::Take() {
165   DCHECK_EQ(wow64access_, 0u);
166   HKEY key = key_;
167   key_ = NULL;
168   return key;
169 }
170 
HasValue(const char16_t * name) const171 bool RegKey::HasValue(const char16_t* name) const {
172   return RegQueryValueEx(key_, ToWCharT(name), 0, NULL, NULL, NULL) ==
173          ERROR_SUCCESS;
174 }
175 
GetValueCount() const176 DWORD RegKey::GetValueCount() const {
177   DWORD count = 0;
178   LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
179                                 NULL, NULL, NULL, NULL);
180   return (result == ERROR_SUCCESS) ? count : 0;
181 }
182 
GetValueNameAt(int index,std::u16string * name) const183 LONG RegKey::GetValueNameAt(int index, std::u16string* name) const {
184   char16_t buf[256];
185   DWORD bufsize = std::size(buf);
186   LONG r = ::RegEnumValue(key_, index, ToWCharT(buf), &bufsize, NULL, NULL,
187                           NULL, NULL);
188   if (r == ERROR_SUCCESS)
189     *name = buf;
190 
191   return r;
192 }
193 
DeleteKey(const char16_t * name)194 LONG RegKey::DeleteKey(const char16_t* name) {
195   DCHECK(key_);
196   DCHECK(name);
197   HKEY subkey = NULL;
198 
199   // Verify the key exists before attempting delete to replicate previous
200   // behavior.
201   LONG result = RegOpenKeyEx(key_, ToWCharT(name), 0,
202                              READ_CONTROL | wow64access_, &subkey);
203   if (result != ERROR_SUCCESS)
204     return result;
205   RegCloseKey(subkey);
206 
207   return RegDelRecurse(key_, std::u16string(name), wow64access_);
208 }
209 
DeleteEmptyKey(const char16_t * name)210 LONG RegKey::DeleteEmptyKey(const char16_t* name) {
211   DCHECK(key_);
212   DCHECK(name);
213 
214   HKEY target_key = NULL;
215   LONG result = RegOpenKeyEx(key_, ToWCharT(name), 0, KEY_READ | wow64access_,
216                              &target_key);
217 
218   if (result != ERROR_SUCCESS)
219     return result;
220 
221   DWORD count = 0;
222   result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
223                            NULL, NULL, NULL, NULL);
224 
225   RegCloseKey(target_key);
226 
227   if (result != ERROR_SUCCESS)
228     return result;
229 
230   if (count == 0)
231     return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
232 
233   return ERROR_DIR_NOT_EMPTY;
234 }
235 
DeleteValue(const char16_t * value_name)236 LONG RegKey::DeleteValue(const char16_t* value_name) {
237   DCHECK(key_);
238   LONG result = RegDeleteValue(key_, ToWCharT(value_name));
239   return result;
240 }
241 
ReadValueDW(const char16_t * name,DWORD * out_value) const242 LONG RegKey::ReadValueDW(const char16_t* name, DWORD* out_value) const {
243   DCHECK(out_value);
244   DWORD type = REG_DWORD;
245   DWORD size = sizeof(DWORD);
246   DWORD local_value = 0;
247   LONG result = ReadValue(name, &local_value, &size, &type);
248   if (result == ERROR_SUCCESS) {
249     if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
250       *out_value = local_value;
251     else
252       result = ERROR_CANTREAD;
253   }
254 
255   return result;
256 }
257 
ReadInt64(const char16_t * name,int64_t * out_value) const258 LONG RegKey::ReadInt64(const char16_t* name, int64_t* out_value) const {
259   DCHECK(out_value);
260   DWORD type = REG_QWORD;
261   int64_t local_value = 0;
262   DWORD size = sizeof(local_value);
263   LONG result = ReadValue(name, &local_value, &size, &type);
264   if (result == ERROR_SUCCESS) {
265     if ((type == REG_QWORD || type == REG_BINARY) &&
266         size == sizeof(local_value))
267       *out_value = local_value;
268     else
269       result = ERROR_CANTREAD;
270   }
271 
272   return result;
273 }
274 
ReadValue(const char16_t * name,std::u16string * out_value) const275 LONG RegKey::ReadValue(const char16_t* name, std::u16string* out_value) const {
276   DCHECK(out_value);
277   const size_t kMaxStringLength = 1024;  // This is after expansion.
278   // Use the one of the other forms of ReadValue if 1024 is too small for you.
279   char16_t raw_value[kMaxStringLength];
280   DWORD type = REG_SZ, size = sizeof(raw_value);
281   LONG result = ReadValue(name, raw_value, &size, &type);
282   if (result == ERROR_SUCCESS) {
283     if (type == REG_SZ) {
284       *out_value = raw_value;
285     } else if (type == REG_EXPAND_SZ) {
286       char16_t expanded[kMaxStringLength];
287       size = ExpandEnvironmentStrings(ToWCharT(raw_value), ToWCharT(expanded),
288                                       kMaxStringLength);
289       // Success: returns the number of char16_t's copied
290       // Fail: buffer too small, returns the size required
291       // Fail: other, returns 0
292       if (size == 0 || size > kMaxStringLength) {
293         result = ERROR_MORE_DATA;
294       } else {
295         *out_value = expanded;
296       }
297     } else {
298       // Not a string. Oops.
299       result = ERROR_CANTREAD;
300     }
301   }
302 
303   return result;
304 }
305 
ReadValue(const char16_t * name,void * data,DWORD * dsize,DWORD * dtype) const306 LONG RegKey::ReadValue(const char16_t* name,
307                        void* data,
308                        DWORD* dsize,
309                        DWORD* dtype) const {
310   LONG result = RegQueryValueEx(key_, ToWCharT(name), 0, dtype,
311                                 reinterpret_cast<LPBYTE>(data), dsize);
312   return result;
313 }
314 
ReadValues(const char16_t * name,std::vector<std::u16string> * values)315 LONG RegKey::ReadValues(const char16_t* name,
316                         std::vector<std::u16string>* values) {
317   values->clear();
318 
319   DWORD type = REG_MULTI_SZ;
320   DWORD size = 0;
321   LONG result = ReadValue(name, NULL, &size, &type);
322   if (result != ERROR_SUCCESS || size == 0)
323     return result;
324 
325   if (type != REG_MULTI_SZ)
326     return ERROR_CANTREAD;
327 
328   std::vector<char16_t> buffer(size / sizeof(char16_t));
329   result = ReadValue(name, &buffer[0], &size, NULL);
330   if (result != ERROR_SUCCESS || size == 0)
331     return result;
332 
333   // Parse the double-null-terminated list of strings.
334   // Note: This code is paranoid to not read outside of |buf|, in the case where
335   // it may not be properly terminated.
336   const char16_t* entry = &buffer[0];
337   const char16_t* buffer_end = entry + (size / sizeof(char16_t));
338   while (entry < buffer_end && entry[0] != '\0') {
339     const char16_t* entry_end = std::find(entry, buffer_end, L'\0');
340     values->push_back(std::u16string(entry, entry_end));
341     entry = entry_end + 1;
342   }
343   return 0;
344 }
345 
WriteValue(const char16_t * name,DWORD in_value)346 LONG RegKey::WriteValue(const char16_t* name, DWORD in_value) {
347   return WriteValue(name, &in_value, static_cast<DWORD>(sizeof(in_value)),
348                     REG_DWORD);
349 }
350 
WriteValue(const char16_t * name,const char16_t * in_value)351 LONG RegKey::WriteValue(const char16_t* name, const char16_t* in_value) {
352   return WriteValue(
353       name, in_value,
354       static_cast<DWORD>(sizeof(*in_value) * (wcslen(ToWCharT(in_value)) + 1)),
355       REG_SZ);
356 }
357 
WriteValue(const char16_t * name,const void * data,DWORD dsize,DWORD dtype)358 LONG RegKey::WriteValue(const char16_t* name,
359                         const void* data,
360                         DWORD dsize,
361                         DWORD dtype) {
362   DCHECK(data || !dsize);
363 
364   LONG result =
365       RegSetValueEx(key_, ToWCharT(name), 0, dtype,
366                     reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
367   return result;
368 }
369 
370 // static
RegDeleteKeyExWrapper(HKEY hKey,const char16_t * lpSubKey,REGSAM samDesired,DWORD Reserved)371 LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
372                                    const char16_t* lpSubKey,
373                                    REGSAM samDesired,
374                                    DWORD Reserved) {
375   typedef LSTATUS(WINAPI * RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
376 
377   RegDeleteKeyExPtr reg_delete_key_ex_func =
378       reinterpret_cast<RegDeleteKeyExPtr>(
379           GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
380 
381   if (reg_delete_key_ex_func)
382     return reg_delete_key_ex_func(hKey, ToWCharT(lpSubKey), samDesired,
383                                   Reserved);
384 
385   // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
386   return RegDeleteKey(hKey, ToWCharT(lpSubKey));
387 }
388 
389 // static
RegDelRecurse(HKEY root_key,const std::u16string & name,REGSAM access)390 LONG RegKey::RegDelRecurse(HKEY root_key,
391                            const std::u16string& name,
392                            REGSAM access) {
393   // First, see if the key can be deleted without having to recurse.
394   LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
395   if (result == ERROR_SUCCESS)
396     return result;
397 
398   HKEY target_key = NULL;
399   result = RegOpenKeyEx(root_key, ToWCharT(&name), 0,
400                         KEY_ENUMERATE_SUB_KEYS | access, &target_key);
401 
402   if (result == ERROR_FILE_NOT_FOUND)
403     return ERROR_SUCCESS;
404   if (result != ERROR_SUCCESS)
405     return result;
406 
407   std::u16string subkey_name(name);
408 
409   // Check for an ending slash and add one if it is missing.
410   if (!name.empty() && subkey_name[name.length() - 1] != '\\')
411     subkey_name += u"\\";
412 
413   // Enumerate the keys
414   result = ERROR_SUCCESS;
415   const DWORD kMaxKeyNameLength = MAX_PATH;
416   const size_t base_key_length = subkey_name.length();
417   std::u16string key_name;
418   while (result == ERROR_SUCCESS) {
419     DWORD key_size = kMaxKeyNameLength;
420     result = RegEnumKeyEx(target_key, 0,
421                           ToWCharT(WriteInto(&key_name, kMaxKeyNameLength)),
422                           &key_size, NULL, NULL, NULL, NULL);
423 
424     if (result != ERROR_SUCCESS)
425       break;
426 
427     key_name.resize(key_size);
428     subkey_name.resize(base_key_length);
429     subkey_name += key_name;
430 
431     if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
432       break;
433   }
434 
435   RegCloseKey(target_key);
436 
437   // Try again to delete the key.
438   result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
439 
440   return result;
441 }
442 
443 // RegistryValueIterator ------------------------------------------------------
444 
RegistryValueIterator(HKEY root_key,const char16_t * folder_key,REGSAM wow64access)445 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
446                                              const char16_t* folder_key,
447                                              REGSAM wow64access)
448     : name_(MAX_PATH, L'\0'), value_(MAX_PATH, L'\0') {
449   Initialize(root_key, folder_key, wow64access);
450 }
451 
RegistryValueIterator(HKEY root_key,const char16_t * folder_key)452 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
453                                              const char16_t* folder_key)
454     : name_(MAX_PATH, L'\0'), value_(MAX_PATH, L'\0') {
455   Initialize(root_key, folder_key, 0);
456 }
457 
Initialize(HKEY root_key,const char16_t * folder_key,REGSAM wow64access)458 void RegistryValueIterator::Initialize(HKEY root_key,
459                                        const char16_t* folder_key,
460                                        REGSAM wow64access) {
461   DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
462   LONG result = RegOpenKeyEx(root_key, ToWCharT(folder_key), 0,
463                              KEY_READ | wow64access, &key_);
464   if (result != ERROR_SUCCESS) {
465     key_ = NULL;
466   } else {
467     DWORD count = 0;
468     result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
469                                NULL, NULL, NULL, NULL);
470 
471     if (result != ERROR_SUCCESS) {
472       ::RegCloseKey(key_);
473       key_ = NULL;
474     } else {
475       index_ = count - 1;
476     }
477   }
478 
479   Read();
480 }
481 
~RegistryValueIterator()482 RegistryValueIterator::~RegistryValueIterator() {
483   if (key_)
484     ::RegCloseKey(key_);
485 }
486 
ValueCount() const487 DWORD RegistryValueIterator::ValueCount() const {
488   DWORD count = 0;
489   LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
490                                   NULL, NULL, NULL, NULL);
491   if (result != ERROR_SUCCESS)
492     return 0;
493 
494   return count;
495 }
496 
Valid() const497 bool RegistryValueIterator::Valid() const {
498   return key_ != NULL && index_ >= 0;
499 }
500 
operator ++()501 void RegistryValueIterator::operator++() {
502   --index_;
503   Read();
504 }
505 
Read()506 bool RegistryValueIterator::Read() {
507   if (Valid()) {
508     DWORD capacity = static_cast<DWORD>(name_.capacity());
509     DWORD name_size = capacity;
510     // |value_size_| is in bytes. Reserve the last character for a NUL.
511     value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(char16_t));
512     LONG result = ::RegEnumValue(
513         key_, index_, ToWCharT(WriteInto(&name_, name_size)), &name_size, NULL,
514         &type_, reinterpret_cast<BYTE*>(value_.data()), &value_size_);
515 
516     if (result == ERROR_MORE_DATA) {
517       // Registry key names are limited to 255 characters and fit within
518       // MAX_PATH (which is 260) but registry value names can use up to 16,383
519       // characters and the value itself is not limited
520       // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
521       // ms724872(v=vs.85).aspx).
522       // Resize the buffers and retry if their size caused the failure.
523       DWORD value_size_in_wchars = to_wchar_size(value_size_);
524       if (value_size_in_wchars + 1 > value_.size())
525         value_.resize(value_size_in_wchars + 1, L'\0');
526       value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(char16_t));
527       name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
528       result = ::RegEnumValue(
529           key_, index_, ToWCharT(WriteInto(&name_, name_size)), &name_size,
530           NULL, &type_, reinterpret_cast<BYTE*>(value_.data()), &value_size_);
531     }
532 
533     if (result == ERROR_SUCCESS) {
534       DCHECK_LT(to_wchar_size(value_size_), value_.size());
535       value_[to_wchar_size(value_size_)] = L'\0';
536       return true;
537     }
538   }
539 
540   name_[0] = L'\0';
541   value_[0] = L'\0';
542   value_size_ = 0;
543   return false;
544 }
545 
546 // RegistryKeyIterator --------------------------------------------------------
547 
RegistryKeyIterator(HKEY root_key,const char16_t * folder_key)548 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
549                                          const char16_t* folder_key) {
550   Initialize(root_key, folder_key, 0);
551 }
552 
RegistryKeyIterator(HKEY root_key,const char16_t * folder_key,REGSAM wow64access)553 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
554                                          const char16_t* folder_key,
555                                          REGSAM wow64access) {
556   Initialize(root_key, folder_key, wow64access);
557 }
558 
~RegistryKeyIterator()559 RegistryKeyIterator::~RegistryKeyIterator() {
560   if (key_)
561     ::RegCloseKey(key_);
562 }
563 
SubkeyCount() const564 DWORD RegistryKeyIterator::SubkeyCount() const {
565   DWORD count = 0;
566   LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, NULL,
567                                   NULL, NULL, NULL, NULL);
568   if (result != ERROR_SUCCESS)
569     return 0;
570 
571   return count;
572 }
573 
Valid() const574 bool RegistryKeyIterator::Valid() const {
575   return key_ != NULL && index_ >= 0;
576 }
577 
operator ++()578 void RegistryKeyIterator::operator++() {
579   --index_;
580   Read();
581 }
582 
Read()583 bool RegistryKeyIterator::Read() {
584   if (Valid()) {
585     DWORD ncount = std::size(name_);
586     FILETIME written;
587     LONG r = ::RegEnumKeyEx(key_, index_, ToWCharT(name_), &ncount, NULL, NULL,
588                             NULL, &written);
589     if (ERROR_SUCCESS == r)
590       return true;
591   }
592 
593   name_[0] = '\0';
594   return false;
595 }
596 
Initialize(HKEY root_key,const char16_t * folder_key,REGSAM wow64access)597 void RegistryKeyIterator::Initialize(HKEY root_key,
598                                      const char16_t* folder_key,
599                                      REGSAM wow64access) {
600   DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
601   LONG result = RegOpenKeyEx(root_key, ToWCharT(folder_key), 0,
602                              KEY_READ | wow64access, &key_);
603   if (result != ERROR_SUCCESS) {
604     key_ = NULL;
605   } else {
606     DWORD count = 0;
607     result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, NULL,
608                                NULL, NULL, NULL, NULL);
609 
610     if (result != ERROR_SUCCESS) {
611       ::RegCloseKey(key_);
612       key_ = NULL;
613     } else {
614       index_ = count - 1;
615     }
616   }
617 
618   Read();
619 }
620 
621 }  // namespace win
622 }  // namespace base
623