计算机从睡眠状态恢复后RasConnectionNotification

时间:2010-10-28 15:22:37

标签: c# winapi

我在CodePlex上有一个名为DotRas的项目,该项目公开了一个名为RasConnectionWatcher的组件,该组件使用RasConnectionNotification Win32 API在计算机上的连接发生更改时接收通知。我的一位用户最近引起了我的注意,如果机器退出睡眠模式,并尝试重拨连接,则连接进入一个循环,表明连接已经被拨打,即使它没有。在重新启动应用程序之前,此循环不会结束,即使通过同步调用完成,结构上的所有值对于该特定调用都是唯一的,并且一旦调用完成,它们都不会保留。

我已尽力解决问题,但我担心这个问题是我使用RasConnectionNotification API并使用ThreadPool.RegisterWaitForSingleObject完成的,这可能会阻止Windows中的其他内容。

以下方法用于注册API支持的4种更改类型中的1种,以及与其关联以监视的句柄。在运行期间,在初始化期间将调用以下方法4次以注册所有4种更改类型。

private void Register(NativeMethods.RASCN changeType, RasHandle handle)
{
    AutoResetEvent waitObject = new AutoResetEvent(false);

    int ret = SafeNativeMethods.Instance.RegisterConnectionNotification(handle, waitObject.SafeWaitHandle, changeType);
    if (ret == NativeMethods.SUCCESS)
    {
        RasConnectionWatcherStateObject stateObject = new RasConnectionWatcherStateObject(changeType);

        stateObject.WaitObject = waitObject;
        stateObject.WaitHandle = ThreadPool.RegisterWaitForSingleObject(waitObject, new WaitOrTimerCallback(this.ConnectionStateChanged), stateObject, Timeout.Infinite, false);

        this._stateObjects.Add(stateObject);
    }
}

当Windows检测到计算机上的连接发生更改时,传递给API的事件会发出信号。使用的回调只接受从状态对象注册的更改类型,然后对其进行处理以确定更改的确切内容。

private void ConnectionStateChanged(object obj, bool timedOut)
{
    lock (this.lockObject)
    {
        if (this.EnableRaisingEvents)
        {
            try
            {
                    // Retrieve the active connections to compare against the last state that was checked.
                    ReadOnlyCollection<RasConnection> connections = RasConnection.GetActiveConnections();
                    RasConnection connection = null;

                    switch (((RasConnectionWatcherStateObject)obj).ChangeType)
                    {
                        case NativeMethods.RASCN.Disconnection:
                            connection = FindEntry(this._lastState, connections);
                            if (connection != null)
                            {
                                this.OnDisconnected(new RasConnectionEventArgs(connection));
                            }

                            if (this.Handle != null)
                            {
                                // The handle that was being monitored has been disconnected.
                                this.Handle = null;
                            }

                            this._lastState = connections;

                            break;
                    }
                }
                catch (Exception ex)
                {
                    this.OnError(new System.IO.ErrorEventArgs(ex));
                }
            }
        }
    }
}

除了机器从睡眠中醒来之外,一切都很完美。现在奇怪的是,当发生这种情况时,如果显示一个MessageBox(即使是1毫秒并通过使用SendMessage关闭),它也会起作用。我只能想象我所做的是在Windows中阻止其他内容,以便在组件处理事件时无法继续处理。

我在这里删除了很多代码,完整的源代码可以在以下位置找到: http://dotras.codeplex.com/SourceControl/changeset/view/68525#1344960

我来自比我更聪明的人的帮助,我在我的舒适区域之外试图解决这个问题,我们将非常感谢任何帮助!

谢谢! - 杰夫

1 个答案:

答案 0 :(得分:0)

经过大量努力,我追查了这个问题。值得庆幸的是,它不是Windows中的阻塞问题。

对于那些好奇的人,基本上一旦机器进入睡眠状态,开发人员就会尝试立即拨打连接(通过Disconnected事件)。由于网络接口尚未完成初始化,因此返回错误并且未关闭连接句柄。任何关闭连接的尝试都会抛出一个错误,指示连接已经关闭,即使它没有。由于句柄处于打开状态,因此任何后续尝试拨打连接都会导致实际错误。

我只需要在HangUp代码中进行调整,以隐藏已关闭连接时抛出的错误。