/// <summary>
        /// Cancels a subscription and releases all resources allocated for it.
        /// </summary>
        /// <param name="subscription">The subscription to cancel.</param>
        public void CancelSubscription(ITsCDaSubscription subscription)
        {
            if (subscription == null)
            {
                throw new ArgumentNullException(nameof(subscription));
            }

            lock (this)
            {
                if (server_ == null)
                {
                    throw new NotConnectedException();
                }
                string methodName = "IOPCServer.RemoveGroup";

                // validate argument.
                if (!typeof(Subscription).IsInstanceOfType(subscription))
                {
                    throw new ArgumentException("Incorrect object type.", nameof(subscription));
                }

                // get the subscription state.
                TsCDaSubscriptionState state = subscription.GetState();

                if (!subscriptions_.ContainsKey(state.ServerHandle))
                {
                    throw new ArgumentException("Handle not found.", nameof(subscription));
                }

                subscriptions_.Remove(state.ServerHandle);

                // release all subscription resources.
                subscription.Dispose();

                // invoke COM method.
                try
                {
                    IOPCServer server = BeginComCall <IOPCServer>(methodName, true);
                    server.RemoveGroup((int)state.ServerHandle, 0);

                    if (DCOMCallWatchdog.IsCancelled)
                    {
                        throw new Exception($"{methodName} call was cancelled due to response timeout");
                    }
                }
                catch (Exception e)
                {
                    ComCallError(methodName, e);
                    throw Utilities.Interop.CreateException(methodName, e);
                }
                finally
                {
                    EndComCall(methodName);
                }
            }
        }
        /// <summary>
        /// Dispose(bool disposing) executes in two distinct scenarios.
        /// If disposing equals true, the method has been called directly
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed.
        /// If disposing equals false, the method has been called by the
        /// runtime from inside the finalizer and you should not reference
        /// other objects. Only unmanaged resources can be disposed.
        /// </summary>
        /// <param name="disposing">If true managed and unmanaged resources can be disposed. If false only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!disposed_)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    if (Subscription != null)
                    {
                        Subscription.Dispose();

                        server_      = null;
                        Subscription = null;
                        daItems_     = null;
                    }
                }
                // Release unmanaged resources. If disposing is false,
                // only the following code is executed.
            }
            disposed_ = true;
        }
        /// <summary>
        /// Dispose(bool disposing) executes in two distinct scenarios.
        /// If disposing equals true, the method has been called directly
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed.
        /// If disposing equals false, the method has been called by the
        /// runtime from inside the finalizer and you should not reference
        /// other objects. Only unmanaged resources can be disposed.
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!_disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    if (_subscription != null)
                    {
                        _subscription.Dispose();

                        _server       = null;
                        _subscription = null;
                        _items        = null;
                    }
                }
                // Release unmanaged resources. If disposing is false,
                // only the following code is executed.
            }
            _disposed = true;
        }