Roll ANGLE r1389:1394
[chromium-blink-merge.git] / chrome_frame / registry_watcher.cc
blobdcbf8b91497f49a93744251cd31f5805efc6ff9c
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // A utility class that makes it easy to register for registry change
6 // notifications.
7 //
9 #include "chrome_frame/registry_watcher.h"
11 #include "chrome_frame/chrome_frame_helper_util.h"
13 namespace {
14 const wchar_t kRegistryWatcherEventName[] = L"chrome_registry_watcher_event";
15 } // namespace
17 RegistryWatcher::RegistryWatcher(HKEY hive,
18 const wchar_t* path,
19 NotifyFunc callback)
20 : callback_(callback),
21 wait_event_(NULL),
22 wait_handle_(NULL),
23 stopping_(false) {
24 // Enforce that we can open the given registry path with the KEY_NOTIFY
25 // permission.
26 LONG result = RegOpenKeyEx(hive, path, 0, KEY_NOTIFY, &registry_key_);
27 if (result != ERROR_SUCCESS) {
28 registry_key_ = NULL;
32 RegistryWatcher::~RegistryWatcher() {
33 StopWatching();
34 if (registry_key_) {
35 RegCloseKey(registry_key_);
36 registry_key_ = NULL;
40 bool RegistryWatcher::StartWatching() {
41 if (!registry_key_ || wait_event_ || !callback_) {
42 return false;
45 bool result = false;
46 wait_event_ = CreateEvent(NULL,
47 FALSE, // Auto-resets
48 FALSE, // Initially non-signalled
49 kRegistryWatcherEventName);
50 if (wait_event_ != NULL) {
51 LONG notify_result = RegNotifyChangeKeyValue(
52 registry_key_,
53 TRUE, // Watch subtree
54 REG_NOTIFY_CHANGE_NAME, // Notifies if a subkey is added.
55 wait_event_,
56 TRUE); // Asynchronous, signal the event when a change occurs.
58 if (notify_result == ERROR_SUCCESS) {
59 if (RegisterWaitForSingleObject(&wait_handle_,
60 wait_event_,
61 &RegistryWatcher::WaitCallback,
62 reinterpret_cast<void*>(this),
63 INFINITE,
64 WT_EXECUTEDEFAULT)) {
65 stopping_ = false;
66 result = true;
71 // If we're not good to go we don't need to hold onto the event.
72 if (!result && wait_event_) {
73 CloseHandle(wait_event_);
74 wait_event_ = NULL;
77 return result;
80 void RegistryWatcher::StopWatching() {
81 stopping_ = true;
82 if (wait_handle_) {
83 // Unregister the wait and block until any current handlers have returned.
84 UnregisterWaitEx(wait_handle_, INVALID_HANDLE_VALUE);
85 wait_handle_ = NULL;
87 if (wait_event_) {
88 CloseHandle(wait_event_);
89 wait_event_ = NULL;
93 void CALLBACK RegistryWatcher::WaitCallback(void* param, BOOLEAN wait_fired) {
94 RegistryWatcher* watcher = reinterpret_cast<RegistryWatcher*>(param);
95 if (watcher->stopping_)
96 return;
98 if (watcher->callback_) {
99 watcher->callback_();