1
我想跟蹤對註冊表項的更改,例如添加/刪除子項,添加/刪除/編輯值。我如何創建一個公開這些更改的IObservable序列?監控與反應式擴展的註冊表項
我想跟蹤對註冊表項的更改,例如添加/刪除子項,添加/刪除/編輯值。我如何創建一個公開這些更改的IObservable序列?監控與反應式擴展的註冊表項
一種方法是調用RegNotifyChangeKeyValue,這是一個Win32函數,它通知調用者有關指定註冊表項的屬性或內容的更改。該函數在檢測到更改時設置事件。請注意,它必須在持久線程上調用,否則只要線程退出(即使未發生更改),它也會發出信號。請參閱下面的Rx.Net可能的實現。
using System;
using System.ComponentModel;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32;
public class RegistryMonitoringOperations
{
[Flags]
public enum RegChangeNotifyFilter
{
/// <summary>Notify the caller if a subkey is added or deleted.</summary>
Key = 1,
/// <summary>Notify the caller of changes to the attributes of the key,
/// such as the security descriptor information.</summary>
Attribute = 2,
/// <summary>Notify the caller of changes to a value of the key. This can
/// include adding or deleting a value, or changing an existing value.</summary>
Value = 4,
/// <summary>Notify the caller of changes to the security descriptor
/// of the key.</summary>
Security = 8
}
private const int KeyQueryValue = 0x0001;
private const int KeyNotify = 0x0010;
private const int StandardRightsRead = 0x00020000;
public static IObservable<Unit> CreateKeyValuesChangedObservable(
RegistryHive hive,
string subKey,
RegChangeNotifyFilter filter,
IScheduler registrationScheduler)
{
return Observable.Create<Unit>(
obs =>
{
try
{
var key = OpenKey(hive, subKey);
return new CompositeDisposable(
CreateKeyValuesChangedObservable(key, filter).SubscribeOn(registrationScheduler).Subscribe(obs),
Disposable.Create(() => RegCloseKey(key)));
}
catch (Win32Exception e)
{
obs.OnError(e);
return Disposable.Empty;
}
});
}
private static IDisposable SetCallbackWhenSignalled(WaitHandle waitObject, Action action)
{
var registeredWait = ThreadPool.RegisterWaitForSingleObject(waitObject, (s, t) => action(), null, -1, true);
return Disposable.Create(() => registeredWait.Unregister(null));
}
private static IObservable<Unit> CreateKeyValuesChangedObservable(IntPtr key, RegChangeNotifyFilter filter)
{
return Observable.Create<Unit>(
obs =>
{
var eventNotify = new AutoResetEvent(false);
var result = RegNotifyChangeKeyValue(key, true, filter, eventNotify.SafeWaitHandle.DangerousGetHandle(), true);
if (result != 0)
{
obs.OnError(new Win32Exception(Marshal.GetLastWin32Error()));
}
return new CompositeDisposable(
eventNotify,
SetCallbackWhenSignalled(
eventNotify,
() =>
{
obs.OnNext(Unit.Default);
obs.OnCompleted();
}));
}).Repeat();
}
private static IntPtr OpenKey(RegistryHive hive, string subKey)
{
IntPtr registryKey;
var result = RegOpenKeyEx((int)hive, subKey, 0, StandardRightsRead | KeyQueryValue | KeyNotify, out registryKey);
if (result != 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return registryKey;
}
下面是這個函數的典型用法:
RegistryMonitoringOperations.CreateKeyValuesChangedObservable(
RegistryHive.LocalMachine,
"somepath",
RegistryMonitoringOperations.RegChangeNotifyFilter.Value,
DispatcherScheduler.Instance)
正如你可以在上面看到,避免奉獻一個線程調用這個函數的一種方式是使用UI線程這是永久性的(所以按照rx的術語,使用調度程序調度程序)。 RegNotifyChangeKeyValue在異步模式下立即返回,因此它不會阻止UI。