Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 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 #include <algorithm>
      9 
     10 #include "base/logging.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/threading/thread_restrictions.h"
     13 #include "base/win/windows_version.h"
     14 
     15 namespace base {
     16 namespace win {
     17 
     18 namespace {
     19 
     20 // RegEnumValue() reports the number of characters from the name that were
     21 // written to the buffer, not how many there are. This constant is the maximum
     22 // name size, such that a buffer with this size should read any name.
     23 const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
     24 
     25 // Registry values are read as BYTE* but can have wchar_t* data whose last
     26 // wchar_t is truncated. This function converts the reported |byte_size| to
     27 // a size in wchar_t that can store a truncated wchar_t if necessary.
     28 inline DWORD to_wchar_size(DWORD byte_size) {
     29   return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
     30 }
     31 
     32 // Mask to pull WOW64 access flags out of REGSAM access.
     33 const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
     34 
     35 }  // namespace
     36 
     37 // RegKey ----------------------------------------------------------------------
     38 
     39 RegKey::RegKey()
     40     : key_(NULL),
     41       watch_event_(0),
     42       wow64access_(0) {
     43 }
     44 
     45 RegKey::RegKey(HKEY key)
     46     : key_(key),
     47       watch_event_(0),
     48       wow64access_(0) {
     49 }
     50 
     51 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
     52     : key_(NULL),
     53       watch_event_(0),
     54       wow64access_(0) {
     55   if (rootkey) {
     56     if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
     57       Create(rootkey, subkey, access);
     58     else
     59       Open(rootkey, subkey, access);
     60   } else {
     61     DCHECK(!subkey);
     62     wow64access_ = access & kWow64AccessMask;
     63   }
     64 }
     65 
     66 RegKey::~RegKey() {
     67   Close();
     68 }
     69 
     70 LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
     71   DWORD disposition_value;
     72   return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
     73 }
     74 
     75 LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
     76                                    DWORD* disposition, REGSAM access) {
     77   DCHECK(rootkey && subkey && access && disposition);
     78   HKEY subhkey = NULL;
     79   LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
     80                                REG_OPTION_NON_VOLATILE, access, NULL, &subhkey,
     81                                disposition);
     82   if (result == ERROR_SUCCESS) {
     83     Close();
     84     key_ = subhkey;
     85     wow64access_ = access & kWow64AccessMask;
     86   }
     87 
     88   return result;
     89 }
     90 
     91 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
     92   DCHECK(name && access);
     93   // After the application has accessed an alternate registry view using one of
     94   // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
     95   // (create, delete, or open) on child registry keys must explicitly use the
     96   // same flag. Otherwise, there can be unexpected behavior.
     97   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
     98   if ((access & kWow64AccessMask) != wow64access_) {
     99     NOTREACHED();
    100     return ERROR_INVALID_PARAMETER;
    101   }
    102   HKEY subkey = NULL;
    103   LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
    104                                access, NULL, &subkey, NULL);
    105   if (result == ERROR_SUCCESS) {
    106     Close();
    107     key_ = subkey;
    108     wow64access_ = access & kWow64AccessMask;
    109   }
    110 
    111   return result;
    112 }
    113 
    114 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
    115   DCHECK(rootkey && subkey && access);
    116   HKEY subhkey = NULL;
    117 
    118   LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
    119   if (result == ERROR_SUCCESS) {
    120     Close();
    121     key_ = subhkey;
    122     wow64access_ = access & kWow64AccessMask;
    123   }
    124 
    125   return result;
    126 }
    127 
    128 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
    129   DCHECK(relative_key_name && access);
    130   // After the application has accessed an alternate registry view using one of
    131   // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
    132   // (create, delete, or open) on child registry keys must explicitly use the
    133   // same flag. Otherwise, there can be unexpected behavior.
    134   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
    135   if ((access & kWow64AccessMask) != wow64access_) {
    136     NOTREACHED();
    137     return ERROR_INVALID_PARAMETER;
    138   }
    139   HKEY subkey = NULL;
    140   LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
    141 
    142   // We have to close the current opened key before replacing it with the new
    143   // one.
    144   if (result == ERROR_SUCCESS) {
    145     Close();
    146     key_ = subkey;
    147     wow64access_ = access & kWow64AccessMask;
    148   }
    149   return result;
    150 }
    151 
    152 void RegKey::Close() {
    153   StopWatching();
    154   if (key_) {
    155     ::RegCloseKey(key_);
    156     key_ = NULL;
    157     wow64access_ = 0;
    158   }
    159 }
    160 
    161 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
    162 void RegKey::Set(HKEY key) {
    163   if (key_ != key) {
    164     Close();
    165     key_ = key;
    166   }
    167 }
    168 
    169 HKEY RegKey::Take() {
    170   DCHECK(wow64access_ == 0);
    171   StopWatching();
    172   HKEY key = key_;
    173   key_ = NULL;
    174   return key;
    175 }
    176 
    177 bool RegKey::HasValue(const wchar_t* name) const {
    178   return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
    179 }
    180 
    181 DWORD RegKey::GetValueCount() const {
    182   DWORD count = 0;
    183   LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
    184                                 NULL, NULL, NULL, NULL);
    185   return (result == ERROR_SUCCESS) ? count : 0;
    186 }
    187 
    188 LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
    189   wchar_t buf[256];
    190   DWORD bufsize = arraysize(buf);
    191   LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
    192   if (r == ERROR_SUCCESS)
    193     *name = buf;
    194 
    195   return r;
    196 }
    197 
    198 LONG RegKey::DeleteKey(const wchar_t* name) {
    199   DCHECK(key_);
    200   DCHECK(name);
    201   HKEY subkey = NULL;
    202 
    203   // Verify the key exists before attempting delete to replicate previous
    204   // behavior.
    205   LONG result =
    206       RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
    207   if (result != ERROR_SUCCESS)
    208     return result;
    209   RegCloseKey(subkey);
    210 
    211   return RegDelRecurse(key_, std::wstring(name), wow64access_);
    212 }
    213 
    214 LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
    215   DCHECK(key_);
    216   DCHECK(name);
    217 
    218   HKEY target_key = NULL;
    219   LONG result = RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_,
    220                              &target_key);
    221 
    222   if (result != ERROR_SUCCESS)
    223     return result;
    224 
    225   DWORD count = 0;
    226   result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
    227                            NULL, NULL, NULL, NULL);
    228 
    229   RegCloseKey(target_key);
    230 
    231   if (result != ERROR_SUCCESS)
    232     return result;
    233 
    234   if (count == 0)
    235     return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
    236 
    237   return ERROR_DIR_NOT_EMPTY;
    238 }
    239 
    240 LONG RegKey::DeleteValue(const wchar_t* value_name) {
    241   DCHECK(key_);
    242   LONG result = RegDeleteValue(key_, value_name);
    243   return result;
    244 }
    245 
    246 LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
    247   DCHECK(out_value);
    248   DWORD type = REG_DWORD;
    249   DWORD size = sizeof(DWORD);
    250   DWORD local_value = 0;
    251   LONG result = ReadValue(name, &local_value, &size, &type);
    252   if (result == ERROR_SUCCESS) {
    253     if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
    254       *out_value = local_value;
    255     else
    256       result = ERROR_CANTREAD;
    257   }
    258 
    259   return result;
    260 }
    261 
    262 LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
    263   DCHECK(out_value);
    264   DWORD type = REG_QWORD;
    265   int64 local_value = 0;
    266   DWORD size = sizeof(local_value);
    267   LONG result = ReadValue(name, &local_value, &size, &type);
    268   if (result == ERROR_SUCCESS) {
    269     if ((type == REG_QWORD || type == REG_BINARY) &&
    270         size == sizeof(local_value))
    271       *out_value = local_value;
    272     else
    273       result = ERROR_CANTREAD;
    274   }
    275 
    276   return result;
    277 }
    278 
    279 LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
    280   DCHECK(out_value);
    281   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   wchar_t raw_value[kMaxStringLength];
    284   DWORD type = REG_SZ, size = sizeof(raw_value);
    285   LONG result = ReadValue(name, raw_value, &size, &type);
    286   if (result == ERROR_SUCCESS) {
    287     if (type == REG_SZ) {
    288       *out_value = raw_value;
    289     } else if (type == REG_EXPAND_SZ) {
    290       wchar_t expanded[kMaxStringLength];
    291       size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
    292       // Success: returns the number of wchar_t's copied
    293       // Fail: buffer too small, returns the size required
    294       // Fail: other, returns 0
    295       if (size == 0 || size > kMaxStringLength) {
    296         result = ERROR_MORE_DATA;
    297       } else {
    298         *out_value = expanded;
    299       }
    300     } else {
    301       // Not a string. Oops.
    302       result = ERROR_CANTREAD;
    303     }
    304   }
    305 
    306   return result;
    307 }
    308 
    309 LONG RegKey::ReadValue(const wchar_t* name,
    310                        void* data,
    311                        DWORD* dsize,
    312                        DWORD* dtype) const {
    313   LONG result = RegQueryValueEx(key_, name, 0, dtype,
    314                                 reinterpret_cast<LPBYTE>(data), dsize);
    315   return result;
    316 }
    317 
    318 LONG RegKey::ReadValues(const wchar_t* name,
    319                         std::vector<std::wstring>* values) {
    320   values->clear();
    321 
    322   DWORD type = REG_MULTI_SZ;
    323   DWORD size = 0;
    324   LONG result = ReadValue(name, NULL, &size, &type);
    325   if (FAILED(result) || size == 0)
    326     return result;
    327 
    328   if (type != REG_MULTI_SZ)
    329     return ERROR_CANTREAD;
    330 
    331   std::vector<wchar_t> buffer(size / sizeof(wchar_t));
    332   result = ReadValue(name, &buffer[0], &size, NULL);
    333   if (FAILED(result) || size == 0)
    334     return result;
    335 
    336   // Parse the double-null-terminated list of strings.
    337   // Note: This code is paranoid to not read outside of |buf|, in the case where
    338   // it may not be properly terminated.
    339   const wchar_t* entry = &buffer[0];
    340   const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
    341   while (entry < buffer_end && entry[0] != '\0') {
    342     const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
    343     values->push_back(std::wstring(entry, entry_end));
    344     entry = entry_end + 1;
    345   }
    346   return 0;
    347 }
    348 
    349 LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
    350   return WriteValue(
    351       name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
    352 }
    353 
    354 LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
    355   return WriteValue(name, in_value,
    356       static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
    357 }
    358 
    359 LONG RegKey::WriteValue(const wchar_t* name,
    360                         const void* data,
    361                         DWORD dsize,
    362                         DWORD dtype) {
    363   DCHECK(data || !dsize);
    364 
    365   LONG result = RegSetValueEx(key_, name, 0, dtype,
    366       reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
    367   return result;
    368 }
    369 
    370 LONG RegKey::StartWatching() {
    371   DCHECK(key_);
    372   if (!watch_event_)
    373     watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
    374 
    375   DWORD filter = REG_NOTIFY_CHANGE_NAME |
    376                  REG_NOTIFY_CHANGE_ATTRIBUTES |
    377                  REG_NOTIFY_CHANGE_LAST_SET |
    378                  REG_NOTIFY_CHANGE_SECURITY;
    379 
    380   // Watch the registry key for a change of value.
    381   LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
    382   if (result != ERROR_SUCCESS) {
    383     CloseHandle(watch_event_);
    384     watch_event_ = 0;
    385   }
    386 
    387   return result;
    388 }
    389 
    390 bool RegKey::HasChanged() {
    391   if (watch_event_) {
    392     if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
    393       StartWatching();
    394       return true;
    395     }
    396   }
    397   return false;
    398 }
    399 
    400 LONG RegKey::StopWatching() {
    401   LONG result = ERROR_INVALID_HANDLE;
    402   if (watch_event_) {
    403     CloseHandle(watch_event_);
    404     watch_event_ = 0;
    405     result = ERROR_SUCCESS;
    406   }
    407   return result;
    408 }
    409 
    410 // static
    411 LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
    412                                    const wchar_t* lpSubKey,
    413                                    REGSAM samDesired,
    414                                    DWORD Reserved) {
    415   typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
    416 
    417   RegDeleteKeyExPtr reg_delete_key_ex_func =
    418       reinterpret_cast<RegDeleteKeyExPtr>(
    419           GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
    420 
    421   if (reg_delete_key_ex_func)
    422     return reg_delete_key_ex_func(hKey, lpSubKey, samDesired, Reserved);
    423 
    424   // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
    425   return RegDeleteKey(hKey, lpSubKey);
    426 }
    427 
    428 // static
    429 LONG RegKey::RegDelRecurse(HKEY root_key,
    430                            const std::wstring& name,
    431                            REGSAM access) {
    432   // First, see if the key can be deleted without having to recurse.
    433   LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
    434   if (result == ERROR_SUCCESS)
    435     return result;
    436 
    437   HKEY target_key = NULL;
    438   result = RegOpenKeyEx(
    439       root_key, name.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key);
    440 
    441   if (result == ERROR_FILE_NOT_FOUND)
    442     return ERROR_SUCCESS;
    443   if (result != ERROR_SUCCESS)
    444     return result;
    445 
    446   std::wstring subkey_name(name);
    447 
    448   // Check for an ending slash and add one if it is missing.
    449   if (!name.empty() && subkey_name[name.length() - 1] != L'\\')
    450     subkey_name += L"\\";
    451 
    452   // Enumerate the keys
    453   result = ERROR_SUCCESS;
    454   const DWORD kMaxKeyNameLength = MAX_PATH;
    455   const size_t base_key_length = subkey_name.length();
    456   std::wstring key_name;
    457   while (result == ERROR_SUCCESS) {
    458     DWORD key_size = kMaxKeyNameLength;
    459     result = RegEnumKeyEx(target_key,
    460                           0,
    461                           WriteInto(&key_name, kMaxKeyNameLength),
    462                           &key_size,
    463                           NULL,
    464                           NULL,
    465                           NULL,
    466                           NULL);
    467 
    468     if (result != ERROR_SUCCESS)
    469       break;
    470 
    471     key_name.resize(key_size);
    472     subkey_name.resize(base_key_length);
    473     subkey_name += key_name;
    474 
    475     if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
    476       break;
    477   }
    478 
    479   RegCloseKey(target_key);
    480 
    481   // Try again to delete the key.
    482   result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
    483 
    484   return result;
    485 }
    486 
    487 // RegistryValueIterator ------------------------------------------------------
    488 
    489 RegistryValueIterator::RegistryValueIterator(HKEY root_key,
    490                                              const wchar_t* folder_key)
    491     : name_(MAX_PATH, L'\0'),
    492       value_(MAX_PATH, L'\0') {
    493   LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
    494   if (result != ERROR_SUCCESS) {
    495     key_ = NULL;
    496   } else {
    497     DWORD count = 0;
    498     result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
    499                                NULL, NULL, NULL, NULL);
    500 
    501     if (result != ERROR_SUCCESS) {
    502       ::RegCloseKey(key_);
    503       key_ = NULL;
    504     } else {
    505       index_ = count - 1;
    506     }
    507   }
    508 
    509   Read();
    510 }
    511 
    512 RegistryValueIterator::~RegistryValueIterator() {
    513   if (key_)
    514     ::RegCloseKey(key_);
    515 }
    516 
    517 DWORD RegistryValueIterator::ValueCount() const {
    518   DWORD count = 0;
    519   LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
    520                                   &count, NULL, NULL, NULL, NULL);
    521   if (result != ERROR_SUCCESS)
    522     return 0;
    523 
    524   return count;
    525 }
    526 
    527 bool RegistryValueIterator::Valid() const {
    528   return key_ != NULL && index_ >= 0;
    529 }
    530 
    531 void RegistryValueIterator::operator++() {
    532   --index_;
    533   Read();
    534 }
    535 
    536 bool RegistryValueIterator::Read() {
    537   if (Valid()) {
    538     DWORD capacity = static_cast<DWORD>(name_.capacity());
    539     DWORD name_size = capacity;
    540     // |value_size_| is in bytes. Reserve the last character for a NUL.
    541     value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
    542     LONG result = ::RegEnumValue(
    543         key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
    544         reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
    545 
    546     if (result == ERROR_MORE_DATA) {
    547       // Registry key names are limited to 255 characters and fit within
    548       // MAX_PATH (which is 260) but registry value names can use up to 16,383
    549       // characters and the value itself is not limited
    550       // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
    551       // ms724872(v=vs.85).aspx).
    552       // Resize the buffers and retry if their size caused the failure.
    553       DWORD value_size_in_wchars = to_wchar_size(value_size_);
    554       if (value_size_in_wchars + 1 > value_.size())
    555         value_.resize(value_size_in_wchars + 1, L'\0');
    556       value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
    557       name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
    558       result = ::RegEnumValue(
    559           key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
    560           reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
    561     }
    562 
    563     if (result == ERROR_SUCCESS) {
    564       DCHECK_LT(to_wchar_size(value_size_), value_.size());
    565       value_[to_wchar_size(value_size_)] = L'\0';
    566       return true;
    567     }
    568   }
    569 
    570   name_[0] = L'\0';
    571   value_[0] = L'\0';
    572   value_size_ = 0;
    573   return false;
    574 }
    575 
    576 // RegistryKeyIterator --------------------------------------------------------
    577 
    578 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
    579                                          const wchar_t* folder_key) {
    580   LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
    581   if (result != ERROR_SUCCESS) {
    582     key_ = NULL;
    583   } else {
    584     DWORD count = 0;
    585     LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
    586                                     NULL, NULL, NULL, NULL, NULL);
    587 
    588     if (result != ERROR_SUCCESS) {
    589       ::RegCloseKey(key_);
    590       key_ = NULL;
    591     } else {
    592       index_ = count - 1;
    593     }
    594   }
    595 
    596   Read();
    597 }
    598 
    599 RegistryKeyIterator::~RegistryKeyIterator() {
    600   if (key_)
    601     ::RegCloseKey(key_);
    602 }
    603 
    604 DWORD RegistryKeyIterator::SubkeyCount() const {
    605   DWORD count = 0;
    606   LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
    607                                   NULL, NULL, NULL, NULL, NULL);
    608   if (result != ERROR_SUCCESS)
    609     return 0;
    610 
    611   return count;
    612 }
    613 
    614 bool RegistryKeyIterator::Valid() const {
    615   return key_ != NULL && index_ >= 0;
    616 }
    617 
    618 void RegistryKeyIterator::operator++() {
    619   --index_;
    620   Read();
    621 }
    622 
    623 bool RegistryKeyIterator::Read() {
    624   if (Valid()) {
    625     DWORD ncount = arraysize(name_);
    626     FILETIME written;
    627     LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
    628                             NULL, &written);
    629     if (ERROR_SUCCESS == r)
    630       return true;
    631   }
    632 
    633   name_[0] = '\0';
    634   return false;
    635 }
    636 
    637 }  // namespace win
    638 }  // namespace base
    639