Last active
December 23, 2023 10:29
-
-
Save thenadz/edfcd52a02d479e443e0 to your computer and use it in GitHub Desktop.
Class to monitor one or more registry values and notify when value changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Win32; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading; | |
public class Program | |
{ | |
private const string REG_KEY = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system"; | |
private const string CAPTION_VALUE_NAME = "legalnoticecaption"; | |
private const string TEXT_VALUE_NAME = "legalnoticetext"; | |
/// <summary> | |
/// The watcher instance. | |
/// </summary> | |
private static RegistryWatcher watcher; | |
/// <summary> | |
/// Mains the specified arguments. | |
/// </summary> | |
/// <param name="args">The arguments.</param> | |
public static void Main(string[] args) | |
{ | |
watcher = new RegistryWatcher( | |
new Tuple<string, string>(REG_KEY, CAPTION_VALUE_NAME), | |
new Tuple<string, string>(REG_KEY, TEXT_VALUE_NAME)); | |
watcher.RegistryChange += RegistryChanged; | |
Registry.SetValue(REG_KEY, CAPTION_VALUE_NAME, string.Empty); | |
Registry.SetValue(REG_KEY, TEXT_VALUE_NAME, string.Empty); | |
Console.ReadLine(); | |
} | |
/// <summary> | |
/// Registries the changed. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="args">The <see cref="RegistryWatcher.RegistryChangeEventArgs"/> instance containing the event data.</param> | |
private static void RegistryChanged(object sender, RegistryWatcher.RegistryChangeEventArgs args) | |
{ | |
if (!string.IsNullOrEmpty(args.Value.ToString())) | |
{ | |
Registry.SetValue(args.KeyName, args.ValueName, string.Empty); | |
} | |
} | |
} | |
public class RegistryWatcher : IDisposable | |
{ | |
/// <summary> | |
/// The period in ms between registry polls. | |
/// </summary> | |
private const int PERIOD = 30000; | |
/// <summary> | |
/// The current reg values to be compared against. | |
/// </summary> | |
private readonly Dictionary<Tuple<string, string>, object> currentRegValues; | |
/// <summary> | |
/// Registry entries to watch. | |
/// </summary> | |
private readonly Tuple<string, string>[] toWatch; | |
/// <summary> | |
/// The timer to trigger registry polls. | |
/// </summary> | |
private readonly Timer timer; | |
/// <summary> | |
/// Occurs when registry value changes. | |
/// </summary> | |
public event EventHandler<RegistryChangeEventArgs> RegistryChange; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="RegistryWatcher"/> class. | |
/// </summary> | |
/// <param name="toWatch">Registry entries to watch.</param> | |
public RegistryWatcher(params Tuple<string, string>[] toWatch) | |
{ | |
this.toWatch = toWatch; | |
if (toWatch.Length > 0) | |
{ | |
currentRegValues = toWatch.ToDictionary(key => key, key => Registry.GetValue(key.Item1, key.Item2, null)); | |
timer = new Timer(CheckRegistry, null, PERIOD, Timeout.Infinite); | |
} | |
} | |
/// <summary> | |
/// Checks the registry. | |
/// </summary> | |
/// <param name="state">The state.</param> | |
private void CheckRegistry(object state) | |
{ | |
foreach (Tuple<string, string> reg in toWatch) | |
{ | |
object newValue = Registry.GetValue(reg.Item1, reg.Item2, null); | |
if (currentRegValues[reg] != newValue) | |
{ | |
RegistryChange?.Invoke(this, new RegistryChangeEventArgs(reg.Item1, reg.Item2, newValue)); | |
currentRegValues[reg] = newValue; | |
} | |
} | |
timer.Change(PERIOD, Timeout.Infinite); | |
} | |
/// <summary> | |
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | |
/// </summary> | |
public void Dispose() | |
{ | |
try | |
{ | |
timer?.Dispose(); | |
} | |
catch { } | |
} | |
/// <summary> | |
/// Event args provided upon registry value changing. | |
/// </summary> | |
public class RegistryChangeEventArgs : EventArgs | |
{ | |
/// <summary> | |
/// Initializes a new instance of the <see cref="RegistryChangeEventArgs"/> class. | |
/// </summary> | |
/// <param name="keyName">Name of the key.</param> | |
/// <param name="valueName">Name of the value.</param> | |
/// <param name="value">The value.</param> | |
public RegistryChangeEventArgs(string keyName, string valueName, object value) | |
{ | |
KeyName = keyName; | |
ValueName = valueName; | |
Value = value; | |
} | |
/// <summary> | |
/// Gets the name of the key. | |
/// </summary> | |
public string KeyName { get; } | |
/// <summary> | |
/// Gets the name of the value. | |
/// </summary> | |
public string ValueName { get; } | |
/// <summary> | |
/// Gets the value. | |
/// </summary> | |
public object Value { get; } | |
} | |
} |
VB>NET Registry Watcher Class
Imports Microsoft.Win32
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading
Public Class Program
Private Const REG_KEY As String = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system"
Private Const CAPTION_VALUE_NAME As String = "legalnoticecaption"
Private Const TEXT_VALUE_NAME As String = "legalnoticetext"
Private Shared watcher As RegistryWatcher
Public Shared Sub Main(ByVal args As String())
watcher = New RegistryWatcher(New Tuple(Of String, String)(REG_KEY, CAPTION_VALUE_NAME), New Tuple(Of String, String)(REG_KEY, TEXT_VALUE_NAME))
AddHandler watcher.RegistryChange, AddressOf RegistryChanged
Registry.SetValue(REG_KEY, CAPTION_VALUE_NAME, String.Empty)
Registry.SetValue(REG_KEY, TEXT_VALUE_NAME, String.Empty)
Console.ReadLine()
End Sub
Private Shared Sub RegistryChanged(ByVal sender As Object, ByVal args As RegistryWatcher.RegistryChangeEventArgs)
If Not String.IsNullOrEmpty(args.Value.ToString()) Then
Registry.SetValue(args.KeyName, args.ValueName, String.Empty)
End If
End Sub
End Class
Public Class RegistryWatcher
Implements IDisposable
Private Const PERIOD As Integer = 30000
Private ReadOnly currentRegValues As Dictionary(Of Tuple(Of String, String), Object)
Private ReadOnly toWatch As Tuple(Of String, String)()
Private ReadOnly timer As Timer
Public Event RegistryChange As EventHandler(Of RegistryChangeEventArgs)
Public Sub New(ParamArray toWatch As Tuple(Of String, String)())
Me.toWatch = toWatch
If toWatch.Length > 0 Then
currentRegValues = toWatch.ToDictionary(Function(key) key, Function(key) Registry.GetValue(key.Item1, key.Item2, Nothing))
timer = New Timer(AddressOf CheckRegistry, Nothing, PERIOD, Timeout.Infinite)
End If
End Sub
Private Sub CheckRegistry(ByVal state As Object)
For Each reg As Tuple(Of String, String) In toWatch
Dim newValue As Object = Registry.GetValue(reg.Item1, reg.Item2, Nothing)
If currentRegValues(reg) <> newValue Then
RegistryChange?.Invoke(Me, New RegistryChangeEventArgs(reg.Item1, reg.Item2, newValue))
currentRegValues(reg) = newValue
End If
Next
timer.Change(PERIOD, Timeout.Infinite)
End Sub
Public Sub Dispose()
Try
timer?.Dispose()
Catch
End Try
End Sub
Public Class RegistryChangeEventArgs
Inherits EventArgs
Public Sub New(ByVal keyName As String, ByVal valueName As String, ByVal value As Object)
KeyName = keyName
ValueName = valueName
Value = value
End Sub
Public ReadOnly Property KeyName As String
Public ReadOnly Property ValueName As String
Public ReadOnly Property Value As Object
End Class
End Class
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In CheckRegistry this does not work:
if (currentRegValues[reg] != newValue)
It is always true even if the values are the same because it is an object.
You must use the object version:
if (!Equals(currentRegValues[reg], newValue))
I saw this when debugging with single step in Visual Studio.