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