DotRas in a console application stop running after the first Dialer_StateChanged event is raised

Oct 11, 2010 at 6:43 PM

Hello, first of all thanks for your hard work on this project.

I'm trying to run the library in a console application and everything is fine until the first "Dialer_StateChanged" event is raised. The ConnectionState appear as "OpenPort" as it should do, but after executing "Console.WriteLine(e.State.ToString)", the application just exit without any exception.

The strange thing is that if I run the same code in a windows form, the application continue running and all the other events are raised until the connection is succesfully established.

Probably I'm missing something, but I really don't know where to look.

Any help would be appreciated.

Thanks

 

My code:

 

Module Module1
       Private connectionAttemptCompleted As Boolean

    Sub Main()
        Dim Dialer As New DotRas.RasDialer
        Dialer.PhoneBookPath = "C:\MyPhoneBook.pbk"
        Dialer.EntryName = "MyEntry" 
        AddHandler Dialer.StateChanged, AddressOf Dialer_StateChanged
        AddHandler Dialer.DialCompleted, AddressOf Dialer_DialCompleted
        Dialer.DialAsync()
    End Sub

    Private Sub Dialer_StateChanged(ByVal sender As Object, ByVal e As DotRas.StateChangedEventArgs)
        Console.WriteLine(e.State.ToString)
    End Sub

    Private Sub Dialer_DialCompleted(ByVal sender As Object, ByVal e As DotRas.DialCompletedEventArgs)
        If (e.Cancelled) Then
            Console.WriteLine("Cancelled!")
        ElseIf (e.TimedOut) Then
            Console.WriteLine("Connection attempt timed out!")
        ElseIf (e.Error IsNot Nothing) Then
            Console.WriteLine(e.Error.ToString())
        ElseIf (e.Connected) Then
            Console.WriteLine("Connection successful!")
        End If

        '  Indicate the connection attempt has completed.
        connectionAttemptCompleted = True
    End Sub

End Module


Coordinator
Oct 11, 2010 at 7:17 PM
Edited Oct 11, 2010 at 7:18 PM

You don't have anything preventing the application thread from exiting main. Console applications terminate once Main has been exited. You can use a mutex, or just call Console.ReadKey after calling DialAsync to keep the application running while it's busy dialing.

Edit: Or you can use the synchronous Dial method instead of using the asynchronous DialAsync method.

Oct 11, 2010 at 7:23 PM

Hi ...  I think everything is ok, you should only remember that the behavoir of a console application is just like that ... Execute the code and exit, when the first event is fired the application will exit (I'm not a guru, is what I think)

Try to call the dialing step in another thread

Module ...

Dim Dialer As New DotRas.RasDialer

Sub Main()
        Dialer.PhoneBookPath = "C:\MyPhoneBook.pbk"
        Dialer.EntryName = "MyEntry"
        AddHandler Dialer.StateChanged, AddressOf Dialer_StateChanged
        AddHandler Dialer.DialCompleted, AddressOf Dialer_DialCompleted

       Dim Thread tr = new thread(DialAsyncProc) // Make the correct declaration in VB.

       tr.start() // start sub thread

      Readkey() // wait for a key to finish the main thread

End Sub

Sub DialAsyncProc

        Dialer.DialAsync()
End Aub

.....

Console.WriteLine // now is not in the main thread so maybe you need to dispatch this to show the info on the screen ...

I hope this help ...

Coordinator
Oct 11, 2010 at 7:58 PM

There is no reason whatsoever to call an asynchronous method from a worker thread. The asynchronous method already handles the threading necessary for it to function in a background thread. The application exiting has nothing to do with an event being raised, it's what is known as a race condition. With asynchronous and multithreaded applications, will the primary thread reach the end of Main before the first event is raised. If you really wanted to get the application to exit once the dialing has completed, here's a quick example that should get you what you need.

Import System.Threading
Import DotRas

Private waitHandle As New ManualResetEvent(false)
Private dialer As New RasDialer

Sub Main()
    AddHandler Me.dialer.DialCompleted, AddressOf Me.dialer_DialCompleted
    AddHandler Me.dialer.StateChanged, AddressOf Me.dialer_StateChanged
    Me.dialer.PhoneBookPath = "C:\MyPhoneBook.pbk"
    Me.dialer.EntryName = "MyEntry"

    ' Begin dialing the connection.
    Me.dialer.DialAsync()

    ' Pause the primary thread, it will be notified to continue processing once the dial completed event is raised.
    Me.waitHandle.WaitOne()
End Sub

Private Sub dialer_StateChanged(ByVal sender As Object, ByVal e As StateChangedEventArgs)
    Console.WriteLine(e.State.ToString())
End Sub

Private Sub dialer_DialCompleted(ByVal sender As Object, ByVal e As DialCompletedEventArgs)
    Me.waitHandle.Set()
End Sub

Starting a background thread is just going to add unnecessary complexity to your application. The above code will keep the application running until the DialCompleted event is raised by the dialer instance.

Oct 11, 2010 at 8:25 PM

Yes, you're right ... to be honest I just try to give a quick answer for help ..but usally I use your recommendation, "waitone" and "set" .... that should be the advice to follow ...

Pure and simple ...

Oct 12, 2010 at 11:49 AM

Thanks for so much faster replies. I missed the fact that running dialer.async() leave the main thread free to continue and exit once done. It's really embarrassing I disturbed you for a so much stupid thing!

Johnatan solution is fine if I need to run additional code on the main thread without waiting for the dialer to complete connection (since my project run in a .NET 4 runtime, probably the new parallel extensions will be a better approach). Also Jeff solution is great if I need to pause the main thread until the dialer complete connection.

Thanks again