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