直接使用win32 API来实现以减少对各种库的依赖,简单的封装了一个class如下:
public class RegistryWatcher : IDisposable
{
public EventHandler<RegistryKeyValueChangedArgs> RegistryKeyValueChanged;
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegNotifyChangeKeyValue(
SafeHandle hKey,
bool watchSubtree,
RegNotifyChangeFilterType filterType,
SafeHandle hEvent,
bool asynchronous);
enum RegNotifyChangeFilterType
{
RegNotifyChangeKeyName = 1,
RegNotifyChangeKeyAttributes = 2,
RegNotifyChangeKeyValue = 4,
RegNotifyChangeAttributes = 8,
RegNotifyChangeAll = RegNotifyChangeKeyName | RegNotifyChangeKeyAttributes | RegNotifyChangeKeyValue | RegNotifyChangeAttributes
}
bool _isDisposed = false;
AutoResetEvent _autoResetEvent;
RegistryHive _registryHive;
string _registryPath;
public RegistryWatcher(RegistryHive hKey, string registryPath)
{
_registryHive = hKey;
_registryPath = registryPath;
}
public void Start()
{
Task.Factory.StartNew(() => OnMonitorRegistryChangedAction(_registryHive, _registryPath), TaskCreationOptions.LongRunning);
}
public void Dispose()
{
_isDisposed = true;
_autoResetEvent?.Set();
}
private void OnMonitorRegistryChangedAction(RegistryHive hKey, string registryPath)
{
var is64BitOperatingSystem = Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32;
while (!_isDisposed)
{
using (var registry = RegistryKey.OpenBaseKey(hKey, is64BitOperatingSystem))
{
using (var subRegistry = registry.OpenSubKey(registryPath))
{
using (var autoResetEvent = new AutoResetEvent(false))
{
_autoResetEvent = autoResetEvent;
int result = RegNotifyChangeKeyValue(subRegistry.Handle, true, RegNotifyChangeFilterType.RegNotifyChangeKeyValue, autoResetEvent.SafeWaitHandle, true);
if (result == 0 && !_isDisposed && autoResetEvent.WaitOne())
{
RegistryKeyValueChanged?.Invoke(this, new RegistryKeyValueChangedArgs());
}
_autoResetEvent = null;
}
}
}
}
}
public class RegistryKeyValueChangedArgs
{
public DateTime Time { get; set; } = DateTime.Now;
}
}