internal static extern int RegNotifyChangeKeyValue( SafeRegistryHandle hKey, [MarshalAs(UnmanagedType.Bool)] bool watchSubtree, RegistryChangeNotificationFilters notifyFilter, SafeWaitHandle hEvent, [MarshalAs(UnmanagedType.Bool)] bool asynchronous);
/// <summary> /// Returns a Task that completes when the specified registry key changes. /// </summary> /// <param name="registryKeyHandle">The handle to the open registry key to watch for changes.</param> /// <param name="watchSubtree"><c>true</c> to watch the keys descendent keys as well; <c>false</c> to watch only this key without descendents.</param> /// <param name="change">Indicates the kinds of changes to watch for.</param> /// <param name="cancellationToken">A token that may be canceled to release the resources from watching for changes and complete the returned Task as canceled.</param> /// <returns> /// A task that completes when the registry key changes, the handle is closed, or upon cancellation. /// </returns> private static async Task WaitForRegistryChangeAsync(SafeRegistryHandle registryKeyHandle, bool watchSubtree, RegistryChangeNotificationFilters change, CancellationToken cancellationToken) { IDisposable dedicatedThreadReleaser = null; try { using (var evt = new ManualResetEventSlim()) { Action registerAction = delegate { int win32Error = NativeMethods.RegNotifyChangeKeyValue( registryKeyHandle, watchSubtree, change, evt.WaitHandle.SafeWaitHandle, true); if (win32Error != 0) { throw new Win32Exception(win32Error); } }; if (LightUps.IsWindows8OrLater) { change |= NativeMethods.REG_NOTIFY_THREAD_AGNOSTIC; registerAction(); } else { // Engage our downlevel support by using a single, dedicated thread to guarantee // that we request notification on a thread that will not be destroyed later. // Although we *could* await this, we synchronously block because our caller expects // subscription to have begun before we return: for the async part to simply be notification. // This async method we're calling uses .ConfigureAwait(false) internally so this won't // deadlock if we're called on a thread with a single-thread SynchronizationContext. dedicatedThreadReleaser = DownlevelRegistryWatcherSupport.ExecuteOnDedicatedThreadAsync(registerAction).GetAwaiter().GetResult(); } await evt.WaitHandle.ToTask(cancellationToken : cancellationToken).ConfigureAwait(false); } } finally { dedicatedThreadReleaser?.Dispose(); } }
static void DoNotify(SafeRegistryHandle registryKeyHandle, bool watchSubtree, RegistryChangeNotificationFilters change, WaitHandle evt) { int win32Error = NativeMethods.RegNotifyChangeKeyValue( registryKeyHandle, watchSubtree, change, evt.SafeWaitHandle, true); if (win32Error != 0) { throw new Win32Exception(win32Error); } }
/// <summary> /// Returns a Task that completes when the specified registry key changes. /// </summary> /// <param name="registryKey">The registry key to watch for changes.</param> /// <param name="watchSubtree"><c>true</c> to watch the keys descendent keys as well; <c>false</c> to watch only this key without descendents.</param> /// <param name="change">Indicates the kinds of changes to watch for.</param> /// <param name="cancellationToken">A token that may be canceled to release the resources from watching for changes and complete the returned Task as canceled.</param> /// <returns> /// A task that completes when the registry key changes, the handle is closed, or upon cancellation. /// </returns> public static Task WaitForChangeAsync(this RegistryKey registryKey, bool watchSubtree = true, RegistryChangeNotificationFilters change = RegistryChangeNotificationFilters.Value | RegistryChangeNotificationFilters.Subkey, CancellationToken cancellationToken = default(CancellationToken)) { Requires.NotNull(registryKey, nameof(registryKey)); return(WaitForRegistryChangeAsync(registryKey.Handle, watchSubtree, change, cancellationToken)); }
/// <summary> /// Returns a Task that completes when the specified registry key changes. /// </summary> /// <param name="registryKeyHandle">The handle to the open registry key to watch for changes.</param> /// <param name="watchSubtree"><c>true</c> to watch the keys descendent keys as well; <c>false</c> to watch only this key without descendents.</param> /// <param name="change">Indicates the kinds of changes to watch for.</param> /// <param name="cancellationToken">A token that may be canceled to release the resources from watching for changes and complete the returned Task as canceled.</param> /// <returns> /// A task that completes when the registry key changes, the handle is closed, or upon cancellation. /// </returns> private static async Task WaitForRegistryChangeAsync(SafeRegistryHandle registryKeyHandle, bool watchSubtree, RegistryChangeNotificationFilters change, CancellationToken cancellationToken) { IDisposable?dedicatedThreadReleaser = null; try { using (var evt = new ManualResetEvent(false)) {