blob: 8e2e5e822c9a48429c3a930cf09f9929ca467939 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004// All Rights Reserved.
5
6#include <assert.h>
7#include <shlwapi.h>
8#include <windows.h>
9
10#include "base/registry.h"
11
12#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
13
14// local types (see the same declarations in the header file)
15#define tchar TCHAR
16#define CTP const tchar*
17#define tstr std::basic_string<tchar>
18
19//
20// RegistryValueIterator
21//
22
23
24RegistryValueIterator::RegistryValueIterator(HKEY root_key,
25 LPCTSTR folder_key) {
26 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
27 if (result != ERROR_SUCCESS) {
28 key_ = NULL;
29 } else {
30 DWORD count = 0;
31 result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
32 NULL, NULL, NULL, NULL);
33
34 if (result != ERROR_SUCCESS) {
35 ::RegCloseKey(key_);
36 key_ = NULL;
37 } else {
38 index_ = count - 1;
39 }
40 }
41
42 Read();
43}
44
45RegistryValueIterator::~RegistryValueIterator() {
46 if (key_)
47 ::RegCloseKey(key_);
48}
49
50bool RegistryValueIterator::Valid() const {
51 // true while the iterator is valid
52 return key_ != NULL && index_ >= 0;
53}
54
55
56void RegistryValueIterator::operator ++ () {
57 // advance to the next entry in the folder
58 --index_;
59 Read();
60}
61
62
63bool RegistryValueIterator::Read() {
64 if (Valid()) {
65 DWORD ncount = sizeof(name_)/sizeof(*name_);
66 value_size_ = sizeof(value_);
67 LRESULT r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
68 reinterpret_cast<BYTE*>(value_), &value_size_);
69 if (ERROR_SUCCESS == r)
70 return true;
71 }
72
73 name_[0] = '\0';
74 value_[0] = '\0';
75 value_size_ = 0;
76 return false;
77}
78
79
80DWORD RegistryValueIterator::ValueCount() const {
81
82 DWORD count = 0;
83 HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL);
84
85 if (result != ERROR_SUCCESS)
86 return 0;
87
88 return count;
89}
90
91
92//
93// RegistryKeyIterator
94//
95
96
97RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
98 LPCTSTR folder_key) {
99 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
100 if (result != ERROR_SUCCESS) {
101 key_ = NULL;
102 } else {
103 DWORD count = 0;
104 HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
105 NULL, NULL, NULL, NULL, NULL);
106
107 if (result != ERROR_SUCCESS) {
108 ::RegCloseKey(key_);
109 key_ = NULL;
110 } else {
111 index_ = count - 1;
112 }
113 }
114
115 Read();
116}
117
118RegistryKeyIterator::~RegistryKeyIterator() {
119 if (key_)
120 ::RegCloseKey(key_);
121}
122
123bool RegistryKeyIterator::Valid() const {
124 // true while the iterator is valid
125 return key_ != NULL && index_ >= 0;
126}
127
128
129void RegistryKeyIterator::operator ++ () {
130 // advance to the next entry in the folder
131 --index_;
132 Read();
133}
134
135
136bool RegistryKeyIterator::Read() {
137 if (Valid()) {
138 DWORD ncount = sizeof(name_)/sizeof(*name_);
139 FILETIME written;
140 LRESULT r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
141 NULL, &written);
142 if (ERROR_SUCCESS == r)
143 return true;
144 }
145
146 name_[0] = '\0';
147 return false;
148}
149
150
151DWORD RegistryKeyIterator::SubkeyCount() const {
152
153 DWORD count = 0;
154 HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
155 NULL, NULL, NULL, NULL, NULL);
156
157 if (result != ERROR_SUCCESS)
158 return 0;
159
160 return count;
161}
162
163
164//
165// RegKey
166//
167
168
169
170RegKey::RegKey(HKEY rootkey, const tchar* subkey, REGSAM access)
171 : key_(NULL), watch_event_(0) {
172 if (rootkey) {
173 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
174 this->Create(rootkey, subkey, access);
175 else
176 this->Open(rootkey, subkey, access);
177 }
178 else assert(!subkey);
179}
180
181
182
183void RegKey::Close() {
184 StopWatching();
185 if (key_) {
186 ::RegCloseKey(key_);
187 key_ = NULL;
188 }
189}
190
191
192
193bool RegKey::Create(HKEY rootkey, const tchar* subkey, REGSAM access) {
194 DWORD disposition_value;
195 return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
196}
197
198
199
200bool RegKey::CreateWithDisposition(HKEY rootkey, const tchar* subkey,
201 DWORD* disposition, REGSAM access) {
202 assert(rootkey && subkey && access && disposition);
203 this->Close();
204
205 LONG const result = RegCreateKeyEx(rootkey,
206 subkey,
207 0,
208 NULL,
209 REG_OPTION_NON_VOLATILE,
210 access,
211 NULL,
212 &key_,
213 disposition );
214 if (result != ERROR_SUCCESS) {
215 key_ = NULL;
216 return false;
217 }
218 else return true;
219}
220
221
222
223bool RegKey::Open(HKEY rootkey, const tchar* subkey, REGSAM access) {
224 assert(rootkey && subkey && access);
225 this->Close();
226
227 LONG const result = RegOpenKeyEx(rootkey, subkey, 0,
228 access, &key_ );
229 if (result != ERROR_SUCCESS) {
230 key_ = NULL;
231 return false;
232 }
233 else return true;
234}
235
236
237
238bool RegKey::CreateKey(const tchar* name, REGSAM access) {
239 assert(name && access);
240
241 HKEY subkey = NULL;
242 LONG const result = RegCreateKeyEx(key_, name, 0, NULL,
243 REG_OPTION_NON_VOLATILE,
244 access, NULL, &subkey, NULL);
245 this->Close();
246
247 key_ = subkey;
248 return (result == ERROR_SUCCESS);
249}
250
251
252
253bool RegKey::OpenKey(const tchar* name, REGSAM access) {
254 assert(name && access);
255
256 HKEY subkey = NULL;
257 LONG const result = RegOpenKeyEx(key_, name, 0, access, &subkey);
258
259 this->Close();
260
261 key_ = subkey;
262 return (result == ERROR_SUCCESS);
263}
264
265
266
267
268DWORD RegKey::ValueCount() {
269 DWORD count = 0;
270 HRESULT const result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
271 NULL, &count, NULL, NULL, NULL, NULL);
272 return (result != ERROR_SUCCESS) ? 0 : count;
273}
274
275
276bool RegKey::ReadName(int index, tstr* name) {
277 tchar buf[256];
278 DWORD bufsize = sizeof(buf)/sizeof(*buf);
279 LRESULT r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL,
280 NULL, NULL);
281 if (r != ERROR_SUCCESS)
282 return false;
283 if (name)
284 *name = buf;
285 return true;
286}
287
288
289bool RegKey::ValueExists(const tchar* name) {
290 if (!key_) return false;
291 const HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
292 return (result == ERROR_SUCCESS);
293}
294
295
296
297bool RegKey::ReadValue(const tchar* name, void* data,
298 DWORD* dsize, DWORD* dtype) {
299 if (!key_) return false;
300 HRESULT const result = RegQueryValueEx(key_, name, 0, dtype,
301 reinterpret_cast<LPBYTE>(data),
302 dsize);
303 return (result == ERROR_SUCCESS);
304}
305
306
307
308bool RegKey::ReadValue(const tchar* name, tstr * value) {
309 assert(value);
310 static const size_t kMaxStringLength = 1024; // This is after expansion.
311 // Use the one of the other forms of ReadValue if 1024 is too small for you.
312 TCHAR raw_value[kMaxStringLength];
313 DWORD type = REG_SZ, size = sizeof(raw_value);
314 if (this->ReadValue(name, raw_value, &size, &type)) {
315 if (type == REG_SZ) {
316 *value = raw_value;
317 } else if (type == REG_EXPAND_SZ) {
318 TCHAR expanded[kMaxStringLength];
319 size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
320 // Success: returns the number of TCHARs copied
321 // Fail: buffer too small, returns the size required
322 // Fail: other, returns 0
323 if (size == 0 || size > kMaxStringLength)
324 return false;
325 *value = expanded;
326 } else {
327 // Not a string. Oops.
328 return false;
329 }
330 return true;
331 }
332 else return false;
333}
334
335
336
337bool RegKey::ReadValueDW(const tchar* name, DWORD * value) {
338 assert(value);
339 DWORD type = REG_DWORD, size = sizeof(DWORD), result = 0;
340 if (this->ReadValue(name, &result, &size, &type)
341 && (type == REG_DWORD || type == REG_BINARY)
342 && size == sizeof(DWORD)) {
343 *value = result;
344 return true;
345 }
346 else return false;
347}
348
349
350
351bool RegKey::WriteValue(const tchar* name, const void * data, DWORD dsize, DWORD dtype) {
352 assert(data);
353 if (!key_) return false;
354 HRESULT const result = RegSetValueEx(key_, name, 0,
355 dtype,
356 reinterpret_cast<LPBYTE>(const_cast<void*>(data)),
357 dsize);
358 return (result == ERROR_SUCCESS);
359}
360
361
362
363bool RegKey::WriteValue(const tchar * name, const tchar * value) {
364 return this->WriteValue(name, value,
365 static_cast<DWORD>(sizeof(*value) * (_tcslen(value) + 1)), REG_SZ);
366}
367
368
369bool RegKey::WriteValue(const tchar * name, DWORD value) {
370 return this->WriteValue(name, &value,
371 static_cast<DWORD>(sizeof(value)), REG_DWORD);
372}
373
374
375
376bool RegKey::DeleteKey(const tchar * name) {
377 if (!key_) return false;
378 return (ERROR_SUCCESS == SHDeleteKey(key_, name));
379}
380
381
382bool RegKey::DeleteValue(const tchar * value_name) {
383 assert(value_name);
384 HRESULT const result = RegDeleteValue(key_, value_name);
385 return (result == ERROR_SUCCESS);
386}
387
388bool RegKey::StartWatching() {
389 assert(watch_event_ == 0);
390 watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
391 DWORD filter = REG_NOTIFY_CHANGE_NAME |
392 REG_NOTIFY_CHANGE_ATTRIBUTES |
393 REG_NOTIFY_CHANGE_LAST_SET |
394 REG_NOTIFY_CHANGE_SECURITY;
395
396 // Watch the registry key for a change of value.
397 HRESULT result = RegNotifyChangeKeyValue(key_, TRUE, filter,
398 watch_event_, TRUE);
399 if (SUCCEEDED(result)) {
400 return true;
401 } else {
402 CloseHandle(watch_event_);
403 watch_event_ = 0;
404 return false;
405 }
406}
407
408bool RegKey::StopWatching() {
409 if (watch_event_) {
410 CloseHandle(watch_event_);
411 watch_event_ = 0;
412 return true;
413 }
414 return false;
415}
416
417bool RegKey::HasChanged() {
418 if (watch_event_) {
419 if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
420 // An event only gets signaled once, then it's done, so we have
421 // to set up another event to watch.
422 CloseHandle(watch_event_);
423 watch_event_ = 0;
424 StartWatching();
425 return true;
426 }
427 }
428 return false;
429}
430
431
432// Register a COM object with the most usual properties.
433bool RegisterCOMServer(const tchar* guid, const tchar* name, const tchar* path) {
434 RegKey key(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_WRITE);
435 key.CreateKey(guid, KEY_WRITE);
436 key.WriteValue(NULL, name);
437 key.CreateKey(_T("InprocServer32"), KEY_WRITE);
438 key.WriteValue(NULL, path);
439 key.WriteValue(_T("ThreadingModel"), _T("Apartment"));
440 return true;
441};
442
443bool RegisterCOMServer(const tchar* guid, const tchar* name, HINSTANCE module) {
444 tchar module_path[MAX_PATH];
445 ::GetModuleFileName(module, module_path, MAX_PATH);
446 _tcslwr_s(module_path, MAX_PATH);
447 return RegisterCOMServer(guid, name, module_path);
448}
449
450bool UnregisterCOMServer(const tchar* guid) {
451 RegKey key(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_WRITE);
452 key.DeleteKey(guid);
453 return true;
454}
455
456// LocalWords: RegKey
license.botf003cfe2008-08-24 09:55:55 +0900457