Newer
Older

tfarina@chromium.org
committed
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

brettw@chromium.org
committed
#include "base/win/registry.h"

maruel@chromium.org
committed

brettw@chromium.org
committed
#include "base/threading/thread_restrictions.h"
#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey

brettw@chromium.org
committed
namespace base {
namespace win {

tfarina@chromium.org
committed
// RegKey ----------------------------------------------------------------------
RegKey::RegKey()
: key_(NULL),
watch_event_(0) {
}
RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
: key_(NULL),
watch_event_(0) {
base::ThreadRestrictions::AssertIOAllowed();
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
RegKey::~RegKey() {
Close();
}
bool RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DWORD disposition_value;
return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}
bool RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(rootkey && subkey && access && disposition);
Close();
LONG result = RegCreateKeyEx(rootkey,
subkey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
access,
NULL,
&key_,
disposition);
if (result != ERROR_SUCCESS) {
key_ = NULL;
return false;
}
bool RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(rootkey && subkey && access);
Close();
LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
return false;
}
bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
access, NULL, &subkey, NULL);
Close();
key_ = subkey;
return (result == ERROR_SUCCESS);
}
bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
base::ThreadRestrictions::AssertIOAllowed();
LONG result = RegOpenKeyEx(key_, name, 0, access, &subkey);
key_ = subkey;
return (result == ERROR_SUCCESS);
}

tfarina@chromium.org
committed
void RegKey::Close() {
base::ThreadRestrictions::AssertIOAllowed();
StopWatching();
if (key_) {
::RegCloseKey(key_);
key_ = NULL;
}
}
DWORD RegKey::ValueCount() const {
base::ThreadRestrictions::AssertIOAllowed();
HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
NULL, &count, NULL, NULL, NULL, NULL);
return (result != ERROR_SUCCESS) ? 0 : count;
}
bool RegKey::ReadName(int index, std::wstring* name) const {
base::ThreadRestrictions::AssertIOAllowed();
wchar_t buf[256];
DWORD bufsize = arraysize(buf);
LRESULT r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL,
NULL, NULL);
if (r != ERROR_SUCCESS)
return false;
if (name)
*name = buf;
return true;
}

tfarina@chromium.org
committed
bool RegKey::DeleteKey(const wchar_t* name) {
base::ThreadRestrictions::AssertIOAllowed();
if (!key_)
return false;
LSTATUS ret = SHDeleteKey(key_, name);
if (ERROR_SUCCESS != ret)
SetLastError(ret);
return ERROR_SUCCESS == ret;
}
bool RegKey::DeleteValue(const wchar_t* value_name) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(value_name);
HRESULT result = RegDeleteValue(key_, value_name);
return (result == ERROR_SUCCESS);
}
bool RegKey::ValueExists(const wchar_t* name) {
base::ThreadRestrictions::AssertIOAllowed();
if (!key_)
return false;
HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
return (result == ERROR_SUCCESS);
}
bool RegKey::ReadValue(const wchar_t* name, void* data,
DWORD* dsize, DWORD* dtype) const {
base::ThreadRestrictions::AssertIOAllowed();
if (!key_)
return false;
HRESULT result = RegQueryValueEx(key_, name, 0, dtype,
reinterpret_cast<LPBYTE>(data), dsize);
return (result == ERROR_SUCCESS);
}
bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(value);
const size_t kMaxStringLength = 1024; // This is after expansion.
// Use the one of the other forms of ReadValue if 1024 is too small for you.
DWORD type = REG_SZ, size = sizeof(raw_value);
if (ReadValue(name, raw_value, &size, &type)) {
if (type == REG_SZ) {
*value = raw_value;
} else if (type == REG_EXPAND_SZ) {
size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
// Success: returns the number of wchar_t's copied
// Fail: buffer too small, returns the size required
// Fail: other, returns 0
if (size == 0 || size > kMaxStringLength)
return false;
*value = expanded;
} else {
// Not a string. Oops.
return false;
}
return true;
}
bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const {
DCHECK(value);
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
DWORD result = 0;
if (ReadValue(name, &result, &size, &type) &&
(type == REG_DWORD || type == REG_BINARY) &&
size == sizeof(DWORD)) {
bool RegKey::WriteValue(const wchar_t* name, const void * data,
DWORD dsize, DWORD dtype) {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(data);
if (!key_)
return false;
HRESULT result = RegSetValueEx(

maruel@chromium.org
committed
key_,
name,
0,
dtype,
reinterpret_cast<LPBYTE>(const_cast<void*>(data)),
dsize);
return (result == ERROR_SUCCESS);
}
bool RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
return WriteValue(name, value,
static_cast<DWORD>(sizeof(*value) * (wcslen(value) + 1)), REG_SZ);
bool RegKey::WriteValue(const wchar_t* name, DWORD value) {
return WriteValue(name, &value,
static_cast<DWORD>(sizeof(value)), REG_DWORD);

jam@chromium.org
committed
if (!watch_event_)
watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD filter = REG_NOTIFY_CHANGE_NAME |
REG_NOTIFY_CHANGE_ATTRIBUTES |
REG_NOTIFY_CHANGE_LAST_SET |
REG_NOTIFY_CHANGE_SECURITY;
// Watch the registry key for a change of value.
HRESULT result = RegNotifyChangeKeyValue(key_, TRUE, filter,
watch_event_, TRUE);
if (SUCCEEDED(result)) {
return true;
} else {
CloseHandle(watch_event_);
watch_event_ = 0;
return false;
}
}

tfarina@chromium.org
committed
bool RegKey::HasChanged() {
if (watch_event_) {
if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
StartWatching();
return true;
}
}
return false;
}
bool RegKey::StopWatching() {
if (watch_event_) {
CloseHandle(watch_event_);
watch_event_ = 0;
return true;
}
return false;
}

tfarina@chromium.org
committed
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
// RegistryValueIterator ------------------------------------------------------
RegistryValueIterator::RegistryValueIterator(HKEY root_key,
const wchar_t* folder_key) {
base::ThreadRestrictions::AssertIOAllowed();
LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
} else {
DWORD count = 0;
result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS) {
::RegCloseKey(key_);
key_ = NULL;
} else {
index_ = count - 1;
}
}
Read();
}
RegistryValueIterator::~RegistryValueIterator() {
base::ThreadRestrictions::AssertIOAllowed();
if (key_)
::RegCloseKey(key_);
}
DWORD RegistryValueIterator::ValueCount() const {
base::ThreadRestrictions::AssertIOAllowed();
DWORD count = 0;
HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
&count, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS)
return 0;
return count;
}
bool RegistryValueIterator::Valid() const {
return key_ != NULL && index_ >= 0;
}
void RegistryValueIterator::operator++() {
--index_;
Read();
}
bool RegistryValueIterator::Read() {
base::ThreadRestrictions::AssertIOAllowed();
if (Valid()) {
DWORD ncount = arraysize(name_);
value_size_ = sizeof(value_);
LRESULT r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
reinterpret_cast<BYTE*>(value_), &value_size_);
if (ERROR_SUCCESS == r)

tfarina@chromium.org
committed
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
}
name_[0] = '\0';
value_[0] = '\0';
value_size_ = 0;
return false;
}
// RegistryKeyIterator --------------------------------------------------------
RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
const wchar_t* folder_key) {
base::ThreadRestrictions::AssertIOAllowed();
LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
} else {
DWORD count = 0;
HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS) {
::RegCloseKey(key_);
key_ = NULL;
} else {
index_ = count - 1;

tfarina@chromium.org
committed
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
Read();
}
RegistryKeyIterator::~RegistryKeyIterator() {
base::ThreadRestrictions::AssertIOAllowed();
if (key_)
::RegCloseKey(key_);
}
DWORD RegistryKeyIterator::SubkeyCount() const {
base::ThreadRestrictions::AssertIOAllowed();
DWORD count = 0;
HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS)
return 0;
return count;
}
bool RegistryKeyIterator::Valid() const {
return key_ != NULL && index_ >= 0;
}
void RegistryKeyIterator::operator++() {
--index_;
Read();
}
bool RegistryKeyIterator::Read() {
base::ThreadRestrictions::AssertIOAllowed();
if (Valid()) {
DWORD ncount = arraysize(name_);
FILETIME written;
LRESULT r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
NULL, &written);
if (ERROR_SUCCESS == r)
return true;
}
name_[0] = '\0';

brettw@chromium.org
committed
} // namespace win
} // namespace base