1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/win/registry.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <ntstatus.h>
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <algorithm>
11*6777b538SAndroid Build Coastguard Worker #include <iterator>
12*6777b538SAndroid Build Coastguard Worker #include <memory>
13*6777b538SAndroid Build Coastguard Worker #include <string>
14*6777b538SAndroid Build Coastguard Worker #include <utility>
15*6777b538SAndroid Build Coastguard Worker #include <vector>
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util_win.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/win/object_watcher.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_handle.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/win/shlwapi.h"
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker extern "C" NTSTATUS WINAPI NtDeleteKey(IN HANDLE KeyHandle);
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker namespace base::win {
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker namespace {
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker // RegEnumValue() reports the number of characters from the name that were
34*6777b538SAndroid Build Coastguard Worker // written to the buffer, not how many there are. This constant is the maximum
35*6777b538SAndroid Build Coastguard Worker // name size, such that a buffer with this size should read any name.
36*6777b538SAndroid Build Coastguard Worker constexpr DWORD MAX_REGISTRY_NAME_SIZE = 16384;
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker // Registry values are read as BYTE* but can have wchar_t* data whose last
39*6777b538SAndroid Build Coastguard Worker // wchar_t is truncated. This function converts the reported |byte_size| to
40*6777b538SAndroid Build Coastguard Worker // a size in wchar_t that can store a truncated wchar_t if necessary.
to_wchar_size(DWORD byte_size)41*6777b538SAndroid Build Coastguard Worker inline DWORD to_wchar_size(DWORD byte_size) {
42*6777b538SAndroid Build Coastguard Worker return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
43*6777b538SAndroid Build Coastguard Worker }
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker // Mask to pull WOW64 access flags out of REGSAM access.
46*6777b538SAndroid Build Coastguard Worker constexpr REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Worker constexpr DWORD kInvalidIterValue = static_cast<DWORD>(-1);
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker } // namespace
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Worker // Watches for modifications to a key.
53*6777b538SAndroid Build Coastguard Worker class RegKey::Watcher : public ObjectWatcher::Delegate {
54*6777b538SAndroid Build Coastguard Worker public:
55*6777b538SAndroid Build Coastguard Worker Watcher() = default;
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker Watcher(const Watcher&) = delete;
58*6777b538SAndroid Build Coastguard Worker Watcher& operator=(const Watcher&) = delete;
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker ~Watcher() override = default;
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker bool StartWatching(HKEY key, ChangeCallback callback);
63*6777b538SAndroid Build Coastguard Worker
64*6777b538SAndroid Build Coastguard Worker // ObjectWatcher::Delegate:
OnObjectSignaled(HANDLE object)65*6777b538SAndroid Build Coastguard Worker void OnObjectSignaled(HANDLE object) override {
66*6777b538SAndroid Build Coastguard Worker DCHECK(watch_event_.is_valid());
67*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(watch_event_.get(), object);
68*6777b538SAndroid Build Coastguard Worker std::move(callback_).Run();
69*6777b538SAndroid Build Coastguard Worker }
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker private:
72*6777b538SAndroid Build Coastguard Worker ScopedHandle watch_event_;
73*6777b538SAndroid Build Coastguard Worker ObjectWatcher object_watcher_;
74*6777b538SAndroid Build Coastguard Worker ChangeCallback callback_;
75*6777b538SAndroid Build Coastguard Worker };
76*6777b538SAndroid Build Coastguard Worker
StartWatching(HKEY key,ChangeCallback callback)77*6777b538SAndroid Build Coastguard Worker bool RegKey::Watcher::StartWatching(HKEY key, ChangeCallback callback) {
78*6777b538SAndroid Build Coastguard Worker DCHECK(key);
79*6777b538SAndroid Build Coastguard Worker DCHECK(callback_.is_null());
80*6777b538SAndroid Build Coastguard Worker
81*6777b538SAndroid Build Coastguard Worker if (!watch_event_.is_valid()) {
82*6777b538SAndroid Build Coastguard Worker watch_event_.Set(CreateEvent(nullptr, TRUE, FALSE, nullptr));
83*6777b538SAndroid Build Coastguard Worker }
84*6777b538SAndroid Build Coastguard Worker
85*6777b538SAndroid Build Coastguard Worker if (!watch_event_.is_valid()) {
86*6777b538SAndroid Build Coastguard Worker return false;
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker
89*6777b538SAndroid Build Coastguard Worker DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
90*6777b538SAndroid Build Coastguard Worker REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY |
91*6777b538SAndroid Build Coastguard Worker REG_NOTIFY_THREAD_AGNOSTIC;
92*6777b538SAndroid Build Coastguard Worker // Watch the registry key for a change of value.
93*6777b538SAndroid Build Coastguard Worker LONG result =
94*6777b538SAndroid Build Coastguard Worker RegNotifyChangeKeyValue(key, /*bWatchSubtree=*/TRUE, filter,
95*6777b538SAndroid Build Coastguard Worker watch_event_.get(), /*fAsynchronous=*/TRUE);
96*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
97*6777b538SAndroid Build Coastguard Worker watch_event_.Close();
98*6777b538SAndroid Build Coastguard Worker return false;
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker callback_ = std::move(callback);
102*6777b538SAndroid Build Coastguard Worker return object_watcher_.StartWatchingOnce(watch_event_.get(), this);
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker // RegKey ----------------------------------------------------------------------
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard Worker RegKey::RegKey() = default;
108*6777b538SAndroid Build Coastguard Worker
RegKey(HKEY key)109*6777b538SAndroid Build Coastguard Worker RegKey::RegKey(HKEY key) : key_(key) {}
110*6777b538SAndroid Build Coastguard Worker
RegKey(HKEY rootkey,const wchar_t * subkey,REGSAM access)111*6777b538SAndroid Build Coastguard Worker RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
112*6777b538SAndroid Build Coastguard Worker if (rootkey) {
113*6777b538SAndroid Build Coastguard Worker if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
114*6777b538SAndroid Build Coastguard Worker (void)Create(rootkey, subkey, access);
115*6777b538SAndroid Build Coastguard Worker } else {
116*6777b538SAndroid Build Coastguard Worker (void)Open(rootkey, subkey, access);
117*6777b538SAndroid Build Coastguard Worker }
118*6777b538SAndroid Build Coastguard Worker } else {
119*6777b538SAndroid Build Coastguard Worker DCHECK(!subkey);
120*6777b538SAndroid Build Coastguard Worker wow64access_ = access & kWow64AccessMask;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker
RegKey(RegKey && other)124*6777b538SAndroid Build Coastguard Worker RegKey::RegKey(RegKey&& other) noexcept
125*6777b538SAndroid Build Coastguard Worker : key_(other.key_),
126*6777b538SAndroid Build Coastguard Worker wow64access_(other.wow64access_),
127*6777b538SAndroid Build Coastguard Worker key_watcher_(std::move(other.key_watcher_)) {
128*6777b538SAndroid Build Coastguard Worker other.key_ = nullptr;
129*6777b538SAndroid Build Coastguard Worker other.wow64access_ = 0;
130*6777b538SAndroid Build Coastguard Worker }
131*6777b538SAndroid Build Coastguard Worker
operator =(RegKey && other)132*6777b538SAndroid Build Coastguard Worker RegKey& RegKey::operator=(RegKey&& other) {
133*6777b538SAndroid Build Coastguard Worker Close();
134*6777b538SAndroid Build Coastguard Worker std::swap(key_, other.key_);
135*6777b538SAndroid Build Coastguard Worker std::swap(wow64access_, other.wow64access_);
136*6777b538SAndroid Build Coastguard Worker key_watcher_ = std::move(other.key_watcher_);
137*6777b538SAndroid Build Coastguard Worker return *this;
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker
~RegKey()140*6777b538SAndroid Build Coastguard Worker RegKey::~RegKey() {
141*6777b538SAndroid Build Coastguard Worker Close();
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker
Create(HKEY rootkey,const wchar_t * subkey,REGSAM access)144*6777b538SAndroid Build Coastguard Worker LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
145*6777b538SAndroid Build Coastguard Worker DWORD disposition_value;
146*6777b538SAndroid Build Coastguard Worker return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker
CreateWithDisposition(HKEY rootkey,const wchar_t * subkey,DWORD * disposition,REGSAM access)149*6777b538SAndroid Build Coastguard Worker LONG RegKey::CreateWithDisposition(HKEY rootkey,
150*6777b538SAndroid Build Coastguard Worker const wchar_t* subkey,
151*6777b538SAndroid Build Coastguard Worker DWORD* disposition,
152*6777b538SAndroid Build Coastguard Worker REGSAM access) {
153*6777b538SAndroid Build Coastguard Worker DCHECK(rootkey && subkey && access && disposition);
154*6777b538SAndroid Build Coastguard Worker HKEY subhkey = nullptr;
155*6777b538SAndroid Build Coastguard Worker LONG result =
156*6777b538SAndroid Build Coastguard Worker RegCreateKeyEx(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE,
157*6777b538SAndroid Build Coastguard Worker access, nullptr, &subhkey, disposition);
158*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
159*6777b538SAndroid Build Coastguard Worker Close();
160*6777b538SAndroid Build Coastguard Worker key_ = subhkey;
161*6777b538SAndroid Build Coastguard Worker wow64access_ = access & kWow64AccessMask;
162*6777b538SAndroid Build Coastguard Worker }
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker return result;
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker
CreateKey(const wchar_t * name,REGSAM access)167*6777b538SAndroid Build Coastguard Worker LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
168*6777b538SAndroid Build Coastguard Worker DCHECK(name && access);
169*6777b538SAndroid Build Coastguard Worker
170*6777b538SAndroid Build Coastguard Worker if (!Valid()) {
171*6777b538SAndroid Build Coastguard Worker // The parent key has not been opened or created.
172*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_HANDLE;
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker // After the application has accessed an alternate registry view using one
176*6777b538SAndroid Build Coastguard Worker // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
177*6777b538SAndroid Build Coastguard Worker // operations (create, delete, or open) on child registry keys must
178*6777b538SAndroid Build Coastguard Worker // explicitly use the same flag. Otherwise, there can be unexpected
179*6777b538SAndroid Build Coastguard Worker // behavior.
180*6777b538SAndroid Build Coastguard Worker // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
181*6777b538SAndroid Build Coastguard Worker if ((access & kWow64AccessMask) != wow64access_) {
182*6777b538SAndroid Build Coastguard Worker NOTREACHED();
183*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_PARAMETER;
184*6777b538SAndroid Build Coastguard Worker }
185*6777b538SAndroid Build Coastguard Worker HKEY subkey = nullptr;
186*6777b538SAndroid Build Coastguard Worker LONG result = RegCreateKeyEx(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE,
187*6777b538SAndroid Build Coastguard Worker access, nullptr, &subkey, nullptr);
188*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
189*6777b538SAndroid Build Coastguard Worker Close();
190*6777b538SAndroid Build Coastguard Worker key_ = subkey;
191*6777b538SAndroid Build Coastguard Worker wow64access_ = access & kWow64AccessMask;
192*6777b538SAndroid Build Coastguard Worker }
193*6777b538SAndroid Build Coastguard Worker
194*6777b538SAndroid Build Coastguard Worker return result;
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker
Open(HKEY rootkey,const wchar_t * subkey,REGSAM access)197*6777b538SAndroid Build Coastguard Worker LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
198*6777b538SAndroid Build Coastguard Worker return Open(rootkey, subkey, /*options=*/0, access);
199*6777b538SAndroid Build Coastguard Worker }
200*6777b538SAndroid Build Coastguard Worker
OpenKey(const wchar_t * relative_key_name,REGSAM access)201*6777b538SAndroid Build Coastguard Worker LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
202*6777b538SAndroid Build Coastguard Worker DCHECK(relative_key_name && access);
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker if (!Valid()) {
205*6777b538SAndroid Build Coastguard Worker // The parent key has not been opened or created.
206*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_HANDLE;
207*6777b538SAndroid Build Coastguard Worker }
208*6777b538SAndroid Build Coastguard Worker
209*6777b538SAndroid Build Coastguard Worker // After the application has accessed an alternate registry view using one
210*6777b538SAndroid Build Coastguard Worker // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
211*6777b538SAndroid Build Coastguard Worker // operations (create, delete, or open) on child registry keys must
212*6777b538SAndroid Build Coastguard Worker // explicitly use the same flag. Otherwise, there can be unexpected
213*6777b538SAndroid Build Coastguard Worker // behavior.
214*6777b538SAndroid Build Coastguard Worker // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
215*6777b538SAndroid Build Coastguard Worker if ((access & kWow64AccessMask) != wow64access_) {
216*6777b538SAndroid Build Coastguard Worker NOTREACHED();
217*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_PARAMETER;
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker HKEY subkey = nullptr;
220*6777b538SAndroid Build Coastguard Worker LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
221*6777b538SAndroid Build Coastguard Worker
222*6777b538SAndroid Build Coastguard Worker // We have to close the current opened key before replacing it with the new
223*6777b538SAndroid Build Coastguard Worker // one.
224*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
225*6777b538SAndroid Build Coastguard Worker Close();
226*6777b538SAndroid Build Coastguard Worker key_ = subkey;
227*6777b538SAndroid Build Coastguard Worker wow64access_ = access & kWow64AccessMask;
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker return result;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker
Close()232*6777b538SAndroid Build Coastguard Worker void RegKey::Close() {
233*6777b538SAndroid Build Coastguard Worker if (key_) {
234*6777b538SAndroid Build Coastguard Worker ::RegCloseKey(key_);
235*6777b538SAndroid Build Coastguard Worker key_ = nullptr;
236*6777b538SAndroid Build Coastguard Worker wow64access_ = 0;
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker }
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
Set(HKEY key)241*6777b538SAndroid Build Coastguard Worker void RegKey::Set(HKEY key) {
242*6777b538SAndroid Build Coastguard Worker if (key_ != key) {
243*6777b538SAndroid Build Coastguard Worker Close();
244*6777b538SAndroid Build Coastguard Worker key_ = key;
245*6777b538SAndroid Build Coastguard Worker }
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker
Take()248*6777b538SAndroid Build Coastguard Worker HKEY RegKey::Take() {
249*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(wow64access_, 0u);
250*6777b538SAndroid Build Coastguard Worker HKEY key = key_;
251*6777b538SAndroid Build Coastguard Worker key_ = nullptr;
252*6777b538SAndroid Build Coastguard Worker return key;
253*6777b538SAndroid Build Coastguard Worker }
254*6777b538SAndroid Build Coastguard Worker
HasValue(const wchar_t * name) const255*6777b538SAndroid Build Coastguard Worker bool RegKey::HasValue(const wchar_t* name) const {
256*6777b538SAndroid Build Coastguard Worker return RegQueryValueEx(key_, name, nullptr, nullptr, nullptr, nullptr) ==
257*6777b538SAndroid Build Coastguard Worker ERROR_SUCCESS;
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
GetValueCount() const260*6777b538SAndroid Build Coastguard Worker base::expected<DWORD, LONG> RegKey::GetValueCount() const {
261*6777b538SAndroid Build Coastguard Worker DWORD count = 0;
262*6777b538SAndroid Build Coastguard Worker LONG result =
263*6777b538SAndroid Build Coastguard Worker RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
264*6777b538SAndroid Build Coastguard Worker nullptr, &count, nullptr, nullptr, nullptr, nullptr);
265*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
266*6777b538SAndroid Build Coastguard Worker return base::ok(count);
267*6777b538SAndroid Build Coastguard Worker }
268*6777b538SAndroid Build Coastguard Worker return base::unexpected(result);
269*6777b538SAndroid Build Coastguard Worker }
270*6777b538SAndroid Build Coastguard Worker
GetValueNameAt(DWORD index,std::wstring * name) const271*6777b538SAndroid Build Coastguard Worker LONG RegKey::GetValueNameAt(DWORD index, std::wstring* name) const {
272*6777b538SAndroid Build Coastguard Worker wchar_t buf[256];
273*6777b538SAndroid Build Coastguard Worker DWORD bufsize = std::size(buf);
274*6777b538SAndroid Build Coastguard Worker LONG r = ::RegEnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr,
275*6777b538SAndroid Build Coastguard Worker nullptr);
276*6777b538SAndroid Build Coastguard Worker if (r == ERROR_SUCCESS) {
277*6777b538SAndroid Build Coastguard Worker name->assign(buf, bufsize);
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker
280*6777b538SAndroid Build Coastguard Worker return r;
281*6777b538SAndroid Build Coastguard Worker }
282*6777b538SAndroid Build Coastguard Worker
DeleteKey(const wchar_t * name,RecursiveDelete recursive)283*6777b538SAndroid Build Coastguard Worker LONG RegKey::DeleteKey(const wchar_t* name, RecursiveDelete recursive) {
284*6777b538SAndroid Build Coastguard Worker DCHECK(name);
285*6777b538SAndroid Build Coastguard Worker
286*6777b538SAndroid Build Coastguard Worker if (!Valid()) {
287*6777b538SAndroid Build Coastguard Worker return ERROR_INVALID_HANDLE;
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Worker // Verify the key exists before attempting delete to replicate previous
291*6777b538SAndroid Build Coastguard Worker // behavior.
292*6777b538SAndroid Build Coastguard Worker RegKey target_key;
293*6777b538SAndroid Build Coastguard Worker LONG result = target_key.Open(key_, name, REG_OPTION_OPEN_LINK,
294*6777b538SAndroid Build Coastguard Worker wow64access_ | KEY_QUERY_VALUE | DELETE);
295*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
296*6777b538SAndroid Build Coastguard Worker return result;
297*6777b538SAndroid Build Coastguard Worker }
298*6777b538SAndroid Build Coastguard Worker
299*6777b538SAndroid Build Coastguard Worker if (recursive.value()) {
300*6777b538SAndroid Build Coastguard Worker target_key.Close();
301*6777b538SAndroid Build Coastguard Worker return RegDelRecurse(key_, name, wow64access_);
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker
304*6777b538SAndroid Build Coastguard Worker // Next, try to delete the key if it is a symbolic link.
305*6777b538SAndroid Build Coastguard Worker if (auto deleted_link = target_key.DeleteIfLink(); deleted_link.has_value()) {
306*6777b538SAndroid Build Coastguard Worker return deleted_link.value();
307*6777b538SAndroid Build Coastguard Worker }
308*6777b538SAndroid Build Coastguard Worker
309*6777b538SAndroid Build Coastguard Worker // It's not a symbolic link, so try to delete it without recursing.
310*6777b538SAndroid Build Coastguard Worker return ::RegDeleteKeyEx(target_key.key_, L"", wow64access_, 0);
311*6777b538SAndroid Build Coastguard Worker }
312*6777b538SAndroid Build Coastguard Worker
DeleteValue(const wchar_t * value_name)313*6777b538SAndroid Build Coastguard Worker LONG RegKey::DeleteValue(const wchar_t* value_name) {
314*6777b538SAndroid Build Coastguard Worker // `RegDeleteValue()` will return an error if `key_` is invalid.
315*6777b538SAndroid Build Coastguard Worker LONG result = RegDeleteValue(key_, value_name);
316*6777b538SAndroid Build Coastguard Worker return result;
317*6777b538SAndroid Build Coastguard Worker }
318*6777b538SAndroid Build Coastguard Worker
ReadValueDW(const wchar_t * name,DWORD * out_value) const319*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
320*6777b538SAndroid Build Coastguard Worker DCHECK(out_value);
321*6777b538SAndroid Build Coastguard Worker DWORD type = REG_DWORD;
322*6777b538SAndroid Build Coastguard Worker DWORD size = sizeof(DWORD);
323*6777b538SAndroid Build Coastguard Worker DWORD local_value = 0;
324*6777b538SAndroid Build Coastguard Worker LONG result = ReadValue(name, &local_value, &size, &type);
325*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
326*6777b538SAndroid Build Coastguard Worker if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) {
327*6777b538SAndroid Build Coastguard Worker *out_value = local_value;
328*6777b538SAndroid Build Coastguard Worker } else {
329*6777b538SAndroid Build Coastguard Worker result = ERROR_CANTREAD;
330*6777b538SAndroid Build Coastguard Worker }
331*6777b538SAndroid Build Coastguard Worker }
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker return result;
334*6777b538SAndroid Build Coastguard Worker }
335*6777b538SAndroid Build Coastguard Worker
ReadInt64(const wchar_t * name,int64_t * out_value) const336*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadInt64(const wchar_t* name, int64_t* out_value) const {
337*6777b538SAndroid Build Coastguard Worker DCHECK(out_value);
338*6777b538SAndroid Build Coastguard Worker DWORD type = REG_QWORD;
339*6777b538SAndroid Build Coastguard Worker int64_t local_value = 0;
340*6777b538SAndroid Build Coastguard Worker DWORD size = sizeof(local_value);
341*6777b538SAndroid Build Coastguard Worker LONG result = ReadValue(name, &local_value, &size, &type);
342*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
343*6777b538SAndroid Build Coastguard Worker if ((type == REG_QWORD || type == REG_BINARY) &&
344*6777b538SAndroid Build Coastguard Worker size == sizeof(local_value)) {
345*6777b538SAndroid Build Coastguard Worker *out_value = local_value;
346*6777b538SAndroid Build Coastguard Worker } else {
347*6777b538SAndroid Build Coastguard Worker result = ERROR_CANTREAD;
348*6777b538SAndroid Build Coastguard Worker }
349*6777b538SAndroid Build Coastguard Worker }
350*6777b538SAndroid Build Coastguard Worker
351*6777b538SAndroid Build Coastguard Worker return result;
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker
ReadValue(const wchar_t * name,std::wstring * out_value) const354*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
355*6777b538SAndroid Build Coastguard Worker DCHECK(out_value);
356*6777b538SAndroid Build Coastguard Worker const size_t kMaxStringLength = 1024; // This is after expansion.
357*6777b538SAndroid Build Coastguard Worker // Use the one of the other forms of ReadValue if 1024 is too small for you.
358*6777b538SAndroid Build Coastguard Worker wchar_t raw_value[kMaxStringLength];
359*6777b538SAndroid Build Coastguard Worker DWORD type = REG_SZ, size = sizeof(raw_value);
360*6777b538SAndroid Build Coastguard Worker LONG result = ReadValue(name, raw_value, &size, &type);
361*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
362*6777b538SAndroid Build Coastguard Worker if (type == REG_SZ) {
363*6777b538SAndroid Build Coastguard Worker *out_value = raw_value;
364*6777b538SAndroid Build Coastguard Worker } else if (type == REG_EXPAND_SZ) {
365*6777b538SAndroid Build Coastguard Worker wchar_t expanded[kMaxStringLength];
366*6777b538SAndroid Build Coastguard Worker size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
367*6777b538SAndroid Build Coastguard Worker // Success: returns the number of wchar_t's copied
368*6777b538SAndroid Build Coastguard Worker // Fail: buffer too small, returns the size required
369*6777b538SAndroid Build Coastguard Worker // Fail: other, returns 0
370*6777b538SAndroid Build Coastguard Worker if (size == 0 || size > kMaxStringLength) {
371*6777b538SAndroid Build Coastguard Worker result = ERROR_MORE_DATA;
372*6777b538SAndroid Build Coastguard Worker } else {
373*6777b538SAndroid Build Coastguard Worker *out_value = expanded;
374*6777b538SAndroid Build Coastguard Worker }
375*6777b538SAndroid Build Coastguard Worker } else {
376*6777b538SAndroid Build Coastguard Worker // Not a string. Oops.
377*6777b538SAndroid Build Coastguard Worker result = ERROR_CANTREAD;
378*6777b538SAndroid Build Coastguard Worker }
379*6777b538SAndroid Build Coastguard Worker }
380*6777b538SAndroid Build Coastguard Worker
381*6777b538SAndroid Build Coastguard Worker return result;
382*6777b538SAndroid Build Coastguard Worker }
383*6777b538SAndroid Build Coastguard Worker
ReadValue(const wchar_t * name,void * data,DWORD * dsize,DWORD * dtype) const384*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValue(const wchar_t* name,
385*6777b538SAndroid Build Coastguard Worker void* data,
386*6777b538SAndroid Build Coastguard Worker DWORD* dsize,
387*6777b538SAndroid Build Coastguard Worker DWORD* dtype) const {
388*6777b538SAndroid Build Coastguard Worker LONG result = RegQueryValueEx(key_, name, nullptr, dtype,
389*6777b538SAndroid Build Coastguard Worker reinterpret_cast<LPBYTE>(data), dsize);
390*6777b538SAndroid Build Coastguard Worker return result;
391*6777b538SAndroid Build Coastguard Worker }
392*6777b538SAndroid Build Coastguard Worker
ReadValues(const wchar_t * name,std::vector<std::wstring> * values)393*6777b538SAndroid Build Coastguard Worker LONG RegKey::ReadValues(const wchar_t* name,
394*6777b538SAndroid Build Coastguard Worker std::vector<std::wstring>* values) {
395*6777b538SAndroid Build Coastguard Worker values->clear();
396*6777b538SAndroid Build Coastguard Worker
397*6777b538SAndroid Build Coastguard Worker DWORD type = REG_MULTI_SZ;
398*6777b538SAndroid Build Coastguard Worker DWORD size = 0;
399*6777b538SAndroid Build Coastguard Worker LONG result = ReadValue(name, nullptr, &size, &type);
400*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS || size == 0) {
401*6777b538SAndroid Build Coastguard Worker return result;
402*6777b538SAndroid Build Coastguard Worker }
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker if (type != REG_MULTI_SZ) {
405*6777b538SAndroid Build Coastguard Worker return ERROR_CANTREAD;
406*6777b538SAndroid Build Coastguard Worker }
407*6777b538SAndroid Build Coastguard Worker
408*6777b538SAndroid Build Coastguard Worker std::vector<wchar_t> buffer(size / sizeof(wchar_t));
409*6777b538SAndroid Build Coastguard Worker result = ReadValue(name, buffer.data(), &size, nullptr);
410*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS || size == 0) {
411*6777b538SAndroid Build Coastguard Worker return result;
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker
414*6777b538SAndroid Build Coastguard Worker // Parse the double-null-terminated list of strings.
415*6777b538SAndroid Build Coastguard Worker // Note: This code is paranoid to not read outside of |buf|, in the case where
416*6777b538SAndroid Build Coastguard Worker // it may not be properly terminated.
417*6777b538SAndroid Build Coastguard Worker auto entry = buffer.cbegin();
418*6777b538SAndroid Build Coastguard Worker auto buffer_end = buffer.cend();
419*6777b538SAndroid Build Coastguard Worker while (entry < buffer_end && *entry != '\0') {
420*6777b538SAndroid Build Coastguard Worker auto entry_end = std::find(entry, buffer_end, '\0');
421*6777b538SAndroid Build Coastguard Worker values->emplace_back(entry, entry_end);
422*6777b538SAndroid Build Coastguard Worker entry = entry_end + 1;
423*6777b538SAndroid Build Coastguard Worker }
424*6777b538SAndroid Build Coastguard Worker return 0;
425*6777b538SAndroid Build Coastguard Worker }
426*6777b538SAndroid Build Coastguard Worker
WriteValue(const wchar_t * name,DWORD in_value)427*6777b538SAndroid Build Coastguard Worker LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
428*6777b538SAndroid Build Coastguard Worker return WriteValue(name, &in_value, static_cast<DWORD>(sizeof(in_value)),
429*6777b538SAndroid Build Coastguard Worker REG_DWORD);
430*6777b538SAndroid Build Coastguard Worker }
431*6777b538SAndroid Build Coastguard Worker
WriteValue(const wchar_t * name,const wchar_t * in_value)432*6777b538SAndroid Build Coastguard Worker LONG RegKey::WriteValue(const wchar_t* name, const wchar_t* in_value) {
433*6777b538SAndroid Build Coastguard Worker return WriteValue(
434*6777b538SAndroid Build Coastguard Worker name, in_value,
435*6777b538SAndroid Build Coastguard Worker static_cast<DWORD>(sizeof(*in_value) *
436*6777b538SAndroid Build Coastguard Worker (std::char_traits<wchar_t>::length(in_value) + 1)),
437*6777b538SAndroid Build Coastguard Worker REG_SZ);
438*6777b538SAndroid Build Coastguard Worker }
439*6777b538SAndroid Build Coastguard Worker
WriteValue(const wchar_t * name,const void * data,DWORD dsize,DWORD dtype)440*6777b538SAndroid Build Coastguard Worker LONG RegKey::WriteValue(const wchar_t* name,
441*6777b538SAndroid Build Coastguard Worker const void* data,
442*6777b538SAndroid Build Coastguard Worker DWORD dsize,
443*6777b538SAndroid Build Coastguard Worker DWORD dtype) {
444*6777b538SAndroid Build Coastguard Worker DCHECK(data || !dsize);
445*6777b538SAndroid Build Coastguard Worker
446*6777b538SAndroid Build Coastguard Worker LONG result =
447*6777b538SAndroid Build Coastguard Worker RegSetValueEx(key_, name, 0, dtype,
448*6777b538SAndroid Build Coastguard Worker reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
449*6777b538SAndroid Build Coastguard Worker return result;
450*6777b538SAndroid Build Coastguard Worker }
451*6777b538SAndroid Build Coastguard Worker
StartWatching(ChangeCallback callback)452*6777b538SAndroid Build Coastguard Worker bool RegKey::StartWatching(ChangeCallback callback) {
453*6777b538SAndroid Build Coastguard Worker if (!key_watcher_) {
454*6777b538SAndroid Build Coastguard Worker key_watcher_ = std::make_unique<Watcher>();
455*6777b538SAndroid Build Coastguard Worker }
456*6777b538SAndroid Build Coastguard Worker
457*6777b538SAndroid Build Coastguard Worker if (!key_watcher_->StartWatching(key_, std::move(callback))) {
458*6777b538SAndroid Build Coastguard Worker return false;
459*6777b538SAndroid Build Coastguard Worker }
460*6777b538SAndroid Build Coastguard Worker
461*6777b538SAndroid Build Coastguard Worker return true;
462*6777b538SAndroid Build Coastguard Worker }
463*6777b538SAndroid Build Coastguard Worker
Open(HKEY rootkey,const wchar_t * subkey,DWORD options,REGSAM access)464*6777b538SAndroid Build Coastguard Worker LONG RegKey::Open(HKEY rootkey,
465*6777b538SAndroid Build Coastguard Worker const wchar_t* subkey,
466*6777b538SAndroid Build Coastguard Worker DWORD options,
467*6777b538SAndroid Build Coastguard Worker REGSAM access) {
468*6777b538SAndroid Build Coastguard Worker DCHECK(options == 0 || options == REG_OPTION_OPEN_LINK) << options;
469*6777b538SAndroid Build Coastguard Worker DCHECK(rootkey && subkey && access);
470*6777b538SAndroid Build Coastguard Worker HKEY subhkey = nullptr;
471*6777b538SAndroid Build Coastguard Worker
472*6777b538SAndroid Build Coastguard Worker LONG result = RegOpenKeyEx(rootkey, subkey, options, access, &subhkey);
473*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
474*6777b538SAndroid Build Coastguard Worker Close();
475*6777b538SAndroid Build Coastguard Worker key_ = subhkey;
476*6777b538SAndroid Build Coastguard Worker wow64access_ = access & kWow64AccessMask;
477*6777b538SAndroid Build Coastguard Worker }
478*6777b538SAndroid Build Coastguard Worker
479*6777b538SAndroid Build Coastguard Worker return result;
480*6777b538SAndroid Build Coastguard Worker }
481*6777b538SAndroid Build Coastguard Worker
IsLink() const482*6777b538SAndroid Build Coastguard Worker expected<bool, LONG> RegKey::IsLink() const {
483*6777b538SAndroid Build Coastguard Worker DWORD value_type = 0;
484*6777b538SAndroid Build Coastguard Worker LONG result = ::RegQueryValueEx(key_, L"SymbolicLinkValue",
485*6777b538SAndroid Build Coastguard Worker /*lpReserved=*/nullptr, &value_type,
486*6777b538SAndroid Build Coastguard Worker /*lpData=*/nullptr, /*lpcbData=*/nullptr);
487*6777b538SAndroid Build Coastguard Worker if (result == ERROR_FILE_NOT_FOUND) {
488*6777b538SAndroid Build Coastguard Worker return ok(false);
489*6777b538SAndroid Build Coastguard Worker }
490*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
491*6777b538SAndroid Build Coastguard Worker return ok(value_type == REG_LINK);
492*6777b538SAndroid Build Coastguard Worker }
493*6777b538SAndroid Build Coastguard Worker return unexpected(result);
494*6777b538SAndroid Build Coastguard Worker }
495*6777b538SAndroid Build Coastguard Worker
DeleteIfLink()496*6777b538SAndroid Build Coastguard Worker std::optional<LONG> RegKey::DeleteIfLink() {
497*6777b538SAndroid Build Coastguard Worker if (auto is_link = IsLink(); !is_link.has_value()) {
498*6777b538SAndroid Build Coastguard Worker return is_link.error(); // Failed to determine if a link.
499*6777b538SAndroid Build Coastguard Worker } else if (is_link.value() == false) {
500*6777b538SAndroid Build Coastguard Worker return std::nullopt; // Not a link.
501*6777b538SAndroid Build Coastguard Worker }
502*6777b538SAndroid Build Coastguard Worker
503*6777b538SAndroid Build Coastguard Worker const NTSTATUS delete_result = ::NtDeleteKey(key_);
504*6777b538SAndroid Build Coastguard Worker if (delete_result == STATUS_SUCCESS) {
505*6777b538SAndroid Build Coastguard Worker return ERROR_SUCCESS;
506*6777b538SAndroid Build Coastguard Worker }
507*6777b538SAndroid Build Coastguard Worker using RtlNtStatusToDosErrorFunction = ULONG(WINAPI*)(NTSTATUS);
508*6777b538SAndroid Build Coastguard Worker static const RtlNtStatusToDosErrorFunction rtl_nt_status_to_dos_error =
509*6777b538SAndroid Build Coastguard Worker reinterpret_cast<RtlNtStatusToDosErrorFunction>(::GetProcAddress(
510*6777b538SAndroid Build Coastguard Worker ::GetModuleHandle(L"ntdll.dll"), "RtlNtStatusToDosError"));
511*6777b538SAndroid Build Coastguard Worker // The most common cause of failure is the presence of subkeys, which is
512*6777b538SAndroid Build Coastguard Worker // reported as `STATUS_CANNOT_DELETE` and maps to `ERROR_ACCESS_DENIED`.
513*6777b538SAndroid Build Coastguard Worker return rtl_nt_status_to_dos_error
514*6777b538SAndroid Build Coastguard Worker ? static_cast<LONG>(rtl_nt_status_to_dos_error(delete_result))
515*6777b538SAndroid Build Coastguard Worker : ERROR_ACCESS_DENIED;
516*6777b538SAndroid Build Coastguard Worker }
517*6777b538SAndroid Build Coastguard Worker
518*6777b538SAndroid Build Coastguard Worker // static
RegDelRecurse(HKEY root_key,const wchar_t * name,REGSAM access)519*6777b538SAndroid Build Coastguard Worker LONG RegKey::RegDelRecurse(HKEY root_key, const wchar_t* name, REGSAM access) {
520*6777b538SAndroid Build Coastguard Worker // First, open the key; taking care not to traverse symbolic links.
521*6777b538SAndroid Build Coastguard Worker RegKey target_key;
522*6777b538SAndroid Build Coastguard Worker LONG result = target_key.Open(
523*6777b538SAndroid Build Coastguard Worker root_key, name, REG_OPTION_OPEN_LINK,
524*6777b538SAndroid Build Coastguard Worker access | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | DELETE);
525*6777b538SAndroid Build Coastguard Worker if (result == ERROR_FILE_NOT_FOUND) { // The key doesn't exist.
526*6777b538SAndroid Build Coastguard Worker return ERROR_SUCCESS;
527*6777b538SAndroid Build Coastguard Worker }
528*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
529*6777b538SAndroid Build Coastguard Worker return result;
530*6777b538SAndroid Build Coastguard Worker }
531*6777b538SAndroid Build Coastguard Worker
532*6777b538SAndroid Build Coastguard Worker // Next, try to delete the key if it is a symbolic link.
533*6777b538SAndroid Build Coastguard Worker if (auto deleted_link = target_key.DeleteIfLink(); deleted_link.has_value()) {
534*6777b538SAndroid Build Coastguard Worker return deleted_link.value();
535*6777b538SAndroid Build Coastguard Worker }
536*6777b538SAndroid Build Coastguard Worker
537*6777b538SAndroid Build Coastguard Worker // It's not a symbolic link, so try to delete it without recursing.
538*6777b538SAndroid Build Coastguard Worker result = ::RegDeleteKeyEx(target_key.key_, L"", access, 0);
539*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
540*6777b538SAndroid Build Coastguard Worker return result;
541*6777b538SAndroid Build Coastguard Worker }
542*6777b538SAndroid Build Coastguard Worker
543*6777b538SAndroid Build Coastguard Worker // Enumerate the keys.
544*6777b538SAndroid Build Coastguard Worker const DWORD kMaxKeyNameLength = 256; // Includes string terminator.
545*6777b538SAndroid Build Coastguard Worker auto subkey_buffer = std::make_unique<wchar_t[]>(kMaxKeyNameLength);
546*6777b538SAndroid Build Coastguard Worker while (true) {
547*6777b538SAndroid Build Coastguard Worker DWORD key_size = kMaxKeyNameLength;
548*6777b538SAndroid Build Coastguard Worker if (::RegEnumKeyEx(target_key.key_, 0, &subkey_buffer[0], &key_size,
549*6777b538SAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS) {
550*6777b538SAndroid Build Coastguard Worker break;
551*6777b538SAndroid Build Coastguard Worker }
552*6777b538SAndroid Build Coastguard Worker CHECK_LT(key_size, kMaxKeyNameLength);
553*6777b538SAndroid Build Coastguard Worker CHECK_EQ(subkey_buffer[key_size], L'\0');
554*6777b538SAndroid Build Coastguard Worker if (RegDelRecurse(target_key.key_, &subkey_buffer[0], access) !=
555*6777b538SAndroid Build Coastguard Worker ERROR_SUCCESS) {
556*6777b538SAndroid Build Coastguard Worker break;
557*6777b538SAndroid Build Coastguard Worker }
558*6777b538SAndroid Build Coastguard Worker }
559*6777b538SAndroid Build Coastguard Worker
560*6777b538SAndroid Build Coastguard Worker // Try again to delete the key.
561*6777b538SAndroid Build Coastguard Worker return ::RegDeleteKeyEx(target_key.key_, L"", access, 0);
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker
564*6777b538SAndroid Build Coastguard Worker // RegistryValueIterator ------------------------------------------------------
565*6777b538SAndroid Build Coastguard Worker
RegistryValueIterator(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)566*6777b538SAndroid Build Coastguard Worker RegistryValueIterator::RegistryValueIterator(HKEY root_key,
567*6777b538SAndroid Build Coastguard Worker const wchar_t* folder_key,
568*6777b538SAndroid Build Coastguard Worker REGSAM wow64access)
569*6777b538SAndroid Build Coastguard Worker : name_(MAX_PATH, '\0'), value_(MAX_PATH, '\0') {
570*6777b538SAndroid Build Coastguard Worker Initialize(root_key, folder_key, wow64access);
571*6777b538SAndroid Build Coastguard Worker }
572*6777b538SAndroid Build Coastguard Worker
RegistryValueIterator(HKEY root_key,const wchar_t * folder_key)573*6777b538SAndroid Build Coastguard Worker RegistryValueIterator::RegistryValueIterator(HKEY root_key,
574*6777b538SAndroid Build Coastguard Worker const wchar_t* folder_key)
575*6777b538SAndroid Build Coastguard Worker : name_(MAX_PATH, '\0'), value_(MAX_PATH, '\0') {
576*6777b538SAndroid Build Coastguard Worker Initialize(root_key, folder_key, 0);
577*6777b538SAndroid Build Coastguard Worker }
578*6777b538SAndroid Build Coastguard Worker
Initialize(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)579*6777b538SAndroid Build Coastguard Worker void RegistryValueIterator::Initialize(HKEY root_key,
580*6777b538SAndroid Build Coastguard Worker const wchar_t* folder_key,
581*6777b538SAndroid Build Coastguard Worker REGSAM wow64access) {
582*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
583*6777b538SAndroid Build Coastguard Worker LONG result =
584*6777b538SAndroid Build Coastguard Worker RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
585*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
586*6777b538SAndroid Build Coastguard Worker key_ = nullptr;
587*6777b538SAndroid Build Coastguard Worker } else {
588*6777b538SAndroid Build Coastguard Worker DWORD count = 0;
589*6777b538SAndroid Build Coastguard Worker result =
590*6777b538SAndroid Build Coastguard Worker ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
591*6777b538SAndroid Build Coastguard Worker nullptr, &count, nullptr, nullptr, nullptr, nullptr);
592*6777b538SAndroid Build Coastguard Worker
593*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
594*6777b538SAndroid Build Coastguard Worker ::RegCloseKey(key_);
595*6777b538SAndroid Build Coastguard Worker key_ = nullptr;
596*6777b538SAndroid Build Coastguard Worker } else {
597*6777b538SAndroid Build Coastguard Worker index_ = count - 1;
598*6777b538SAndroid Build Coastguard Worker }
599*6777b538SAndroid Build Coastguard Worker }
600*6777b538SAndroid Build Coastguard Worker
601*6777b538SAndroid Build Coastguard Worker Read();
602*6777b538SAndroid Build Coastguard Worker }
603*6777b538SAndroid Build Coastguard Worker
~RegistryValueIterator()604*6777b538SAndroid Build Coastguard Worker RegistryValueIterator::~RegistryValueIterator() {
605*6777b538SAndroid Build Coastguard Worker if (key_)
606*6777b538SAndroid Build Coastguard Worker ::RegCloseKey(key_);
607*6777b538SAndroid Build Coastguard Worker }
608*6777b538SAndroid Build Coastguard Worker
ValueCount() const609*6777b538SAndroid Build Coastguard Worker DWORD RegistryValueIterator::ValueCount() const {
610*6777b538SAndroid Build Coastguard Worker DWORD count = 0;
611*6777b538SAndroid Build Coastguard Worker LONG result =
612*6777b538SAndroid Build Coastguard Worker ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
613*6777b538SAndroid Build Coastguard Worker nullptr, &count, nullptr, nullptr, nullptr, nullptr);
614*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS)
615*6777b538SAndroid Build Coastguard Worker return 0;
616*6777b538SAndroid Build Coastguard Worker
617*6777b538SAndroid Build Coastguard Worker return count;
618*6777b538SAndroid Build Coastguard Worker }
619*6777b538SAndroid Build Coastguard Worker
Valid() const620*6777b538SAndroid Build Coastguard Worker bool RegistryValueIterator::Valid() const {
621*6777b538SAndroid Build Coastguard Worker return key_ != nullptr && index_ != kInvalidIterValue;
622*6777b538SAndroid Build Coastguard Worker }
623*6777b538SAndroid Build Coastguard Worker
operator ++()624*6777b538SAndroid Build Coastguard Worker void RegistryValueIterator::operator++() {
625*6777b538SAndroid Build Coastguard Worker if (index_ != kInvalidIterValue)
626*6777b538SAndroid Build Coastguard Worker --index_;
627*6777b538SAndroid Build Coastguard Worker Read();
628*6777b538SAndroid Build Coastguard Worker }
629*6777b538SAndroid Build Coastguard Worker
Read()630*6777b538SAndroid Build Coastguard Worker bool RegistryValueIterator::Read() {
631*6777b538SAndroid Build Coastguard Worker if (Valid()) {
632*6777b538SAndroid Build Coastguard Worker DWORD capacity = static_cast<DWORD>(name_.capacity());
633*6777b538SAndroid Build Coastguard Worker DWORD name_size = capacity;
634*6777b538SAndroid Build Coastguard Worker // |value_size_| is in bytes. Reserve the last character for a NUL.
635*6777b538SAndroid Build Coastguard Worker value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
636*6777b538SAndroid Build Coastguard Worker LONG result = ::RegEnumValue(
637*6777b538SAndroid Build Coastguard Worker key_, index_, WriteInto(&name_, name_size), &name_size, nullptr, &type_,
638*6777b538SAndroid Build Coastguard Worker reinterpret_cast<BYTE*>(value_.data()), &value_size_);
639*6777b538SAndroid Build Coastguard Worker
640*6777b538SAndroid Build Coastguard Worker if (result == ERROR_MORE_DATA) {
641*6777b538SAndroid Build Coastguard Worker // Registry key names are limited to 255 characters and fit within
642*6777b538SAndroid Build Coastguard Worker // MAX_PATH (which is 260) but registry value names can use up to 16,383
643*6777b538SAndroid Build Coastguard Worker // characters and the value itself is not limited
644*6777b538SAndroid Build Coastguard Worker // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
645*6777b538SAndroid Build Coastguard Worker // ms724872(v=vs.85).aspx).
646*6777b538SAndroid Build Coastguard Worker // Resize the buffers and retry if their size caused the failure.
647*6777b538SAndroid Build Coastguard Worker DWORD value_size_in_wchars = to_wchar_size(value_size_);
648*6777b538SAndroid Build Coastguard Worker if (value_size_in_wchars + 1 > value_.size())
649*6777b538SAndroid Build Coastguard Worker value_.resize(value_size_in_wchars + 1, '\0');
650*6777b538SAndroid Build Coastguard Worker value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
651*6777b538SAndroid Build Coastguard Worker name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
652*6777b538SAndroid Build Coastguard Worker result = ::RegEnumValue(
653*6777b538SAndroid Build Coastguard Worker key_, index_, WriteInto(&name_, name_size), &name_size, nullptr,
654*6777b538SAndroid Build Coastguard Worker &type_, reinterpret_cast<BYTE*>(value_.data()), &value_size_);
655*6777b538SAndroid Build Coastguard Worker }
656*6777b538SAndroid Build Coastguard Worker
657*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS) {
658*6777b538SAndroid Build Coastguard Worker DCHECK_LT(to_wchar_size(value_size_), value_.size());
659*6777b538SAndroid Build Coastguard Worker value_[to_wchar_size(value_size_)] = '\0';
660*6777b538SAndroid Build Coastguard Worker return true;
661*6777b538SAndroid Build Coastguard Worker }
662*6777b538SAndroid Build Coastguard Worker }
663*6777b538SAndroid Build Coastguard Worker
664*6777b538SAndroid Build Coastguard Worker name_[0] = '\0';
665*6777b538SAndroid Build Coastguard Worker value_[0] = '\0';
666*6777b538SAndroid Build Coastguard Worker value_size_ = 0;
667*6777b538SAndroid Build Coastguard Worker return false;
668*6777b538SAndroid Build Coastguard Worker }
669*6777b538SAndroid Build Coastguard Worker
670*6777b538SAndroid Build Coastguard Worker // RegistryKeyIterator --------------------------------------------------------
671*6777b538SAndroid Build Coastguard Worker
RegistryKeyIterator(HKEY root_key,const wchar_t * folder_key)672*6777b538SAndroid Build Coastguard Worker RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
673*6777b538SAndroid Build Coastguard Worker const wchar_t* folder_key) {
674*6777b538SAndroid Build Coastguard Worker Initialize(root_key, folder_key, 0);
675*6777b538SAndroid Build Coastguard Worker }
676*6777b538SAndroid Build Coastguard Worker
RegistryKeyIterator(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)677*6777b538SAndroid Build Coastguard Worker RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
678*6777b538SAndroid Build Coastguard Worker const wchar_t* folder_key,
679*6777b538SAndroid Build Coastguard Worker REGSAM wow64access) {
680*6777b538SAndroid Build Coastguard Worker Initialize(root_key, folder_key, wow64access);
681*6777b538SAndroid Build Coastguard Worker }
682*6777b538SAndroid Build Coastguard Worker
~RegistryKeyIterator()683*6777b538SAndroid Build Coastguard Worker RegistryKeyIterator::~RegistryKeyIterator() {
684*6777b538SAndroid Build Coastguard Worker if (key_)
685*6777b538SAndroid Build Coastguard Worker ::RegCloseKey(key_);
686*6777b538SAndroid Build Coastguard Worker }
687*6777b538SAndroid Build Coastguard Worker
SubkeyCount() const688*6777b538SAndroid Build Coastguard Worker DWORD RegistryKeyIterator::SubkeyCount() const {
689*6777b538SAndroid Build Coastguard Worker DWORD count = 0;
690*6777b538SAndroid Build Coastguard Worker LONG result =
691*6777b538SAndroid Build Coastguard Worker ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, &count, nullptr,
692*6777b538SAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
693*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS)
694*6777b538SAndroid Build Coastguard Worker return 0;
695*6777b538SAndroid Build Coastguard Worker
696*6777b538SAndroid Build Coastguard Worker return count;
697*6777b538SAndroid Build Coastguard Worker }
698*6777b538SAndroid Build Coastguard Worker
Valid() const699*6777b538SAndroid Build Coastguard Worker bool RegistryKeyIterator::Valid() const {
700*6777b538SAndroid Build Coastguard Worker return key_ != nullptr && index_ != kInvalidIterValue;
701*6777b538SAndroid Build Coastguard Worker }
702*6777b538SAndroid Build Coastguard Worker
operator ++()703*6777b538SAndroid Build Coastguard Worker void RegistryKeyIterator::operator++() {
704*6777b538SAndroid Build Coastguard Worker if (index_ != kInvalidIterValue)
705*6777b538SAndroid Build Coastguard Worker --index_;
706*6777b538SAndroid Build Coastguard Worker Read();
707*6777b538SAndroid Build Coastguard Worker }
708*6777b538SAndroid Build Coastguard Worker
Read()709*6777b538SAndroid Build Coastguard Worker bool RegistryKeyIterator::Read() {
710*6777b538SAndroid Build Coastguard Worker if (Valid()) {
711*6777b538SAndroid Build Coastguard Worker DWORD ncount = static_cast<DWORD>(std::size(name_));
712*6777b538SAndroid Build Coastguard Worker FILETIME written;
713*6777b538SAndroid Build Coastguard Worker LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, nullptr, nullptr,
714*6777b538SAndroid Build Coastguard Worker nullptr, &written);
715*6777b538SAndroid Build Coastguard Worker if (ERROR_SUCCESS == r)
716*6777b538SAndroid Build Coastguard Worker return true;
717*6777b538SAndroid Build Coastguard Worker }
718*6777b538SAndroid Build Coastguard Worker
719*6777b538SAndroid Build Coastguard Worker name_[0] = '\0';
720*6777b538SAndroid Build Coastguard Worker return false;
721*6777b538SAndroid Build Coastguard Worker }
722*6777b538SAndroid Build Coastguard Worker
Initialize(HKEY root_key,const wchar_t * folder_key,REGSAM wow64access)723*6777b538SAndroid Build Coastguard Worker void RegistryKeyIterator::Initialize(HKEY root_key,
724*6777b538SAndroid Build Coastguard Worker const wchar_t* folder_key,
725*6777b538SAndroid Build Coastguard Worker REGSAM wow64access) {
726*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
727*6777b538SAndroid Build Coastguard Worker LONG result =
728*6777b538SAndroid Build Coastguard Worker RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
729*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
730*6777b538SAndroid Build Coastguard Worker key_ = nullptr;
731*6777b538SAndroid Build Coastguard Worker } else {
732*6777b538SAndroid Build Coastguard Worker DWORD count = 0;
733*6777b538SAndroid Build Coastguard Worker result =
734*6777b538SAndroid Build Coastguard Worker ::RegQueryInfoKey(key_, nullptr, nullptr, nullptr, &count, nullptr,
735*6777b538SAndroid Build Coastguard Worker nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
736*6777b538SAndroid Build Coastguard Worker
737*6777b538SAndroid Build Coastguard Worker if (result != ERROR_SUCCESS) {
738*6777b538SAndroid Build Coastguard Worker ::RegCloseKey(key_);
739*6777b538SAndroid Build Coastguard Worker key_ = nullptr;
740*6777b538SAndroid Build Coastguard Worker } else {
741*6777b538SAndroid Build Coastguard Worker index_ = count - 1;
742*6777b538SAndroid Build Coastguard Worker }
743*6777b538SAndroid Build Coastguard Worker }
744*6777b538SAndroid Build Coastguard Worker
745*6777b538SAndroid Build Coastguard Worker Read();
746*6777b538SAndroid Build Coastguard Worker }
747*6777b538SAndroid Build Coastguard Worker
748*6777b538SAndroid Build Coastguard Worker } // namespace base::win
749