/// <summary> /// Invokes the associated event handler. /// </summary> /// <returns>True if the watcher will be run again; false if the /// entry has been closed and can be removed.</returns> public bool Invoke(RegistryWatcher sender) { if (_key == null) { // Returns true so we don't try and remove null entries from // the list. return true; } if (!_registered) { return false; } _callback(sender, _args); if (_args.CancelWatcher) { Unregister(); return false; } lock (this) { // only re-register if we haven't been closed if (_registered) { try { Register(); } catch (Win32Exception ex) { // If we fail to re-register (probably because the // key has been deleted), there's nothing that can // be done. Fail if we're debugging, otherwise just // continue without registering the watcher again. Debug.Fail("Error registering registry watcher: " + ex.ToString()); _registered = false; } } } return true; }
/// <summary> /// Starts listening for notifications in the specified registry key. /// /// Each part of the key must be provided separately so that the watcher /// can open its own handle. /// </summary> /// <param name="hive">The hive to watch</param> /// <param name="view">The view to watch</param> /// <param name="key">The key to watch</param> /// <param name="handler">The event handler to invoke</param> /// <param name="recursive">True to watch all subkeys as well</param> /// <param name="notifyValueChange"> /// True to notify if a value is added, removed or updated. /// </param> /// <param name="notifyKeyChange"> /// True to notify if a subkey is added or removed. /// </param> /// <param name="tag"> /// An arbitrary identifier to include with any raised events. /// </param> /// <returns> /// An opaque token that can be pased to Remove, or null if the watcher /// could not be added. /// </returns> public object TryAdd( RegistryHive hive, RegistryView view, string key, RegistryChangedEventHandler handler, bool recursive = false, bool notifyValueChange = true, bool notifyKeyChange = true, object tag = null ) { if (key == null) { throw new ArgumentNullException("key"); } if (handler == null) { throw new ArgumentNullException("handler"); } if (!(notifyValueChange | notifyKeyChange)) { throw new InvalidOperationException("Must wait for at least one type of change"); } var args = new RegistryChangedEventArgs( hive, view, key, recursive, notifyValueChange, notifyKeyChange, tag ); int currentWatcher = -1; RegistryWatcher watcher; bool needNewThread; var token = TryAddInternal(handler, args, out needNewThread); while (needNewThread) { if (_extraWatchers == null) { _extraWatchers = new List <RegistryWatcher>(); } currentWatcher += 1; if (currentWatcher >= _extraWatchers.Count) { watcher = new RegistryWatcher(); _extraWatchers.Add(watcher); } else { watcher = _extraWatchers[currentWatcher]; } token = watcher.TryAddInternal(handler, args, out needNewThread); } return(token); }
object AddWatch(RegistryWatcher watcher, string subkey, Action<RegistryChangedEventArgs> callback, bool recursive = false, bool notifyValueChange = true, bool notifyKeyChange = true) { return watcher.Add( RegistryHive.CurrentUser, RegistryView.Default, GetKey(subkey), (s, e) => { callback(e); }, recursive, notifyValueChange, notifyKeyChange); }
/// <summary> /// Starts listening for notifications in the specified registry key. /// /// Each part of the key must be provided separately so that the watcher /// can open its own handle. /// </summary> /// <param name="hive">The hive to watch</param> /// <param name="view">The view to watch</param> /// <param name="key">The key to watch</param> /// <param name="handler">The event handler to invoke</param> /// <param name="recursive">True to watch all subkeys as well</param> /// <param name="notifyValueChange"> /// True to notify if a value is added, removed or updated. /// </param> /// <param name="notifyKeyChange"> /// True to notify if a subkey is added or removed. /// </param> /// <param name="tag"> /// An arbitrary identifier to include with any raised events. /// </param> /// <returns> /// An opaque token that can be pased to Remove, or null if the watcher /// could not be added. /// </returns> public object TryAdd( RegistryHive hive, RegistryView view, string key, RegistryChangedEventHandler handler, bool recursive = false, bool notifyValueChange = true, bool notifyKeyChange = true, object tag = null ) { if (key == null) { throw new ArgumentNullException("key"); } if (handler == null) { throw new ArgumentNullException("handler"); } if (!(notifyValueChange | notifyKeyChange)) { throw new InvalidOperationException("Must wait for at least one type of change"); } var args = new RegistryChangedEventArgs( hive, view, key, recursive, notifyValueChange, notifyKeyChange, tag ); int currentWatcher = -1; RegistryWatcher watcher; bool needNewThread; var token = TryAddInternal(handler, args, out needNewThread); while (needNewThread) { if (_extraWatchers == null) { _extraWatchers = new List<RegistryWatcher>(); } currentWatcher += 1; if (currentWatcher >= _extraWatchers.Count) { watcher = new RegistryWatcher(); _extraWatchers.Add(watcher); } else { watcher = _extraWatchers[currentWatcher]; } token = watcher.TryAddInternal(handler, args, out needNewThread); } return token; }
public void RegistryWatcherUpdateNonRecursive() { string keyName = "RegistryWatcherUpdateNonRecursive"; SetValue(keyName, "TestValue", "ABC"); SetValue(keyName + "\\TestKey", "Value", 123); using (var watcher = new RegistryWatcher()) { RegistryChangedEventArgs args = null; var argsSet = new ManualResetEventSlim(); var watch1 = AddWatch(watcher, keyName, e => { args = e; argsSet.Set(); }); // Value is set, but does not actually change SetValue(keyName, "TestValue", "ABC"); Assert.IsFalse(argsSet.Wait(TIMEOUT)); Assert.IsNull(args); // Value is changed SetValue(keyName, "TestValue", "DEF"); Assert.IsTrue(argsSet.Wait(TIMEOUT)); Assert.IsNotNull(args); Assert.AreEqual(GetKey(keyName), args.Key); argsSet.Reset(); args = null; // Value in subkey is changed, but we don't notice SetValue(keyName + "\\TestKey", "Value", 456); Assert.IsFalse(argsSet.Wait(TIMEOUT)); Assert.IsNull(args); watcher.Remove(watch1); // Value is changed back, but we don't get notified SetValue(keyName, "TestValue", "ABC"); Assert.IsFalse(argsSet.Wait(TIMEOUT)); Assert.IsNull(args); // Value in subkey is changed back, but we don't notice SetValue(keyName + "\\TestKey", "Value", 123); Assert.IsFalse(argsSet.Wait(TIMEOUT)); Assert.IsNull(args); } }
public void RegistryWatcher100Keys() { string keyName = "RegistryWatcher100Keys"; for (int i = 0; i < 100; ++i) { SetValue(string.Format("{0}\\Key{1}", keyName, i), "Value", "ABC"); } using (var watcher = new RegistryWatcher()) { var args = new RegistryChangedEventArgs[100]; var argsSet = args.Select(_ => new ManualResetEventSlim()).ToArray(); var tokens = new object[100]; for (int i = 0; i < 100; ++i) { tokens[i] = AddWatch(watcher, string.Format("{0}\\Key{1}", keyName, i), new ArgSetter(args, argsSet, i).Raised); } // Change the first value SetValue(keyName + "\\Key0", "Value", "DEF"); Assert.IsTrue(argsSet[0].Wait(TIMEOUT)); Assert.IsNotNull(args[0]); Assert.AreEqual(GetKey(keyName + "\\Key0"), args[0].Key); argsSet[0].Reset(); args[0] = null; // Change the last value SetValue(keyName + "\\Key99", "Value", "DEF"); Assert.IsTrue(argsSet[99].Wait(TIMEOUT)); Assert.IsNotNull(args[99]); Assert.AreEqual(GetKey(keyName + "\\Key99"), args[99].Key); argsSet[99].Reset(); args[99] = null; watcher.Remove(tokens[0]); watcher.Remove(tokens[99]); // Change the first value SetValue(keyName + "\\Key0", "Value", "GHI"); Assert.IsFalse(argsSet[0].Wait(TIMEOUT)); Assert.IsNull(args[0]); // Change the last value SetValue(keyName + "\\Key99", "Value", "GHI"); Assert.IsFalse(argsSet[99].Wait(TIMEOUT)); Assert.IsNull(args[99]); } }
public void RegistryWatcherDeleteRecursive() { string keyName = "RegistryWatcherDeleteRecursive"; SetValue(keyName, "TestValue1", "ABC"); SetValue(keyName, "TestValue2", "DEF"); SetValue(keyName, "TestValue3", "GHI"); SetValue(keyName + "\\TestKey1", "Value", 123); SetValue(keyName + "\\TestKey2", "Value", 456); using (var watcher = new RegistryWatcher()) { RegistryChangedEventArgs args = null; var argsSet = new ManualResetEventSlim(); var watch1 = AddWatch(watcher, keyName, e => { args = e; argsSet.Set(); }, recursive: true); // Value is deleted DeleteValue(keyName, "TestValue2"); Assert.IsTrue(argsSet.Wait(TIMEOUT)); Assert.IsNotNull(args); Assert.AreEqual(GetKey(keyName), args.Key); argsSet.Reset(); args = null; // Value in subkey is deleted DeleteValue(keyName + "\\TestKey1", "Value"); Assert.IsTrue(argsSet.Wait(TIMEOUT)); Assert.IsNotNull(args); Assert.AreEqual(GetKey(keyName), args.Key); argsSet.Reset(); args = null; // Subkey is deleted DeleteKey(keyName + "\\TestKey1"); Assert.IsTrue(argsSet.Wait(TIMEOUT)); Assert.IsNotNull(args); Assert.AreEqual(GetKey(keyName), args.Key); argsSet.Reset(); args = null; watcher.Remove(watch1); // Another value is deleted, but we don't get notified DeleteValue(keyName, "TestValue3"); Assert.IsFalse(argsSet.Wait(TIMEOUT)); Assert.IsNull(args); // Another key is deleted, but we don't get notified DeleteKey(keyName + "\\TestKey2"); Assert.IsFalse(argsSet.Wait(TIMEOUT)); Assert.IsNull(args); } }