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