tags:

views:

11

answers:

0

Hi all!

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 already 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