0
\$\begingroup\$

I am working on replacing a dependency in a library for System.Management and migrating to using Microsoft.Management.Infrastructure as recommended by Microsoft. The issue is that Microsoft.Management.Infrastructue does not have an equivalent for the ManagementEventWatcher class in System.Management. The management event watcher is used in this scenario to monitor for registry changes and perform an action when this occurs. Normally with managment event watcher you could do like below (crude example).

        var query = "SELECT * FROM RegistryValueChangeEvent WHERE " +
                    "Hive = 'HKEY_LOCAL_MACHINE' " +
                    "AND KeyPath = 'SOFTWARE\\\\TESTKEY' " +
                    "AND ValueName = 'TestValue'"; 

        var mgmtWatcher = new ManagementEventWatcher(query);

        mgmtWatcher.EventArrived += MgmtWatcher_EventArrived;

        mgmtWatcher
            .Start();

        Console.ReadLine();

        private static void MgmtWatcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
             Console.WriteLine("Detected");
        }

I have now created the below as a replacement and am wondering if anyone can see any issues or something I am missing.

/// <summary>
///     CimWatcher event args, which contains CimSubscriptionResult
/// </summary>
public class CimWatcherEventArgs : EventArgs
{
    public CimSubscriptionResult CimSubscriptionResult { get; }

    public CimWatcherEventArgs(CimSubscriptionResult cimSubscriptionResult)
    {
        CimSubscriptionResult = cimSubscriptionResult;
    }
}

/// <summary>
///     <para>
///         A public class used to start/stop the subscription to specific indication source,
///         and listen to the incoming indications, event <see cref="EventArrived" />
///         will be raised for each cimindication.
///     </para>
/// </summary>
public class CimWatcher : IDisposable
{
    internal enum CimWatcherStatus
    {
        Default
        , Started
        , Stopped
    }

    //Events
    public event EventHandler<CimWatcherEventArgs> EventArrived = delegate { };

    //Fields
    private object _myLock;
    private bool _isDisposed;
    private CimWatcherStatus _cimWatcherStatus;
    private readonly string _computerName;
    private readonly string _nameSpace;
    private readonly string _queryDialect;
    private readonly string _queryExpression;
    private CimSession _cimSession;
    private CimAsyncMultipleResults<CimSubscriptionResult> _cimObservable;
    private IDisposable _subscription;
    internal static readonly string DefaultNameSpace = @"root\cimv2";
    internal static readonly string DefaultQueryDialect = "WQL";

    /// <summary>
    ///     Initializes a new instance of the <see cref="CimWatcher" /> class.
    /// </summary>
    /// <param name="queryExpression"></param>
    public CimWatcher(string queryExpression)
    {
        if (string.IsNullOrWhiteSpace(queryExpression))
            throw new ArgumentNullException(nameof(queryExpression));

        _nameSpace = DefaultNameSpace;
        _queryDialect = DefaultQueryDialect;
        _queryExpression = queryExpression;

        Initialize();
    }

    /// <summary>
    ///     Initializes a new instance of the <see cref="CimWatcher" /> class.
    /// </summary>
    /// <param name="queryDialect"></param>
    /// <param name="queryExpression"></param>
    public CimWatcher(string queryDialect, string queryExpression)
    {
        if (string.IsNullOrWhiteSpace(queryExpression))
            throw new ArgumentNullException(nameof(queryExpression));

        _nameSpace = DefaultNameSpace;
        _queryDialect = queryDialect ?? DefaultQueryDialect;
        _queryExpression = queryExpression;

        Initialize();
    }

    /// <summary>
    ///     Initializes a new instance of the <see cref="CimWatcher" /> class.
    /// </summary>
    /// <param name="nameSpace"></param>
    /// <param name="queryDialect"></param>
    /// <param name="queryExpression"></param>
    public CimWatcher(string nameSpace, string queryDialect, string queryExpression)
    {
        if (string.IsNullOrWhiteSpace(queryExpression))
            throw new ArgumentNullException(nameof(queryExpression));

        _nameSpace = nameSpace ?? DefaultNameSpace;
        _queryDialect = queryDialect ?? DefaultQueryDialect;
        _queryExpression = queryExpression;

        Initialize();
    }

    /// <summary>
    ///     Initializes a new instance of the <see cref="CimWatcher" /> class.
    /// </summary>
    /// <param name="computerName"></param>
    /// <param name="nameSpace"></param>
    /// <param name="queryDialect"></param>
    /// <param name="queryExpression"></param>
    public CimWatcher(string computerName, string nameSpace, string queryDialect, string queryExpression)
    {
        if (string.IsNullOrWhiteSpace(queryExpression))
            throw new ArgumentNullException(nameof(queryExpression));

        _computerName = computerName;
        _nameSpace = nameSpace ?? DefaultNameSpace;
        _queryDialect = queryDialect ?? DefaultQueryDialect;
        _queryExpression = queryExpression;

        Initialize();
    }

    public void Initialize()
    {
        _cimWatcherStatus = CimWatcherStatus.Default;
        _myLock = new object();

        _cimSession = CimSession
            .Create(_computerName);

        _cimObservable = _cimSession
            .SubscribeAsync(_nameSpace, _queryDialect, _queryExpression);
    }

    private void OnEventArrived(CimWatcherEventArgs cimWatcherEventArgs)
    {
        Volatile
            .Read(ref EventArrived)
            .Invoke(this, cimWatcherEventArgs);
    }

    public void Start()
    {
        lock (_myLock)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(CimWatcher));

            if (_cimWatcherStatus != CimWatcherStatus.Default && _cimWatcherStatus != CimWatcherStatus.Stopped) return;

            _subscription = _cimObservable
                .Subscribe(cimSubscriptionResult => { OnEventArrived(new CimWatcherEventArgs(cimSubscriptionResult)); });

            _cimWatcherStatus = CimWatcherStatus.Started;
        }
    }

    public void Stop()
    {
        lock (_myLock)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(CimWatcher));

            if (_cimWatcherStatus != CimWatcherStatus.Started) return;

            _subscription
                ?.Dispose();

            _cimWatcherStatus = CimWatcherStatus.Stopped;
        }
    }

    public void Dispose()
    {
        _isDisposed = true;
        _subscription?.Dispose();
        _cimSession?.Dispose();
    }
}

And it can be used like below(crude example).

        var query = "SELECT * FROM RegistryValueChangeEvent WHERE " +
                    "Hive = 'HKEY_LOCAL_MACHINE' " +
                    "AND KeyPath = 'SOFTWARE\\\\TESTKEY' " +
                    "AND ValueName = 'TestValue'"; 

        var watcher = 
            new CimWatcher(query);

        watcher.EventArrived += Watcher_EventArrived;

        watcher
            .Start();

        Console.ReadLine();

        private static void Watcher_EventArrived(object sender, CimWatcherEventArgs e)
        {
             Console.WriteLine("Detected");
        }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.