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