Home All Groups Group Topic Archive Search About

VB.NET: RasDial + CallBacks + throwing events = frozen UI?

Author
12 Jun 2006 7:38 PM
bhc
all-

up until just recently, i was fairly sure i'd implemented a RasDial
class in VB.NET complete with a callback to get updated status.  from
this wrapper, when i throw an event back to the calling program, i can
console.writeline the state successfully.  but as soon as i replace
that line with updating the UI, the program freezes, and execution
halts.  no exceptions are thrown or anything (i've got the line in a
try...catch block, but nothing happens), the app just freezes.  in
fact, if i just mouseover the line that causes the problem (in this
case, it's just a simple Me.Text of a form that's calling my object),
the program freezes.  what's amusing is that i can successfully
observe and return Me.Left...i imagine it has something to do with the
RasDial occurring in a separate thread...but it's not working
regardless.

any help would be appreciated, thanks in advance.

relevant sample code:
---
'in a class
    'The callback function for obtaining updated ras states
    Private mRasCallBack As RasDialCallBack = AddressOf RasDialFunc

    Public Function Dial(ByVal Parameters As RASDIALPARAMS) As IntPtr
        Try
            'Declare return value
            Dim lReturn As Int32

            'Declare handle for RAS dial attempt
            Dim lHandle As IntPtr

            'Reset flag that controls whether or not we're done dialing
            mRasDone = False

            'Start dialing
            lReturn = modRASAPI.RasDial(IntPtr.Zero, Nothing,
Parameters, 0, mRasCallBack, lHandle)

            'See if an error occurred
            If lReturn <> 0 Then
                'Get the error message
                Dim lErrString As String =
modRASAPI.DecodeRASErrorNumber(lReturn)

                'Throw the error
                Throw New Exception(lErrString)
            End If

            'Return the handle
            Dial = lHandle
        Catch ex As Exception
            Throw ex
        End Try
    End Function

   Private Function RasDialFunc(ByVal unMsg As Integer, ByVal
rasconnstate As Integer, ByVal dwError As Integer) As Integer
        Try
            'Get the new state
            Dim lState As RasConnState = rasconnstate

            'Throw a state changed event
            RaiseEvent StateChanged(lState, GetConStateSTR(lState))

            'See if we're either connected or disconnected
            Select Case lState
                Case modRASEnums.RasConnState.Connected
                    'Raise a done message
                    ThrowDoneEvent(True, 0, "")

                Case modRASEnums.RasConnState.Disconnected
                    'Raise a done message
                    ThrowDoneEvent(True, 0, "")
            End Select

            'See if an error occurred
            If dwError <> 0 Then
                'First we need to determine what the error is
                Dim lErrorMessage As String
                Try
                    'Attempt to decode the error number
                    lErrorMessage =
modRASAPI.DecodeRASErrorNumber(dwError)
                Catch ex As Exception
                    'Assume the error message, if there was one
                    lErrorMessage = ex.Message
                End Try

                'Raise a done message
                ThrowDoneEvent(False, dwError, lErrorMessage)
            End If

        Catch ex As Exception
            Throw ex
        End Try
    End Function
---
'in the calling program

    Private Sub mRAS_StateChanged(ByVal CurrentState As
pdsRAS.modRASEnums.RasConnState, ByVal CurrentStateStr As String)
Handles mRAS.StateChanged
        Try
            'this line works, and i can see the updated state in the
console
            Console.WriteLine(CurrentState)
            'this line does not work, and the app halts
            Me.Text = CurrentState
        Catch ex As Exception
            Stop
        End Try
    End Sub

Author
12 Jun 2006 11:32 PM
Tom Shelton
bhc wrote:
Show quoteHide quote
> all-
>
> up until just recently, i was fairly sure i'd implemented a RasDial
> class in VB.NET complete with a callback to get updated status.  from
> this wrapper, when i throw an event back to the calling program, i can
> console.writeline the state successfully.  but as soon as i replace
> that line with updating the UI, the program freezes, and execution
> halts.  no exceptions are thrown or anything (i've got the line in a
> try...catch block, but nothing happens), the app just freezes.  in
> fact, if i just mouseover the line that causes the problem (in this
> case, it's just a simple Me.Text of a form that's calling my object),
> the program freezes.  what's amusing is that i can successfully
> observe and return Me.Left...i imagine it has something to do with the
> RasDial occurring in a separate thread...but it's not working
> regardless.

More then likely you are right - it is occuring on a separate thread.
You should check the Me.InvokeRequired propertie in the callback - if
it is true, then you need to call Me.Invoke so that the call is
marshaled to the UI thread...

--
Tom Shelton [MVP]
Author
13 Jun 2006 1:18 PM
bhc
that's what i was afraid of...perhaps you could expand a little bit on
Invoking, as it's definitely not me strong suit...

what i gather, is that i need to have a Sub that updates the form text,
declare a Delegate that has the same signature, and a variable of the
Delegate type that has an AddressOf pointing to the Sub.  what i have
right now....

    Private Delegate Sub DelUpdateTextCallBack(ByVal NewText As String)
    Private x As DelUpdateTextCallBack = AddressOf UpdateText

    Private Sub UpdateText(ByVal NewText As String)
        Me.Text = NewText
        Application.DoEvents()
    End Sub

then in the mRAS_StateChanged above...

            If Me.InvokeRequired Then
                Me.Invoke(x, New Object() {CurrentState})
            End If

i imagine it's not right, as i'm experiencing the same problems already
on the Me.Invoke line, but that was the best i could come up with...

Show quoteHide quote
>
> More then likely you are right - it is occuring on a separate thread.
> You should check the Me.InvokeRequired propertie in the callback - if
> it is true, then you need to call Me.Invoke so that the call is
> marshaled to the UI thread...
>
> --
> Tom Shelton [MVP]
Author
16 Jun 2006 8:04 PM
Tom Shelton
bhc wrote:
Show quoteHide quote
> that's what i was afraid of...perhaps you could expand a little bit on
> Invoking, as it's definitely not me strong suit...
>
> what i gather, is that i need to have a Sub that updates the form text,
> declare a Delegate that has the same signature, and a variable of the
> Delegate type that has an AddressOf pointing to the Sub.  what i have
> right now....
>
>     Private Delegate Sub DelUpdateTextCallBack(ByVal NewText As String)
>     Private x As DelUpdateTextCallBack = AddressOf UpdateText
>
>     Private Sub UpdateText(ByVal NewText As String)
>         Me.Text = NewText
>         Application.DoEvents()
>     End Sub
>
> then in the mRAS_StateChanged above...
>
>             If Me.InvokeRequired Then
>                 Me.Invoke(x, New Object() {CurrentState})
>             End If
>
> i imagine it's not right, as i'm experiencing the same problems already
> on the Me.Invoke line, but that was the best i could come up with...

bhc - did you ever get this sorted out?  I've been sort of out for the
last couple of days...  I got your email, and I came back here to check
if any other answers were offered - apparently not.  I can try and do a
little bit of playing with this at home tonight, if you still need the
help....

--
Tom Shelton [MVP]
Author
21 Jun 2006 5:46 PM
bhc
hi tom - thanks for getting back to me.

turns out this was my fault - although it still doesn't make much sense
to me.  here's the deal...in the calling thread, i started dialing,
then entered a loop where i slept 100 miliseconds at a time.  when the
event came bubbling up from the RasCallBack, any screen update would
cause the program to freeze.  well...all i have to do was throw in a
DoEvents, and it worked.  i imagine the screen wasn't able to update
for whatever reason, and the DoEvents was needed to flush out the
request.  just a guess - like i said, i really don't understand why it
didn't work to begin with...