Из проекта RegistryMonitor вытащил класс и немного изменил его так:
( смотрим код в ThreadLoop() )
P.S: Сама проблема в конце темы.
Оригинал: _eventNotify.Handle
Замена из оригинала на : _eventNotify.SafeWaitHandle.DangerousGetHandle()
public class RegistryMonitor : IDisposable
{
#region P/Invoke
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegOpenKeyEx(IntPtr hKey, string subKey, uint options, int samDesired,
out IntPtr phkResult);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtree,
RegChangeNotifyFilter dwNotifyFilter, IntPtr hEvent,
bool fAsynchronous);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegCloseKey(IntPtr hKey);
private const int KEY_QUERY_VALUE = 0x0001;
private const int KEY_NOTIFY = 0x0010;
private const int STANDARD_RIGHTS_READ = 0x00020000;
private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
private static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(unchecked((int)0x80000006));
#endregion
#region Event handling
public event EventHandler RegChanged;
protected virtual void OnRegChanged()
{
RegChanged?.Invoke(this, null);
}
public event ErrorEventHandler Error;
protected virtual void OnError(Exception e)
{
Error?.Invoke(this, new ErrorEventArgs(e));
}
#endregion
#region Private member variables
private IntPtr _registryHive;
private string _registrySubName;
private object _threadLock = new object();
private Thread _thread;
private bool _disposed = false;
private ManualResetEvent _eventTerminate = new ManualResetEvent(false);
private RegChangeNotifyFilter _regFilter = RegChangeNotifyFilter.Key | RegChangeNotifyFilter.Attribute |
RegChangeNotifyFilter.Value | RegChangeNotifyFilter.Security;
#endregion
public RegistryMonitor(RegistryKey registryKey)
{
InitRegistryKey(registryKey.Name);
}
public RegistryMonitor(string name)
{
if (name == null || name.Length == 0)
throw new ArgumentNullException("name");
InitRegistryKey(name);
}
public RegistryMonitor(RegistryHive registryHive, string subKey)
{
InitRegistryKey(registryHive, subKey);
}
public RegChangeNotifyFilter RegChangeNotifyFilter
{
get { return _regFilter; }
set
{
lock (_threadLock)
{
if (IsMonitoring)
throw new InvalidOperationException("Monitoring thread is already running");
_regFilter = value;
}
}
}
#region Initialization
private void InitRegistryKey(RegistryHive hive, string name)
{
switch (hive)
{
case RegistryHive.ClassesRoot:
_registryHive = HKEY_CLASSES_ROOT;
break;
case RegistryHive.CurrentConfig:
_registryHive = HKEY_CURRENT_CONFIG;
break;
case RegistryHive.CurrentUser:
_registryHive = HKEY_CURRENT_USER;
break;
case RegistryHive.DynData:
_registryHive = HKEY_DYN_DATA;
break;
case RegistryHive.LocalMachine:
_registryHive = HKEY_LOCAL_MACHINE;
break;
case RegistryHive.PerformanceData:
_registryHive = HKEY_PERFORMANCE_DATA;
break;
case RegistryHive.Users:
_registryHive = HKEY_USERS;
break;
default:
throw new InvalidEnumArgumentException("hive", (int)hive, typeof(RegistryHive));
}
_registrySubName = name;
}
private void InitRegistryKey(string name)
{
var nameParts = name.Split('\\');
switch (nameParts[0])
{
case "HKEY_CLASSES_ROOT":
case "HKCR":
_registryHive = HKEY_CLASSES_ROOT;
break;
case "HKEY_CURRENT_USER":
case "HKCU":
_registryHive = HKEY_CURRENT_USER;
break;
case "HKEY_LOCAL_MACHINE":
case "HKLM":
_registryHive = HKEY_LOCAL_MACHINE;
break;
case "HKEY_USERS":
_registryHive = HKEY_USERS;
break;
case "HKEY_CURRENT_CONFIG":
_registryHive = HKEY_CURRENT_CONFIG;
break;
default:
_registryHive = IntPtr.Zero;
throw new ArgumentException($"The registry hive { nameParts[0] } is not supported", "value");
}
_registrySubName = string.Join("\\", nameParts, 1, nameParts.Length - 1);
}
#endregion
public bool IsMonitoring
{
get { return _thread != null; }
}
public void Start()
{
if (_disposed)
throw new ObjectDisposedException(null, "This instance is already disposed");
lock (_threadLock)
{
if (!IsMonitoring)
{
_eventTerminate.Reset();
_thread = new Thread(new ThreadStart(MonitorThread));
_thread.IsBackground = true;
_thread.Start();
}
}
}
public void Stop()
{
if (_disposed)
throw new ObjectDisposedException(null, "This instance is already disposed");
lock (_threadLock)
{
var thread = _thread;
if (thread != null)
{
_eventTerminate.Set();
thread.Join();
}
}
}
private void Dispose(bool disposing)
{
if (disposing)
GC.SuppressFinalize(this);
Stop();
}
public void Dispose()
{
var Truth = true;
Dispose(Truth);
}
private void MonitorThread()
{
try
{
ThreadLoop();
}
catch (Exception e) { OnError(e); }
_thread = null;
}
private void ThreadLoop()
{
IntPtr registryKey;
int result = RegOpenKeyEx( _registryHive, _registrySubName, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_NOTIFY,out registryKey);
if (result != 0)
throw new Win32Exception(result);
try
{
var _eventNotify = new AutoResetEvent(false);
var waitHandles = new WaitHandle[] { _eventNotify, _eventTerminate };
while (!_eventTerminate.WaitOne(0, true))
{
result = RegNotifyChangeKeyValue(registryKey, true, _regFilter, _eventNotify.SafeWaitHandle.DangerousGetHandle(), true);
if (result != 0) throw new Win32Exception(result);
if (WaitHandle.WaitAny(waitHandles) == 0)
{
OnRegChanged();
}
}
}
finally
{
if (registryKey != IntPtr.Zero)
RegCloseKey(registryKey);
}
}
}
[Flags]
public enum RegChangeNotifyFilter
{
Key = 1,
Attribute = 2,
Value = 4,
Security = 8,
}
}
Теперь само сканирование: (Создал отдельный класс RegMon)
Список для проверки изменение в ветках реестра:
static List<string> RegScan = new List<string>()
{
@"HKEY_CLASSES_ROOT\exefile\shell\runas\command",
@"HKEY_CLASSES_ROOT\zapfile\shell\open\command",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.exe",
@"HKEY_CLASSES_ROOT\.exe",
@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
};
Массив RegistryMonitor
Старт проверки:
public static void StartRegistryMonitor()
{
if (registryMonitors != null) return;
registryMonitors = new RegistryMonitor[RegScan.Count];
for (int i = 0; i < RegScan.Count; i++)
{
Console.WriteLine($"Проверка ветки реестра: {RegScan[i]}");
registryMonitors[i] = new RegistryMonitor(RegScan[i]);
registryMonitors[i].RegChanged += OnRegistryChanged;
registryMonitors[i].Start();
}
}
Уведомление об изменение в ветках реестра:
static void OnRegistryChanged(object sender, EventArgs args)
{
Console.WriteLine("Зафиксировано изменение в реестре.");
}
Запускаю сканирование так:
Task.Factory.StartNew(() => RegMon.StartRegistryMonitor());
Console.Read();
При запуске казалось бы всё работает нормально как и хотелось, но оказалось что он реагирует на любой раздел в реестре а не в определённых ветках реестра из
List<string> RegScan
.
Проблема оказалось в том что если в списке RegScan добавить по определению ветки реестра HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run и.т.д то он реагирует на все разделы в реестре, если убрать этот раздел, то всё работает как нужно.
P.S: Полагаю что косяк в самом классе RegistryUtils.RegistryMonitor.cs
Подскажите что можно заменить чтобы чтобы мой класс реагировал и на другие ветки в разделах реестра.
Виртуальный выделенный сервер (VDS) становится отличным выбором
На разных страницах есть один и тот же блок фиксированной высотыК примеру:
Помогите разобраться где я допустил ошибку или может быть вообще все неправильно написалНужно чтобы получилась такая последовательность:
ПриветВ проекте возникла необходимость использовать JS-шаблонизаторы, но я я понятия не имею, как их использовать даже после изучения документации