@msdn=http://search.microsoft.com/search/results.aspx?qu=$$$ @pinvoke=http://pinvoke.net/$$$.htm Summary: Notifies the caller about changes to the attributes or contents of a specified registry key. !!!!C# Signature: [DllImport("Advapi32.dll")] private static extern int RegNotifyChangeKeyValue( IntPtr hKey, bool watchSubtree, REG_NOTIFY_CHANGE notifyFilter, IntPtr hEvent, bool asynchronous ); [Flags] public enum REG_NOTIFY_CHANGE : uint { /// <summary> /// Notify the caller if a subkey is added or deleted /// </summary> NAME = 0x1, /// <summary> /// Notify the caller of changes to the attributes of the key, /// such as the security descriptor information /// </summary> ATTRIBUTES = 0x2, /// <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> LAST_SET = 0x4, /// <summary> /// Notify the caller of changes to the security descriptor of the key /// </summary> SECURITY = 0x8 } !!!!C++ Signature: LONG WINAPI RegNotifyChangeKeyValue( __in HKEY hKey, __in BOOL bWatchSubtree, __in DWORD dwNotifyFilter, __in_opt HANDLE hEvent, __in BOOL fAsynchronous ); !!!!VB Signature: Declare Function RegNotifyChangeKeyValue Lib "advapi32.dll" (hKey As IntPtr, _ watchSubtree As Boolean, dwNotifyFilter As Integer, hEvent As IntPtr, fAsynchronous As Boolean) As Integer !!!!Notes: Starting with the .NET Framework 2.0, the IntPtr@mdsn parameters could be defined as SafeHandle@msdn instead. !!!!Tips & Tricks: Please add some! !!!!Sample Code: // RegistryChangeMonitor.cs using System; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using Microsoft.Win32; namespace BBooth { #region Delegates public delegate void RegistryChangeHandler(object sender, RegistryChangeEventArgs e); #endregion public class RegistryChangeMonitor : IDisposable { #region Fields private string _registryPath; private REG_NOTIFY_CHANGE _filter; private Thread _monitorThread; private RegistryKey _monitorKey; #endregion #region Imports [DllImport("Advapi32.dll")] private static extern int RegNotifyChangeKeyValue( IntPtr hKey, bool watchSubtree, REG_NOTIFY_CHANGE notifyFilter, IntPtr hEvent, bool asynchronous ); #endregion #region Enumerations [Flags] public enum REG_NOTIFY_CHANGE : uint { NAME = 0x1, ATTRIBUTES = 0x2, LAST_SET = 0x4, SECURITY = 0x8 } #endregion #region Constructors public RegistryChangeMonitor(string registryPath) : this(registryPath, REG_NOTIFY_CHANGE.LAST_SET) { ; } public RegistryChangeMonitor(string registryPath, REG_NOTIFY_CHANGE filter) { this._registryPath = registryPath.ToUpper(); this._filter = filter; } ~RegistryChangeMonitor() { this.Dispose(false); } #endregion #region Methods private void Dispose(bool disposing) { if (disposing) GC.SuppressFinalize(this); this.Stop(); } public void Dispose() { this.Dispose(true); } public void Start() { lock (this) { if (this._monitorThread == null) { ThreadStart ts = new ThreadStart(this.MonitorThread); this._monitorThread = new Thread(ts); this._monitorThread.IsBackground = true; } if (!this._monitorThread.IsAlive) { this._monitorThread.Start(); } } } public void Stop() { lock (this) { this.Changed = null; this.Error = null; if (this._monitorThread != null) { this._monitorThread = null; } // The "Close()" will trigger RegNotifyChangeKeyValue if it is still listening if (this._monitorKey != null) { this._monitorKey.Close(); this._monitorKey = null; } } } private void MonitorThread() { try { IntPtr ptr = IntPtr.Zero; lock (this) { if (this._registryPath.StartsWith("HKEY_CLASSES_ROOT")) this._monitorKey = Registry.ClassesRoot.OpenSubKey(this._registryPath.Substring(18)); else if (this._registryPath.StartsWith("HKCR")) this._monitorKey = Registry.ClassesRoot.OpenSubKey(this._registryPath.Substring(5)); else if (this._registryPath.StartsWith("HKEY_CURRENT_USER")) this._monitorKey = Registry.CurrentUser.OpenSubKey(this._registryPath.Substring(18)); else if (this._registryPath.StartsWith("HKCU")) this._monitorKey = Registry.CurrentUser.OpenSubKey(this._registryPath.Substring(5)); else if (this._registryPath.StartsWith("HKEY_LOCAL_MACHINE")) this._monitorKey = Registry.LocalMachine.OpenSubKey(this._registryPath.Substring(19)); else if (this._registryPath.StartsWith("HKLM")) this._monitorKey = Registry.LocalMachine.OpenSubKey(this._registryPath.Substring(5)); else if (this._registryPath.StartsWith("HKEY_USERS")) this._monitorKey = Registry.Users.OpenSubKey(this._registryPath.Substring(11)); else if (this._registryPath.StartsWith("HKU")) this._monitorKey = Registry.Users.OpenSubKey(this._registryPath.Substring(4)); else if (this._registryPath.StartsWith("HKEY_CURRENT_CONFIG")) this._monitorKey = Registry.CurrentConfig.OpenSubKey(this._registryPath.Substring(20)); else if (this._registryPath.StartsWith("HKCC")) this._monitorKey = Registry.CurrentConfig.OpenSubKey(this._registryPath.Substring(5)); // Fetch the native handle if (this._monitorKey != null) { object hkey = typeof(RegistryKey).InvokeMember( "hkey", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic, null, this._monitorKey, null ); ptr = (IntPtr)typeof(SafeHandle).InvokeMember( "handle", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic, null, hkey, null); } } if (ptr != IntPtr.Zero) { while (true) { // If this._monitorThread is null that probably means Dispose is being called. Don't monitor anymore. if ((this._monitorThread == null) || (this._monitorKey == null)) break; // RegNotifyChangeKeyValue blocks until a change occurs. int result = RegNotifyChangeKeyValue(ptr, true, this._filter, IntPtr.Zero, false); if ((this._monitorThread == null) || (this._monitorKey == null)) break; if (result == 0) { if (this.Changed != null) { RegistryChangeEventArgs e = new RegistryChangeEventArgs(this); this.Changed(this, e); if (e.Stop) break; } } else { if (this.Error != null) { Win32Exception ex = new Win32Exception(); // Unless the exception is thrown, nobody is nice enough to set a good stacktrace for us. Set it ourselves. typeof(Exception).InvokeMember( "_stackTrace", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, ex, new object[] { new StackTrace(true) } ); RegistryChangeEventArgs e = new RegistryChangeEventArgs(this); e.Exception = ex; this.Error(this, e); } break; } } } } catch (Exception ex) { if (this.Error != null) { RegistryChangeEventArgs e = new RegistryChangeEventArgs(this); e.Exception = ex; this.Error(this, e); } } finally { this.Stop(); } } #endregion #region Events public event RegistryChangeHandler Changed; public event RegistryChangeHandler Error; #endregion #region Properties public bool Monitoring { get { if (this._monitorThread != null) return this._monitorThread.IsAlive; return false; } } #endregion } } // RegistryChangeEventArgs.cs using System; namespace BBooth { public class RegistryChangeEventArgs : EventArgs { #region Fields private bool _stop; private Exception _exception; private RegistryChangeMonitor _monitor; #endregion #region Constructor public RegistryChangeEventArgs(RegistryChangeMonitor monitor) { this._monitor = monitor; } #endregion #region Properties public RegistryChangeMonitor Monitor { get { return this._monitor; } } public Exception Exception { get { return this._exception; } set { this._exception = value; } } public bool Stop { get { return this._stop; } set { this._stop = value; } } #endregion } } !!!!Alternative Managed API: Do you know one? Please contribute it! Documentation: RegNotifyChangeKeyValue@msdn on MSDN
Edit advapi32.RegNotif...
You do not have permission to change this page. If you feel this is in error, please send feedback with the contact link on the main page.