我在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
我来自比我更聪明的人的帮助,我在我的舒适区域之外试图解决这个问题,我们将非常感谢任何帮助!
谢谢! - 杰夫
答案 0 :(得分:0)
经过大量努力,我追查了这个问题。值得庆幸的是,它不是Windows中的阻塞问题。
对于那些好奇的人,基本上一旦机器进入睡眠状态,开发人员就会尝试立即拨打连接(通过Disconnected事件)。由于网络接口尚未完成初始化,因此返回错误并且未关闭连接句柄。任何关闭连接的尝试都会抛出一个错误,指示连接已经关闭,即使它没有。由于句柄处于打开状态,因此任何后续尝试拨打连接都会导致实际错误。
我只需要在HangUp代码中进行调整,以隐藏已关闭连接时抛出的错误。