Home | History | Annotate | Download | only in chrome_frame
      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 //
      8 
      9 #include "chrome_frame/registry_watcher.h"
     10 
     11 #include "chrome_frame/chrome_frame_helper_util.h"
     12 
     13 namespace {
     14 const wchar_t kRegistryWatcherEventName[] = L"chrome_registry_watcher_event";
     15 }  // namespace
     16 
     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;
     29   }
     30 }
     31 
     32 RegistryWatcher::~RegistryWatcher() {
     33   StopWatching();
     34   if (registry_key_) {
     35     RegCloseKey(registry_key_);
     36     registry_key_ = NULL;
     37   }
     38 }
     39 
     40 bool RegistryWatcher::StartWatching() {
     41   if (!registry_key_ || wait_event_ || !callback_) {
     42     return false;
     43   }
     44 
     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.
     57 
     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;
     67       }
     68     }
     69   }
     70 
     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;
     75   }
     76 
     77   return result;
     78 }
     79 
     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;
     86   }
     87   if (wait_event_) {
     88     CloseHandle(wait_event_);
     89     wait_event_ = NULL;
     90   }
     91 }
     92 
     93 void CALLBACK RegistryWatcher::WaitCallback(void* param, BOOLEAN wait_fired) {
     94   RegistryWatcher* watcher = reinterpret_cast<RegistryWatcher*>(param);
     95   if (watcher->stopping_)
     96     return;
     97 
     98   if (watcher->callback_) {
     99     watcher->callback_();
    100   }
    101 }
    102