开发者

RasConnectionNotification after computer resumes from sleep

I've got a project called DotRas on CodePlex that exposes a component called RasConnectionWatcher which uses the RasConnectionNotification Win32 API to receive notifications when connections on a machine change. One of my users recently brought to my attention that if the machine comes out of sleep mode, and attempts to redial the connection, the connection goes into a loop indicating the connection is alread开发者_JS百科y being dialed even though it isn't. This loop will not end until the application is restarted, even if done through a synchronous call which all values on the structs are unique for that specific call, and none of it is retained once the call completes.

I've done as much as I can to fix the problem, but I fear the problem is something I've done with the RasConnectionNotification API and using ThreadPool.RegisterWaitForSingleObject which might be blocking something else in Windows.

The below method is used to register 1 of the 4 change types the API supports, and the handle to associate with it to monitor. During runtime, the below method would be called 4 times during initialization to register all 4 change types.

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);
    }
}

The event passed into the API gets signaled when Windows detects a change in the connections on the machine. The callback used just takes the change type registered from the state object and then processes it to determine exactly what changed.

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));
                }
            }
        }
    }
}

Everything works perfectly, other than when the machine comes out of sleep. Now the strange thing is when this happens, if a MessageBox is displayed (even for 1 ms and closed by using SendMessage) it will work. I can only imagine something I've done is blocking something else in Windows so that it can't continue processing while the event is being processed by the component.

I've stripped down a lot of the code here, the full source can be found at: http://dotras.codeplex.com/SourceControl/changeset/view/68525#1344960

I've come for help from people much smarter than myself, I'm outside of my comfort zone trying to fix this problem, any assistance would be greatly appreciated!

Thanks! - Jeff


After a lot of effort, I tracked down the problem. Thankfully it wasn't a blocking issue in Windows.

For those curious, basically once the machine came out of sleep the developer was attempting to immediately dial a connection (via the Disconnected event). Since the network interfaces hadn't finished initializing, an error was returned and the connection handle was not being closed. Any attempts to close the connection would throw an error indicating the connection was already closed, even though it wasn't. Since the handle was left open, any subsequent attempts to dial the connection would cause an actual error.

I just had to make an adjustment in the HangUp code to hide the error thrown when a connection is closed that has already been closed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜