/ src / modules / LightSwitch / LightSwitchService / NightLightRegistryObserver.h
NightLightRegistryObserver.h
  1  #pragma once
  2  #include <wtypes.h>
  3  #include <string>
  4  #include <functional>
  5  #include <thread>
  6  #include <atomic>
  7  #include <mutex>
  8  
  9  class NightLightRegistryObserver
 10  {
 11  public:
 12      NightLightRegistryObserver(HKEY root, const std::wstring& subkey, std::function<void()> callback) :
 13          _root(root), _subkey(subkey), _callback(std::move(callback)), _stop(false)
 14      {
 15          _thread = std::thread([this]() { this->Run(); });
 16      }
 17  
 18      ~NightLightRegistryObserver()
 19      {
 20          Stop();
 21      }
 22  
 23      void Stop()
 24      {
 25          _stop = true;
 26  
 27          {
 28              std::lock_guard<std::mutex> lock(_mutex);
 29              if (_event)
 30                  SetEvent(_event);
 31          }
 32  
 33          if (_thread.joinable())
 34              _thread.join();
 35  
 36          std::lock_guard<std::mutex> lock(_mutex);
 37          if (_hKey)
 38          {
 39              RegCloseKey(_hKey);
 40              _hKey = nullptr;
 41          }
 42  
 43          if (_event)
 44          {
 45              CloseHandle(_event);
 46              _event = nullptr;
 47          }
 48      }
 49  
 50  
 51  private:
 52      void Run()
 53      {
 54          {
 55              std::lock_guard<std::mutex> lock(_mutex);
 56              if (RegOpenKeyExW(_root, _subkey.c_str(), 0, KEY_NOTIFY, &_hKey) != ERROR_SUCCESS)
 57                  return;
 58  
 59              _event = CreateEventW(nullptr, TRUE, FALSE, nullptr);
 60              if (!_event)
 61              {
 62                  RegCloseKey(_hKey);
 63                  _hKey = nullptr;
 64                  return;
 65              }
 66          }
 67  
 68          while (!_stop)
 69          {
 70              HKEY hKeyLocal = nullptr;
 71              HANDLE eventLocal = nullptr;
 72  
 73              {
 74                  std::lock_guard<std::mutex> lock(_mutex);
 75                  if (_stop)
 76                      break;
 77  
 78                  hKeyLocal = _hKey;
 79                  eventLocal = _event;
 80              }
 81  
 82              if (!hKeyLocal || !eventLocal)
 83                  break;
 84  
 85              if (_stop)
 86                  break;
 87  
 88              if (RegNotifyChangeKeyValue(hKeyLocal, FALSE, REG_NOTIFY_CHANGE_LAST_SET, eventLocal, TRUE) != ERROR_SUCCESS)
 89                  break;
 90  
 91              DWORD wait = WaitForSingleObject(eventLocal, INFINITE);
 92              if (_stop || wait == WAIT_FAILED)
 93                  break;
 94  
 95              ResetEvent(eventLocal);
 96  
 97              if (!_stop && _callback)
 98              {
 99                  try
100                  {
101                      _callback();
102                  }
103                  catch (...)
104                  {
105                  }
106              }
107          }
108  
109          {
110              std::lock_guard<std::mutex> lock(_mutex);
111              if (_hKey)
112              {
113                  RegCloseKey(_hKey);
114                  _hKey = nullptr;
115              }
116  
117              if (_event)
118              {
119                  CloseHandle(_event);
120                  _event = nullptr;
121              }
122          }
123      }
124  
125  
126      HKEY _root;
127      std::wstring _subkey;
128      std::function<void()> _callback;
129      HANDLE _event = nullptr;
130      HKEY _hKey = nullptr;
131      std::thread _thread;
132      std::atomic<bool> _stop;
133      std::mutex _mutex;
134  };