// 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. // // A utility class that makes it easy to register for registry change // notifications. // #include "chrome_frame/registry_watcher.h" #include "chrome_frame/chrome_frame_helper_util.h" namespace { const wchar_t kRegistryWatcherEventName[] = L"chrome_registry_watcher_event"; } // namespace RegistryWatcher::RegistryWatcher(HKEY hive, const wchar_t* path, NotifyFunc callback) : callback_(callback), wait_event_(NULL), wait_handle_(NULL), stopping_(false) { // Enforce that we can open the given registry path with the KEY_NOTIFY // permission. LONG result = RegOpenKeyEx(hive, path, 0, KEY_NOTIFY, ®istry_key_); if (result != ERROR_SUCCESS) { registry_key_ = NULL; } } RegistryWatcher::~RegistryWatcher() { StopWatching(); if (registry_key_) { RegCloseKey(registry_key_); registry_key_ = NULL; } } bool RegistryWatcher::StartWatching() { if (!registry_key_ || wait_event_ || !callback_) { return false; } bool result = false; wait_event_ = CreateEvent(NULL, FALSE, // Auto-resets FALSE, // Initially non-signalled kRegistryWatcherEventName); if (wait_event_ != NULL) { LONG notify_result = RegNotifyChangeKeyValue( registry_key_, TRUE, // Watch subtree REG_NOTIFY_CHANGE_NAME, // Notifies if a subkey is added. wait_event_, TRUE); // Asynchronous, signal the event when a change occurs. if (notify_result == ERROR_SUCCESS) { if (RegisterWaitForSingleObject(&wait_handle_, wait_event_, &RegistryWatcher::WaitCallback, reinterpret_cast(this), INFINITE, WT_EXECUTEDEFAULT)) { stopping_ = false; result = true; } } } // If we're not good to go we don't need to hold onto the event. if (!result && wait_event_) { CloseHandle(wait_event_); wait_event_ = NULL; } return result; } void RegistryWatcher::StopWatching() { stopping_ = true; if (wait_handle_) { // Unregister the wait and block until any current handlers have returned. UnregisterWaitEx(wait_handle_, INVALID_HANDLE_VALUE); wait_handle_ = NULL; } if (wait_event_) { CloseHandle(wait_event_); wait_event_ = NULL; } } void CALLBACK RegistryWatcher::WaitCallback(void* param, BOOLEAN wait_fired) { RegistryWatcher* watcher = reinterpret_cast(param); if (watcher->stopping_) return; if (watcher->callback_) { watcher->callback_(); } }