Home | History | Annotate | Download | only in base
      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 
     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 
     44 RegistryValueIterator::~RegistryValueIterator() {
     45   if (key_)
     46     ::RegCloseKey(key_);
     47 }
     48 
     49 bool RegistryValueIterator::Valid() const {
     50   // true while the iterator is valid
     51   return key_ != NULL && index_ >= 0;
     52 }
     53 
     54 void RegistryValueIterator::operator++() {
     55   // advance to the next entry in the folder
     56   --index_;
     57   Read();
     58 }
     59 
     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 
     76 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 
     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 
    113 RegistryKeyIterator::~RegistryKeyIterator() {
    114   if (key_)
    115     ::RegCloseKey(key_);
    116 }
    117 
    118 bool RegistryKeyIterator::Valid() const {
    119   // true while the iterator is valid
    120   return key_ != NULL && index_ >= 0;
    121 }
    122 
    123 void RegistryKeyIterator::operator++() {
    124   // advance to the next entry in the folder
    125   --index_;
    126   Read();
    127 }
    128 
    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 
    143 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 
    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 
    171 void RegKey::Close() {
    172   StopWatching();
    173   if (key_) {
    174     ::RegCloseKey(key_);
    175     key_ = NULL;
    176   }
    177 }
    178 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    346 bool RegKey::DeleteKey(const tchar * name) {
    347   if (!key_) return false;
    348   return (ERROR_SUCCESS == SHDeleteKey(key_, name));
    349 }
    350 
    351 
    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 
    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 
    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 
    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.
    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 
    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 
    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