Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2003 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 // Registry configuration wrapers class implementation
     12 //
     13 // Change made by S. Ganesh - ganesh (at) google.com:
     14 //   Use SHQueryValueEx instead of RegQueryValueEx throughout.
     15 //   A call to the SHLWAPI function is essentially a call to the standard
     16 //   function but with post-processing:
     17 //   * to fix REG_SZ or REG_EXPAND_SZ data that is not properly null-terminated;
     18 //   * to expand REG_EXPAND_SZ data.
     19 
     20 #include "webrtc/base/win32regkey.h"
     21 
     22 #include <shlwapi.h>
     23 
     24 #include "webrtc/base/common.h"
     25 #include "webrtc/base/logging.h"
     26 #include "webrtc/base/scoped_ptr.h"
     27 
     28 namespace rtc {
     29 
     30 RegKey::RegKey() {
     31   h_key_ = NULL;
     32 }
     33 
     34 RegKey::~RegKey() {
     35   Close();
     36 }
     37 
     38 HRESULT RegKey::Create(HKEY parent_key, const wchar_t* key_name) {
     39   return Create(parent_key,
     40                 key_name,
     41                 REG_NONE,
     42                 REG_OPTION_NON_VOLATILE,
     43                 KEY_ALL_ACCESS,
     44                 NULL,
     45                 NULL);
     46 }
     47 
     48 HRESULT RegKey::Open(HKEY parent_key, const wchar_t* key_name) {
     49   return Open(parent_key, key_name, KEY_ALL_ACCESS);
     50 }
     51 
     52 bool RegKey::HasValue(const TCHAR* value_name) const {
     53   return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_, value_name, NULL,
     54                                              NULL, NULL, NULL));
     55 }
     56 
     57 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
     58                          const wchar_t* value_name,
     59                          DWORD value) {
     60   ASSERT(full_key_name != NULL);
     61 
     62   return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);
     63 }
     64 
     65 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
     66                          const wchar_t* value_name,
     67                          DWORD64 value) {
     68   ASSERT(full_key_name != NULL);
     69 
     70   return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);
     71 }
     72 
     73 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
     74                          const wchar_t* value_name,
     75                          float value) {
     76   ASSERT(full_key_name != NULL);
     77 
     78   return SetValueStaticHelper(full_key_name, value_name,
     79                               REG_BINARY, &value, sizeof(value));
     80 }
     81 
     82 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
     83                          const wchar_t* value_name,
     84                          double value) {
     85   ASSERT(full_key_name != NULL);
     86 
     87   return SetValueStaticHelper(full_key_name, value_name,
     88                               REG_BINARY, &value, sizeof(value));
     89 }
     90 
     91 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
     92                          const wchar_t* value_name,
     93                          const TCHAR* value) {
     94   ASSERT(full_key_name != NULL);
     95   ASSERT(value != NULL);
     96 
     97   return SetValueStaticHelper(full_key_name, value_name,
     98                               REG_SZ, const_cast<wchar_t*>(value));
     99 }
    100 
    101 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
    102                          const wchar_t* value_name,
    103                          const uint8_t* value,
    104                          DWORD byte_count) {
    105   ASSERT(full_key_name != NULL);
    106 
    107   return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,
    108                               const_cast<uint8_t*>(value), byte_count);
    109 }
    110 
    111 HRESULT RegKey::SetValueMultiSZ(const wchar_t* full_key_name,
    112                                 const wchar_t* value_name,
    113                                 const uint8_t* value,
    114                                 DWORD byte_count) {
    115   ASSERT(full_key_name != NULL);
    116 
    117   return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,
    118                               const_cast<uint8_t*>(value), byte_count);
    119 }
    120 
    121 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    122                          const wchar_t* value_name,
    123                          DWORD* value) {
    124   ASSERT(full_key_name != NULL);
    125   ASSERT(value != NULL);
    126 
    127   return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);
    128 }
    129 
    130 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    131                          const wchar_t* value_name,
    132                          DWORD64* value) {
    133   ASSERT(full_key_name != NULL);
    134   ASSERT(value != NULL);
    135 
    136   return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);
    137 }
    138 
    139 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    140                          const wchar_t* value_name,
    141                          float* value) {
    142   ASSERT(value != NULL);
    143   ASSERT(full_key_name != NULL);
    144 
    145   DWORD byte_count = 0;
    146   scoped_ptr<byte[]> buffer;
    147   HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
    148                                     REG_BINARY, buffer.accept(), &byte_count);
    149   if (SUCCEEDED(hr)) {
    150     ASSERT(byte_count == sizeof(*value));
    151     if (byte_count == sizeof(*value)) {
    152       *value = *reinterpret_cast<float*>(buffer.get());
    153     }
    154   }
    155   return hr;
    156 }
    157 
    158 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    159                          const wchar_t* value_name,
    160                          double* value) {
    161   ASSERT(value != NULL);
    162   ASSERT(full_key_name != NULL);
    163 
    164   DWORD byte_count = 0;
    165   scoped_ptr<byte[]> buffer;
    166   HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
    167                                     REG_BINARY, buffer.accept(), &byte_count);
    168   if (SUCCEEDED(hr)) {
    169     ASSERT(byte_count == sizeof(*value));
    170     if (byte_count == sizeof(*value)) {
    171       *value = *reinterpret_cast<double*>(buffer.get());
    172     }
    173   }
    174   return hr;
    175 }
    176 
    177 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    178                          const wchar_t* value_name,
    179                          wchar_t** value) {
    180   ASSERT(full_key_name != NULL);
    181   ASSERT(value != NULL);
    182 
    183   return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);
    184 }
    185 
    186 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    187                          const wchar_t* value_name,
    188                          std::wstring* value) {
    189   ASSERT(full_key_name != NULL);
    190   ASSERT(value != NULL);
    191 
    192   scoped_ptr<wchar_t[]> buffer;
    193   HRESULT hr = RegKey::GetValue(full_key_name, value_name, buffer.accept());
    194   if (SUCCEEDED(hr)) {
    195     value->assign(buffer.get());
    196   }
    197   return hr;
    198 }
    199 
    200 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    201                          const wchar_t* value_name,
    202                          std::vector<std::wstring>* value) {
    203   ASSERT(full_key_name != NULL);
    204   ASSERT(value != NULL);
    205 
    206   return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);
    207 }
    208 
    209 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
    210                          const wchar_t* value_name,
    211                          uint8_t** value,
    212                          DWORD* byte_count) {
    213   ASSERT(full_key_name != NULL);
    214   ASSERT(value != NULL);
    215   ASSERT(byte_count != NULL);
    216 
    217   return GetValueStaticHelper(full_key_name, value_name,
    218                               REG_BINARY, value, byte_count);
    219 }
    220 
    221 HRESULT RegKey::DeleteSubKey(const wchar_t* key_name) {
    222   ASSERT(key_name != NULL);
    223   ASSERT(h_key_ != NULL);
    224 
    225   LONG res = ::RegDeleteKey(h_key_, key_name);
    226   HRESULT hr = HRESULT_FROM_WIN32(res);
    227   if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
    228       hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
    229     hr = S_FALSE;
    230   }
    231   return hr;
    232 }
    233 
    234 HRESULT RegKey::DeleteValue(const wchar_t* value_name) {
    235   ASSERT(h_key_ != NULL);
    236 
    237   LONG res = ::RegDeleteValue(h_key_, value_name);
    238   HRESULT hr = HRESULT_FROM_WIN32(res);
    239   if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
    240       hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
    241     hr = S_FALSE;
    242   }
    243   return hr;
    244 }
    245 
    246 HRESULT RegKey::Close() {
    247   HRESULT hr = S_OK;
    248   if (h_key_ != NULL) {
    249     LONG res = ::RegCloseKey(h_key_);
    250     hr = HRESULT_FROM_WIN32(res);
    251     h_key_ = NULL;
    252   }
    253   return hr;
    254 }
    255 
    256 HRESULT RegKey::Create(HKEY parent_key,
    257                        const wchar_t* key_name,
    258                        wchar_t* lpszClass,
    259                        DWORD options,
    260                        REGSAM sam_desired,
    261                        LPSECURITY_ATTRIBUTES lpSecAttr,
    262                        LPDWORD lpdwDisposition) {
    263   ASSERT(key_name != NULL);
    264   ASSERT(parent_key != NULL);
    265 
    266   DWORD dw = 0;
    267   HKEY h_key = NULL;
    268   LONG res = ::RegCreateKeyEx(parent_key, key_name, 0, lpszClass, options,
    269                               sam_desired, lpSecAttr, &h_key, &dw);
    270   HRESULT hr = HRESULT_FROM_WIN32(res);
    271 
    272   if (lpdwDisposition) {
    273     *lpdwDisposition = dw;
    274   }
    275 
    276   // we have to close the currently opened key
    277   // before replacing it with the new one
    278   if (hr == S_OK) {
    279     hr = Close();
    280     ASSERT(hr == S_OK);
    281     h_key_ = h_key;
    282   }
    283   return hr;
    284 }
    285 
    286 HRESULT RegKey::Open(HKEY parent_key,
    287                      const wchar_t* key_name,
    288                      REGSAM sam_desired) {
    289   ASSERT(key_name != NULL);
    290   ASSERT(parent_key != NULL);
    291 
    292   HKEY h_key = NULL;
    293   LONG res = ::RegOpenKeyEx(parent_key, key_name, 0, sam_desired, &h_key);
    294   HRESULT hr = HRESULT_FROM_WIN32(res);
    295 
    296   // we have to close the currently opened key
    297   // before replacing it with the new one
    298   if (hr == S_OK) {
    299     // close the currently opened key if any
    300     hr = Close();
    301     ASSERT(hr == S_OK);
    302     h_key_ = h_key;
    303   }
    304   return hr;
    305 }
    306 
    307 // save the key and all of its subkeys and values to a file
    308 HRESULT RegKey::Save(const wchar_t* full_key_name, const wchar_t* file_name) {
    309   ASSERT(full_key_name != NULL);
    310   ASSERT(file_name != NULL);
    311 
    312   std::wstring key_name(full_key_name);
    313   HKEY h_key = GetRootKeyInfo(&key_name);
    314   if (!h_key) {
    315     return E_FAIL;
    316   }
    317 
    318   RegKey key;
    319   HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
    320   if (FAILED(hr)) {
    321     return hr;
    322   }
    323 
    324   AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, true);
    325   LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);
    326   AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, false);
    327 
    328   return HRESULT_FROM_WIN32(res);
    329 }
    330 
    331 // restore the key and all of its subkeys and values which are saved into a file
    332 HRESULT RegKey::Restore(const wchar_t* full_key_name,
    333                         const wchar_t* file_name) {
    334   ASSERT(full_key_name != NULL);
    335   ASSERT(file_name != NULL);
    336 
    337   std::wstring key_name(full_key_name);
    338   HKEY h_key = GetRootKeyInfo(&key_name);
    339   if (!h_key) {
    340     return E_FAIL;
    341   }
    342 
    343   RegKey key;
    344   HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_WRITE);
    345   if (FAILED(hr)) {
    346     return hr;
    347   }
    348 
    349   AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, true);
    350   LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);
    351   AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, false);
    352 
    353   return HRESULT_FROM_WIN32(res);
    354 }
    355 
    356 // check if the current key has the specified subkey
    357 bool RegKey::HasSubkey(const wchar_t* key_name) const {
    358   ASSERT(key_name != NULL);
    359 
    360   RegKey key;
    361   HRESULT hr = key.Open(h_key_, key_name, KEY_READ);
    362   key.Close();
    363   return hr == S_OK;
    364 }
    365 
    366 // static flush key
    367 HRESULT RegKey::FlushKey(const wchar_t* full_key_name) {
    368   ASSERT(full_key_name != NULL);
    369 
    370   HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    371   // get the root HKEY
    372   std::wstring key_name(full_key_name);
    373   HKEY h_key = GetRootKeyInfo(&key_name);
    374 
    375   if (h_key != NULL) {
    376     LONG res = ::RegFlushKey(h_key);
    377     hr = HRESULT_FROM_WIN32(res);
    378   }
    379   return hr;
    380 }
    381 
    382 // static SET helper
    383 HRESULT RegKey::SetValueStaticHelper(const wchar_t* full_key_name,
    384                                      const wchar_t* value_name,
    385                                      DWORD type,
    386                                      LPVOID value,
    387                                      DWORD byte_count) {
    388   ASSERT(full_key_name != NULL);
    389 
    390   HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    391   // get the root HKEY
    392   std::wstring key_name(full_key_name);
    393   HKEY h_key = GetRootKeyInfo(&key_name);
    394 
    395   if (h_key != NULL) {
    396     RegKey key;
    397     hr = key.Create(h_key, key_name.c_str());
    398     if (hr == S_OK) {
    399       switch (type) {
    400         case REG_DWORD:
    401           hr = key.SetValue(value_name, *(static_cast<DWORD*>(value)));
    402           break;
    403         case REG_QWORD:
    404           hr = key.SetValue(value_name, *(static_cast<DWORD64*>(value)));
    405           break;
    406         case REG_SZ:
    407           hr = key.SetValue(value_name, static_cast<const wchar_t*>(value));
    408           break;
    409         case REG_BINARY:
    410           hr = key.SetValue(value_name, static_cast<const uint8_t*>(value),
    411                             byte_count);
    412           break;
    413         case REG_MULTI_SZ:
    414           hr = key.SetValue(value_name, static_cast<const uint8_t*>(value),
    415                             byte_count, type);
    416           break;
    417         default:
    418           ASSERT(false);
    419           hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
    420           break;
    421       }
    422       // close the key after writing
    423       HRESULT temp_hr = key.Close();
    424       if (hr == S_OK) {
    425         hr = temp_hr;
    426       }
    427     }
    428   }
    429   return hr;
    430 }
    431 
    432 // static GET helper
    433 HRESULT RegKey::GetValueStaticHelper(const wchar_t* full_key_name,
    434                                      const wchar_t* value_name,
    435                                      DWORD type,
    436                                      LPVOID value,
    437                                      DWORD* byte_count) {
    438   ASSERT(full_key_name != NULL);
    439 
    440   HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    441   // get the root HKEY
    442   std::wstring key_name(full_key_name);
    443   HKEY h_key = GetRootKeyInfo(&key_name);
    444 
    445   if (h_key != NULL) {
    446     RegKey key;
    447     hr = key.Open(h_key, key_name.c_str(), KEY_READ);
    448     if (hr == S_OK) {
    449       switch (type) {
    450         case REG_DWORD:
    451           hr = key.GetValue(value_name, reinterpret_cast<DWORD*>(value));
    452           break;
    453         case REG_QWORD:
    454           hr = key.GetValue(value_name, reinterpret_cast<DWORD64*>(value));
    455           break;
    456         case REG_SZ:
    457           hr = key.GetValue(value_name, reinterpret_cast<wchar_t**>(value));
    458           break;
    459         case REG_MULTI_SZ:
    460           hr = key.GetValue(value_name, reinterpret_cast<
    461                                             std::vector<std::wstring>*>(value));
    462           break;
    463         case REG_BINARY:
    464           hr = key.GetValue(value_name, reinterpret_cast<uint8_t**>(value),
    465                             byte_count);
    466           break;
    467         default:
    468           ASSERT(false);
    469           hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
    470           break;
    471       }
    472       // close the key after writing
    473       HRESULT temp_hr = key.Close();
    474       if (hr == S_OK) {
    475         hr = temp_hr;
    476       }
    477     }
    478   }
    479   return hr;
    480 }
    481 
    482 // GET helper
    483 HRESULT RegKey::GetValueHelper(const wchar_t* value_name,
    484                                DWORD* type,
    485                                uint8_t** value,
    486                                DWORD* byte_count) const {
    487   ASSERT(byte_count != NULL);
    488   ASSERT(value != NULL);
    489   ASSERT(type != NULL);
    490 
    491   // init return buffer
    492   *value = NULL;
    493 
    494   // get the size of the return data buffer
    495   LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count);
    496   HRESULT hr = HRESULT_FROM_WIN32(res);
    497 
    498   if (hr == S_OK) {
    499     // if the value length is 0, nothing to do
    500     if (*byte_count != 0) {
    501       // allocate the buffer
    502       *value = new byte[*byte_count];
    503       ASSERT(*value != NULL);
    504 
    505       // make the call again to get the data
    506       res = ::SHQueryValueEx(h_key_, value_name, NULL,
    507                              type, *value, byte_count);
    508       hr = HRESULT_FROM_WIN32(res);
    509       ASSERT(hr == S_OK);
    510     }
    511   }
    512   return hr;
    513 }
    514 
    515 // Int32 Get
    516 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD* value) const {
    517   ASSERT(value != NULL);
    518 
    519   DWORD type = 0;
    520   DWORD byte_count = sizeof(DWORD);
    521   LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
    522                               value, &byte_count);
    523   HRESULT hr = HRESULT_FROM_WIN32(res);
    524   ASSERT((hr != S_OK) || (type == REG_DWORD));
    525   ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD)));
    526   return hr;
    527 }
    528 
    529 // Int64 Get
    530 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD64* value) const {
    531   ASSERT(value != NULL);
    532 
    533   DWORD type = 0;
    534   DWORD byte_count = sizeof(DWORD64);
    535   LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
    536                               value, &byte_count);
    537   HRESULT hr = HRESULT_FROM_WIN32(res);
    538   ASSERT((hr != S_OK) || (type == REG_QWORD));
    539   ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD64)));
    540   return hr;
    541 }
    542 
    543 // String Get
    544 HRESULT RegKey::GetValue(const wchar_t* value_name, wchar_t** value) const {
    545   ASSERT(value != NULL);
    546 
    547   DWORD byte_count = 0;
    548   DWORD type = 0;
    549 
    550   // first get the size of the string buffer
    551   LONG res = ::SHQueryValueEx(h_key_, value_name, NULL,
    552                               &type, NULL, &byte_count);
    553   HRESULT hr = HRESULT_FROM_WIN32(res);
    554 
    555   if (hr == S_OK) {
    556     // allocate room for the string and a terminating \0
    557     *value = new wchar_t[(byte_count / sizeof(wchar_t)) + 1];
    558 
    559     if ((*value) != NULL) {
    560       if (byte_count != 0) {
    561         // make the call again
    562         res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
    563                                *value, &byte_count);
    564         hr = HRESULT_FROM_WIN32(res);
    565       } else {
    566         (*value)[0] = L'\0';
    567       }
    568 
    569       ASSERT((hr != S_OK) || (type == REG_SZ) ||
    570              (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
    571     } else {
    572       hr = E_OUTOFMEMORY;
    573     }
    574   }
    575 
    576   return hr;
    577 }
    578 
    579 // get a string value
    580 HRESULT RegKey::GetValue(const wchar_t* value_name, std::wstring* value) const {
    581   ASSERT(value != NULL);
    582 
    583   DWORD byte_count = 0;
    584   DWORD type = 0;
    585 
    586   // first get the size of the string buffer
    587   LONG res = ::SHQueryValueEx(h_key_, value_name, NULL,
    588                               &type, NULL, &byte_count);
    589   HRESULT hr = HRESULT_FROM_WIN32(res);
    590 
    591   if (hr == S_OK) {
    592     if (byte_count != 0) {
    593       // Allocate some memory and make the call again
    594       value->resize(byte_count / sizeof(wchar_t) + 1);
    595       res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
    596                              &value->at(0), &byte_count);
    597       hr = HRESULT_FROM_WIN32(res);
    598       value->resize(wcslen(value->data()));
    599     } else {
    600       value->clear();
    601     }
    602 
    603     ASSERT((hr != S_OK) || (type == REG_SZ) ||
    604            (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
    605   }
    606 
    607   return hr;
    608 }
    609 
    610 // convert REG_MULTI_SZ bytes to string array
    611 HRESULT RegKey::MultiSZBytesToStringArray(const uint8_t* buffer,
    612                                           DWORD byte_count,
    613                                           std::vector<std::wstring>* value) {
    614   ASSERT(buffer != NULL);
    615   ASSERT(value != NULL);
    616 
    617   const wchar_t* data = reinterpret_cast<const wchar_t*>(buffer);
    618   DWORD data_len = byte_count / sizeof(wchar_t);
    619   value->clear();
    620   if (data_len > 1) {
    621     // must be terminated by two null characters
    622     if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {
    623       return E_INVALIDARG;
    624     }
    625 
    626     // put null-terminated strings into arrays
    627     while (*data) {
    628       std::wstring str(data);
    629       value->push_back(str);
    630       data += str.length() + 1;
    631     }
    632   }
    633   return S_OK;
    634 }
    635 
    636 // get a std::vector<std::wstring> value from REG_MULTI_SZ type
    637 HRESULT RegKey::GetValue(const wchar_t* value_name,
    638                          std::vector<std::wstring>* value) const {
    639   ASSERT(value != NULL);
    640 
    641   DWORD byte_count = 0;
    642   DWORD type = 0;
    643   uint8_t* buffer = 0;
    644 
    645   // first get the size of the buffer
    646   HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count);
    647   ASSERT((hr != S_OK) || (type == REG_MULTI_SZ));
    648 
    649   if (SUCCEEDED(hr)) {
    650     hr = MultiSZBytesToStringArray(buffer, byte_count, value);
    651   }
    652 
    653   return hr;
    654 }
    655 
    656 // Binary data Get
    657 HRESULT RegKey::GetValue(const wchar_t* value_name,
    658                          uint8_t** value,
    659                          DWORD* byte_count) const {
    660   ASSERT(byte_count != NULL);
    661   ASSERT(value != NULL);
    662 
    663   DWORD type = 0;
    664   HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);
    665   ASSERT((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));
    666   return hr;
    667 }
    668 
    669 // Raw data get
    670 HRESULT RegKey::GetValue(const wchar_t* value_name,
    671                          uint8_t** value,
    672                          DWORD* byte_count,
    673                          DWORD* type) const {
    674   ASSERT(type != NULL);
    675   ASSERT(byte_count != NULL);
    676   ASSERT(value != NULL);
    677 
    678   return GetValueHelper(value_name, type, value, byte_count);
    679 }
    680 
    681 // Int32 set
    682 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD value) const {
    683   ASSERT(h_key_ != NULL);
    684 
    685   LONG res =
    686       ::RegSetValueEx(h_key_, value_name, NULL, REG_DWORD,
    687                       reinterpret_cast<const uint8_t*>(&value), sizeof(DWORD));
    688   return HRESULT_FROM_WIN32(res);
    689 }
    690 
    691 // Int64 set
    692 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD64 value) const {
    693   ASSERT(h_key_ != NULL);
    694 
    695   LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_QWORD,
    696                              reinterpret_cast<const uint8_t*>(&value),
    697                              sizeof(DWORD64));
    698   return HRESULT_FROM_WIN32(res);
    699 }
    700 
    701 // String set
    702 HRESULT RegKey::SetValue(const wchar_t* value_name,
    703                          const wchar_t* value) const {
    704   ASSERT(value != NULL);
    705   ASSERT(h_key_ != NULL);
    706 
    707   LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_SZ,
    708                              reinterpret_cast<const uint8_t*>(value),
    709                              (lstrlen(value) + 1) * sizeof(wchar_t));
    710   return HRESULT_FROM_WIN32(res);
    711 }
    712 
    713 // Binary data set
    714 HRESULT RegKey::SetValue(const wchar_t* value_name,
    715                          const uint8_t* value,
    716                          DWORD byte_count) const {
    717   ASSERT(h_key_ != NULL);
    718 
    719   // special case - if 'value' is NULL make sure byte_count is zero
    720   if (value == NULL) {
    721     byte_count = 0;
    722   }
    723 
    724   LONG res = ::RegSetValueEx(h_key_, value_name, NULL,
    725                              REG_BINARY, value, byte_count);
    726   return HRESULT_FROM_WIN32(res);
    727 }
    728 
    729 // Raw data set
    730 HRESULT RegKey::SetValue(const wchar_t* value_name,
    731                          const uint8_t* value,
    732                          DWORD byte_count,
    733                          DWORD type) const {
    734   ASSERT(value != NULL);
    735   ASSERT(h_key_ != NULL);
    736 
    737   LONG res = ::RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);
    738   return HRESULT_FROM_WIN32(res);
    739 }
    740 
    741 bool RegKey::HasKey(const wchar_t* full_key_name) {
    742   ASSERT(full_key_name != NULL);
    743 
    744   // get the root HKEY
    745   std::wstring key_name(full_key_name);
    746   HKEY h_key = GetRootKeyInfo(&key_name);
    747 
    748   if (h_key != NULL) {
    749     RegKey key;
    750     HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
    751     key.Close();
    752     return S_OK == hr;
    753   }
    754   return false;
    755 }
    756 
    757 // static version of HasValue
    758 bool RegKey::HasValue(const wchar_t* full_key_name, const wchar_t* value_name) {
    759   ASSERT(full_key_name != NULL);
    760 
    761   bool has_value = false;
    762   // get the root HKEY
    763   std::wstring key_name(full_key_name);
    764   HKEY h_key = GetRootKeyInfo(&key_name);
    765 
    766   if (h_key != NULL) {
    767     RegKey key;
    768     if (key.Open(h_key, key_name.c_str(), KEY_READ) == S_OK) {
    769       has_value = key.HasValue(value_name);
    770       key.Close();
    771     }
    772   }
    773   return has_value;
    774 }
    775 
    776 HRESULT RegKey::GetValueType(const wchar_t* full_key_name,
    777                              const wchar_t* value_name,
    778                              DWORD* value_type) {
    779   ASSERT(full_key_name != NULL);
    780   ASSERT(value_type != NULL);
    781 
    782   *value_type = REG_NONE;
    783 
    784   std::wstring key_name(full_key_name);
    785   HKEY h_key = GetRootKeyInfo(&key_name);
    786 
    787   RegKey key;
    788   HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
    789   if (SUCCEEDED(hr)) {
    790     LONG res = ::SHQueryValueEx(key.h_key_, value_name, NULL, value_type,
    791                                 NULL, NULL);
    792     if (res != ERROR_SUCCESS) {
    793       hr = HRESULT_FROM_WIN32(res);
    794     }
    795   }
    796 
    797   return hr;
    798 }
    799 
    800 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name) {
    801   ASSERT(full_key_name != NULL);
    802 
    803   return DeleteKey(full_key_name, true);
    804 }
    805 
    806 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name, bool recursively) {
    807   ASSERT(full_key_name != NULL);
    808 
    809   // need to open the parent key first
    810   // get the root HKEY
    811   std::wstring key_name(full_key_name);
    812   HKEY h_key = GetRootKeyInfo(&key_name);
    813 
    814   // get the parent key
    815   std::wstring parent_key(GetParentKeyInfo(&key_name));
    816 
    817   RegKey key;
    818   HRESULT hr = key.Open(h_key, parent_key.c_str());
    819 
    820   if (hr == S_OK) {
    821     hr = recursively ? key.RecurseDeleteSubKey(key_name.c_str())
    822                      : key.DeleteSubKey(key_name.c_str());
    823   } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
    824              hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
    825     hr = S_FALSE;
    826   }
    827 
    828   key.Close();
    829   return hr;
    830 }
    831 
    832 HRESULT RegKey::DeleteValue(const wchar_t* full_key_name,
    833                             const wchar_t* value_name) {
    834   ASSERT(full_key_name != NULL);
    835 
    836   HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
    837   // get the root HKEY
    838   std::wstring key_name(full_key_name);
    839   HKEY h_key = GetRootKeyInfo(&key_name);
    840 
    841   if (h_key != NULL) {
    842     RegKey key;
    843     hr = key.Open(h_key, key_name.c_str());
    844     if (hr == S_OK) {
    845       hr = key.DeleteValue(value_name);
    846       key.Close();
    847     }
    848   }
    849   return hr;
    850 }
    851 
    852 HRESULT RegKey::RecurseDeleteSubKey(const wchar_t* key_name) {
    853   ASSERT(key_name != NULL);
    854 
    855   RegKey key;
    856   HRESULT hr = key.Open(h_key_, key_name);
    857 
    858   if (hr == S_OK) {
    859     // enumerate all subkeys of this key and recursivelly delete them
    860     FILETIME time = {0};
    861     wchar_t key_name_buf[kMaxKeyNameChars] = {0};
    862     DWORD key_name_buf_size = kMaxKeyNameChars;
    863     while (hr == S_OK &&
    864         ::RegEnumKeyEx(key.h_key_, 0, key_name_buf, &key_name_buf_size,
    865                        NULL, NULL, NULL,  &time) == ERROR_SUCCESS) {
    866       hr = key.RecurseDeleteSubKey(key_name_buf);
    867 
    868       // restore the buffer size
    869       key_name_buf_size = kMaxKeyNameChars;
    870     }
    871     // close the top key
    872     key.Close();
    873   }
    874 
    875   if (hr == S_OK) {
    876     // the key has no more children keys
    877     // delete the key and all of its values
    878     hr = DeleteSubKey(key_name);
    879   }
    880 
    881   return hr;
    882 }
    883 
    884 HKEY RegKey::GetRootKeyInfo(std::wstring* full_key_name) {
    885   ASSERT(full_key_name != NULL);
    886 
    887   HKEY h_key = NULL;
    888   // get the root HKEY
    889   size_t index = full_key_name->find(L'\\');
    890   std::wstring root_key;
    891 
    892   if (index == -1) {
    893     root_key = *full_key_name;
    894     *full_key_name = L"";
    895   } else {
    896     root_key = full_key_name->substr(0, index);
    897     *full_key_name = full_key_name->substr(index + 1,
    898                                            full_key_name->length() - index - 1);
    899   }
    900 
    901   for (std::wstring::iterator iter = root_key.begin();
    902        iter != root_key.end(); ++iter) {
    903     *iter = toupper(*iter);
    904   }
    905 
    906   if (!root_key.compare(L"HKLM") ||
    907       !root_key.compare(L"HKEY_LOCAL_MACHINE")) {
    908     h_key = HKEY_LOCAL_MACHINE;
    909   } else if (!root_key.compare(L"HKCU") ||
    910              !root_key.compare(L"HKEY_CURRENT_USER")) {
    911     h_key = HKEY_CURRENT_USER;
    912   } else if (!root_key.compare(L"HKU") ||
    913              !root_key.compare(L"HKEY_USERS")) {
    914     h_key = HKEY_USERS;
    915   } else if (!root_key.compare(L"HKCR") ||
    916              !root_key.compare(L"HKEY_CLASSES_ROOT")) {
    917     h_key = HKEY_CLASSES_ROOT;
    918   }
    919 
    920   return h_key;
    921 }
    922 
    923 
    924 // Returns true if this key name is 'safe' for deletion
    925 // (doesn't specify a key root)
    926 bool RegKey::SafeKeyNameForDeletion(const wchar_t* key_name) {
    927   ASSERT(key_name != NULL);
    928   std::wstring key(key_name);
    929 
    930   HKEY root_key = GetRootKeyInfo(&key);
    931 
    932   if (!root_key) {
    933     key = key_name;
    934   }
    935   if (key.empty()) {
    936     return false;
    937   }
    938   bool found_subkey = false, backslash_found = false;
    939   for (size_t i = 0 ; i < key.length() ; ++i) {
    940     if (key[i] == L'\\') {
    941       backslash_found = true;
    942     } else if (backslash_found) {
    943       found_subkey = true;
    944       break;
    945     }
    946   }
    947   return (root_key == HKEY_USERS) ? found_subkey : true;
    948 }
    949 
    950 std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) {
    951   ASSERT(key_name != NULL);
    952 
    953   // get the parent key
    954   size_t index = key_name->rfind(L'\\');
    955   std::wstring parent_key;
    956   if (index == -1) {
    957     parent_key = L"";
    958   } else {
    959     parent_key = key_name->substr(0, index);
    960     *key_name = key_name->substr(index + 1, key_name->length() - index - 1);
    961   }
    962 
    963   return parent_key;
    964 }
    965 
    966 // get the number of values for this key
    967 uint32_t RegKey::GetValueCount() {
    968   DWORD num_values = 0;
    969 
    970   if (ERROR_SUCCESS != ::RegQueryInfoKey(
    971         h_key_,  // key handle
    972         NULL,  // buffer for class name
    973         NULL,  // size of class string
    974         NULL,  // reserved
    975         NULL,  // number of subkeys
    976         NULL,  // longest subkey size
    977         NULL,  // longest class string
    978         &num_values,  // number of values for this key
    979         NULL,  // longest value name
    980         NULL,  // longest value data
    981         NULL,  // security descriptor
    982         NULL)) {  // last write time
    983     ASSERT(false);
    984   }
    985   return num_values;
    986 }
    987 
    988 // Enumerators for the value_names for this key
    989 
    990 // Called to get the value name for the given value name index
    991 // Use GetValueCount() to get the total value_name count for this key
    992 // Returns failure if no key at the specified index
    993 HRESULT RegKey::GetValueNameAt(int index, std::wstring* value_name,
    994                                DWORD* type) {
    995   ASSERT(value_name != NULL);
    996 
    997   LONG res = ERROR_SUCCESS;
    998   wchar_t value_name_buf[kMaxValueNameChars] = {0};
    999   DWORD value_name_buf_size = kMaxValueNameChars;
   1000   res = ::RegEnumValue(h_key_, index, value_name_buf, &value_name_buf_size,
   1001                        NULL, type, NULL, NULL);
   1002 
   1003   if (res == ERROR_SUCCESS) {
   1004     value_name->assign(value_name_buf);
   1005   }
   1006 
   1007   return HRESULT_FROM_WIN32(res);
   1008 }
   1009 
   1010 uint32_t RegKey::GetSubkeyCount() {
   1011   // number of values for key
   1012   DWORD num_subkeys = 0;
   1013 
   1014   if (ERROR_SUCCESS != ::RegQueryInfoKey(
   1015           h_key_,  // key handle
   1016           NULL,  // buffer for class name
   1017           NULL,  // size of class string
   1018           NULL,  // reserved
   1019           &num_subkeys,  // number of subkeys
   1020           NULL,  // longest subkey size
   1021           NULL,  // longest class string
   1022           NULL,  // number of values for this key
   1023           NULL,  // longest value name
   1024           NULL,  // longest value data
   1025           NULL,  // security descriptor
   1026           NULL)) { // last write time
   1027     ASSERT(false);
   1028   }
   1029   return num_subkeys;
   1030 }
   1031 
   1032 HRESULT RegKey::GetSubkeyNameAt(int index, std::wstring* key_name) {
   1033   ASSERT(key_name != NULL);
   1034 
   1035   LONG res = ERROR_SUCCESS;
   1036   wchar_t key_name_buf[kMaxKeyNameChars] = {0};
   1037   DWORD key_name_buf_size = kMaxKeyNameChars;
   1038 
   1039   res = ::RegEnumKeyEx(h_key_, index, key_name_buf, &key_name_buf_size,
   1040                        NULL, NULL, NULL, NULL);
   1041 
   1042   if (res == ERROR_SUCCESS) {
   1043     key_name->assign(key_name_buf);
   1044   }
   1045 
   1046   return HRESULT_FROM_WIN32(res);
   1047 }
   1048 
   1049 // Is the key empty: having no sub-keys and values
   1050 bool RegKey::IsKeyEmpty(const wchar_t* full_key_name) {
   1051   ASSERT(full_key_name != NULL);
   1052 
   1053   bool is_empty = true;
   1054 
   1055   // Get the root HKEY
   1056   std::wstring key_name(full_key_name);
   1057   HKEY h_key = GetRootKeyInfo(&key_name);
   1058 
   1059   // Open the key to check
   1060   if (h_key != NULL) {
   1061     RegKey key;
   1062     HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
   1063     if (SUCCEEDED(hr)) {
   1064       is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0;
   1065       key.Close();
   1066     }
   1067   }
   1068 
   1069   return is_empty;
   1070 }
   1071 
   1072 bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable) {
   1073   ASSERT(privilege != NULL);
   1074 
   1075   bool ret = false;
   1076   HANDLE token;
   1077   if (::OpenProcessToken(::GetCurrentProcess(),
   1078                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
   1079     LUID luid;
   1080     memset(&luid, 0, sizeof(luid));
   1081     if (::LookupPrivilegeValue(NULL, privilege, &luid)) {
   1082       TOKEN_PRIVILEGES privs;
   1083       privs.PrivilegeCount = 1;
   1084       privs.Privileges[0].Luid = luid;
   1085       privs.Privileges[0].Attributes = to_enable ? SE_PRIVILEGE_ENABLED : 0;
   1086       if (::AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, 0)) {
   1087         ret = true;
   1088       } else {
   1089         LOG_GLE(LS_ERROR) << "AdjustTokenPrivileges failed";
   1090       }
   1091     } else {
   1092       LOG_GLE(LS_ERROR) << "LookupPrivilegeValue failed";
   1093     }
   1094     CloseHandle(token);
   1095   } else {
   1096     LOG_GLE(LS_ERROR) << "OpenProcessToken(GetCurrentProcess) failed";
   1097   }
   1098 
   1099   return ret;
   1100 }
   1101 
   1102 }  // namespace rtc
   1103