Implementing a Callback function (_cdecl) in VB.NET

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • kurtcobain1978

    #1

    Implementing a Callback function (_cdecl) in VB.NET



    --------------------------------------------------------------------------------

    I need to do the exactly same thing in VB.NET.

    Load a unmanaged C DLL dynamically and then call a function in which I pass
    the callback function as an argument. My C function being called callback as
    type _cdecl.

    Does anybody have any ideas?

    Here is what I am trying to do:

    -----------Native Code snippet----------------
    typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
    const int messageType, const char * message) ;

    //This is the native function to be invoked
    ErrorCode register(CALLBA CK_HANDLER messageHandler, const char * parameters);
    ----------------------------------------------

    -------------VB.NET code snippet-------------

    .......
    Module CallbackHandler
    Public Delegate Function Callback(ByVal messageType As Long, ByVal message
    As String) As Long
    Public Declare Function register Lib "api.dll" (ByVal trafficType As
    Integer, ByVal listener As Callback) As Long
    End Module
    ......

    .......
    Public Function myCallback(ByVa l messageType As Long, ByVal message As
    String) As Long
    Try
    MsgBox(messageT ype)
    MsgBox(message)
    Catch ex As Exception
    'MsgBox(ex)
    Finally
    End Try
    End Function
    ......
    ......
    Dim cb As CallbackHandler .myCallback
    cb = AddressOf myCallback
    CallBackHandler .register(2, cb)
    .......
    ----------------------------------------------

    However I keep getting the error NullReferenceEx ception which I guess is
    because my native declaration is _cdecl while I'm trying to make a _stdcall.

    Any help would be greatly appreciated.

    Peace!
  • Ken Tucker [MVP]

    #2
    Re: Implementing a Callback function (_cdecl) in VB.NET

    Hi,

    Two things. First the unmanaged long is the same as the managed
    integer. I would change the longs to integer. Second you sometimes get a
    null reference error when passing a parameter byval when it should be byref.
    Since the message is a pointer to char try using byref.

    Ken
    ------------------------------
    "kurtcobain1978 " <kurtcobain1978 @discussions.mi crosoft.com> wrote in message
    news:B624693C-B075-4C49-9801-88E18ED97408@mi crosoft.com...[color=blue]
    >
    >
    > --------------------------------------------------------------------------------
    >
    > I need to do the exactly same thing in VB.NET.
    >
    > Load a unmanaged C DLL dynamically and then call a function in which I
    > pass
    > the callback function as an argument. My C function being called callback
    > as
    > type _cdecl.
    >
    > Does anybody have any ideas?
    >
    > Here is what I am trying to do:
    >
    > -----------Native Code snippet----------------
    > typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
    > const int messageType, const char * message) ;
    >
    > //This is the native function to be invoked
    > ErrorCode register(CALLBA CK_HANDLER messageHandler, const char *
    > parameters);
    > ----------------------------------------------
    >
    > -------------VB.NET code snippet-------------
    >
    > ......
    > Module CallbackHandler
    > Public Delegate Function Callback(ByVal messageType As Long, ByVal message
    > As String) As Long
    > Public Declare Function register Lib "api.dll" (ByVal trafficType As
    > Integer, ByVal listener As Callback) As Long
    > End Module
    > .....
    >
    > ......
    > Public Function myCallback(ByVa l messageType As Long, ByVal message As
    > String) As Long
    > Try
    > MsgBox(messageT ype)
    > MsgBox(message)
    > Catch ex As Exception
    > 'MsgBox(ex)
    > Finally
    > End Try
    > End Function
    > .....
    > .....
    > Dim cb As CallbackHandler .myCallback
    > cb = AddressOf myCallback
    > CallBackHandler .register(2, cb)
    > ......
    > ----------------------------------------------
    >
    > However I keep getting the error NullReferenceEx ception which I guess is
    > because my native declaration is _cdecl while I'm trying to make a
    > _stdcall.
    >
    > Any help would be greatly appreciated.
    >
    > Peace![/color]


    Comment

    • £ukasz

      #3
      Re: Implementing a Callback function (_cdecl) in VB.NET

      kurtcobain1978 wrote:[color=blue]
      >
      > --------------------------------------------------------------------------------
      >
      > I need to do the exactly same thing in VB.NET.
      >
      > Load a unmanaged C DLL dynamically and then call a function in which I pass
      > the callback function as an argument. My C function being called callback as
      > type _cdecl.
      >
      > Does anybody have any ideas?
      >
      > Here is what I am trying to do:
      >
      > -----------Native Code snippet----------------
      > typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)([/color]
      Why can't you change it to __stdcall?[color=blue]
      > const int messageType, const char * message) ;
      >
      > //This is the native function to be invoked
      > ErrorCode register(CALLBA CK_HANDLER messageHandler, const char * parameters);
      > ----------------------------------------------
      >
      > -------------VB.NET code snippet-------------
      >
      > ......
      > Module CallbackHandler
      > Public Delegate Function Callback(ByVal messageType As Long, ByVal message
      > As String) As Long
      > Public Declare Function register Lib "api.dll" (ByVal trafficType As
      > Integer, ByVal listener As Callback) As Long
      > End Module
      > .....
      >
      > ......
      > Public Function myCallback(ByVa l messageType As Long, ByVal message As
      > String) As Long
      > Try
      > MsgBox(messageT ype)
      > MsgBox(message)
      > Catch ex As Exception
      > 'MsgBox(ex)
      > Finally
      > End Try
      > End Function
      > .....
      > .....
      > Dim cb As CallbackHandler .myCallback
      > cb = AddressOf myCallback
      > CallBackHandler .register(2, cb)
      > ......
      > ----------------------------------------------
      >
      > However I keep getting the error NullReferenceEx ception which I guess is
      > because my native declaration is _cdecl while I'm trying to make a _stdcall.
      >
      > Any help would be greatly appreciated.
      >
      > Peace![/color]

      £ukasz

      Comment

      • Dragon

        #4
        Re: Implementing a Callback function (_cdecl) in VB.NET

        Hi,

        "kurtcobain1978 " <kurtcobain1978 @discussions.mi crosoft.com>
        ÓÏÏÂÝÉÌ/ÓÏÏÂÝÉÌÁ × ÎÏ×ÏÓÔÑÈ ÓÌÅÄÕÀÝÅÅ:
        news:B624693C-B075-4C49-9801-88E18ED97408@mi crosoft.com...
        [color=blue]
        > Load a unmanaged C DLL dynamically and then call a function in which I[/color]
        pass[color=blue]
        > the callback function as an argument. My C function being called[/color]
        callback as[color=blue]
        > type _cdecl.[/color]

        Well, I see that in your header it is __cdecl, not _cdecl.
        [color=blue]
        > -----------Native Code snippet----------------
        > typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
        > const int messageType, const char * message) ;
        >
        > //This is the native function to be invoked
        > ErrorCode register(CALLBA CK_HANDLER messageHandler, const char *[/color]
        parameters);[color=blue]
        > ----------------------------------------------
        >
        > -------------VB.NET code snippet-------------
        >
        > ......
        > Module CallbackHandler
        > Public Delegate Function Callback(ByVal messageType As Long, ByVal[/color]
        message[color=blue]
        > As String) As Long[/color]

        C'ish int is Integer in VB .NET, and I guess ErrorCode too, so you'll
        probably have to try this:


        ~
        Public Delegate Function CALLBACK_HANDLE R ( _
        ByVal messageType As Integer, _
        <MarshalAs(Unma nagedType.LPStr ), [In]()> ByVal message As String _
        ) As Integer
        ~
        [color=blue]
        > Public Declare Function register Lib "api.dll" (ByVal trafficType As
        > Integer, ByVal listener As Callback) As Long[/color]

        I thought first parameter was a CALLBACK_HANDLE R there, and second an
        LPSTR, wasn't it?
        If so, declaration would be

        ~
        Public Declare Function register Lib "api.dll" ( _
        ByVal messageHandler As CALLBACK_HANDLE R, _
        <MarshalAs(Unma nagedType.LPStr ), [In]()> ByVal parameters As String,
        _
        ) As Integer
        ~

        I hope this helps,
        Roman


        Comment

        • kurtcobain1978

          #5
          Re: Implementing a Callback function (_cdecl) in VB.NET

          Hey Roman,
          Thanks for your valuable suggestions. Actually the NullReferenceEx ception
          seems to be because of Integer/Long type like you mentioned (atleast thats
          what I could figure)

          My callback method does get called but then I get a debug error that says :

          ----------------------------------------------------
          Debug Error

          "..\bin\thirdpa rtyapplication. exe"
          File i386\chkesp.c
          line 42

          The value of ESP was not property saved across a function call. This is
          usually a result of calling a function declated with one calling convention
          with a function pointer declated with a different calling convention.

          (Please retry to debug)
          -----------------------------------------------

          However looks like the the Marshalling didn't work.. or... ????? I am all
          lost here. Looks like while trying to modify the method names, I goofed up in
          stating the methods signatures properly earlier.

          Now this is what I am using after the change:
          -------------------------------------
          Public Declare Function register Lib "api.dll" ( _
          ByVal traffictype As Integer, ByVal messageHandler As Callback) As Integer

          Public Delegate Function Callback( _
          ByVal messageType As Integer, _
          <MarshalAs(Unma nagedType.LPStr ), [In]()> ByVal message As String ) As
          Integer
          ---------------------------
          Public Function localCallback(B yVal messageType As Integer, ByVal
          message As String) As Integer
          Try
          txtMessageArea. Text = message
          Catch ex As Exception
          MsgBox(ex)
          localCallback=1
          End Try
          localCallback=0
          End Function
          --------------------------
          Dim cb As CallBackHandler .Callback
          cb = AddressOf localCallback
          CallBackHandler .beginSabreTraf ficListener(2, cb)
          --------------------------
          -----------Native Code snippet----------------
          typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
          const int messageType, const char * message) ;

          //This is the native function to be invoked
          ErrorCode register(CALLBA CK_HANDLER messageHandler, const char *
          parameters);
          ----------------------------------------------

          [and you were right, it is __cdecl and not _cdecl]

          The return value in localCallback does get printed in the textarea correctly
          but then after that I get a debug error (above) and the application
          terminates. Is it possible that because the returning (callback) argument is
          a string, its not able to find the string terminator or something because the
          response seems to be complete yet it throws an exception.
          Will await your inputs.

          Regards,
          Danny


          "Dragon" wrote:
          [color=blue]
          > Hi,
          >
          > "kurtcobain1978 " <kurtcobain1978 @discussions.mi crosoft.com>
          > ÓÏÏÂÝÉÌ/ÓÏÏÂÝÉÌà  × ÎÏ×ÏÓÔÑà ˆ ÓÌÅÄÕÀÝà …Ã…:
          > news:B624693C-B075-4C49-9801-88E18ED97408@mi crosoft.com...
          >[color=green]
          > > Load a unmanaged C DLL dynamically and then call a function in which I[/color]
          > pass[color=green]
          > > the callback function as an argument. My C function being called[/color]
          > callback as[color=green]
          > > type _cdecl.[/color]
          >
          > Well, I see that in your header it is __cdecl, not _cdecl.
          >[color=green]
          > > -----------Native Code snippet----------------
          > > typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
          > > const int messageType, const char * message) ;
          > >
          > > //This is the native function to be invoked
          > > ErrorCode register(CALLBA CK_HANDLER messageHandler, const char *[/color]
          > parameters);[color=green]
          > > ----------------------------------------------
          > >
          > > -------------VB.NET code snippet-------------
          > >
          > > ......
          > > Module CallbackHandler
          > > Public Delegate Function Callback(ByVal messageType As Long, ByVal[/color]
          > message[color=green]
          > > As String) As Long[/color]
          >
          > C'ish int is Integer in VB .NET, and I guess ErrorCode too, so you'll
          > probably have to try this:
          >
          >
          > ~
          > Public Delegate Function CALLBACK_HANDLE R ( _
          > ByVal messageType As Integer, _
          > <MarshalAs(Unma nagedType.LPStr ), [In]()> ByVal message As String _
          > ) As Integer
          > ~
          >[color=green]
          > > Public Declare Function register Lib "api.dll" (ByVal trafficType As
          > > Integer, ByVal listener As Callback) As Long[/color]
          >
          > I thought first parameter was a CALLBACK_HANDLE R there, and second an
          > LPSTR, wasn't it?
          > If so, declaration would be
          >
          > ~
          > Public Declare Function register Lib "api.dll" ( _
          > ByVal messageHandler As CALLBACK_HANDLE R, _
          > <MarshalAs(Unma nagedType.LPStr ), [In]()> ByVal parameters As String,
          > _
          > ) As Integer
          > ~
          >
          > I hope this helps,
          > Roman
          >
          >
          >[/color]

          Comment

          • kurtcobain1978

            #6
            Re: Implementing a Callback function (_cdecl) in VB.NET

            Oo I'm so sorry.. i made a mistake again..

            the native functions are actually..

            -----------------------------
            typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
            const SABREAPICODE messageType, const char * message
            ) ;

            ErrorCode register(const int trafficType, CALLBACK_HANDLE R listener);
            -----------------------------------

            I'm sleep depreived till I get this done.. so please don't blame me for
            creating all the confusion. :)

            Regards.

            "kurtcobain1978 " wrote:
            [color=blue]
            > Hey Roman,
            > Thanks for your valuable suggestions. Actually the NullReferenceEx ception[/color]

            Comment

            • kurtcobain1978

              #7
              Re: Implementing a Callback function (_cdecl) in VB.NET

              Thanks for your feedback Ken. Please read the message that I have posted. You
              and Roman might be able to help me.


              "Ken Tucker [MVP]" wrote:
              [color=blue]
              > Hi,
              >
              > Two things. First the unmanaged long is the same as the managed
              > integer. I would change the longs to integer. Second you sometimes get a
              > null reference error when passing a parameter byval when it should be byref.
              > Since the message is a pointer to char try using byref.
              >
              > Ken
              > ------------------------------
              > "kurtcobain1978 " <kurtcobain1978 @discussions.mi crosoft.com> wrote in message
              > news:B624693C-B075-4C49-9801-88E18ED97408@mi crosoft.com...[color=green]
              > >
              > >
              > > --------------------------------------------------------------------------------
              > >
              > > I need to do the exactly same thing in VB.NET.
              > >
              > > Load a unmanaged C DLL dynamically and then call a function in which I
              > > pass
              > > the callback function as an argument. My C function being called callback
              > > as
              > > type _cdecl.
              > >
              > > Does anybody have any ideas?
              > >
              > > Here is what I am trying to do:
              > >
              > > -----------Native Code snippet----------------
              > > typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
              > > const int messageType, const char * message) ;
              > >
              > > //This is the native function to be invoked
              > > ErrorCode register(CALLBA CK_HANDLER messageHandler, const char *
              > > parameters);
              > > ----------------------------------------------
              > >
              > > -------------VB.NET code snippet-------------
              > >
              > > ......
              > > Module CallbackHandler
              > > Public Delegate Function Callback(ByVal messageType As Long, ByVal message
              > > As String) As Long
              > > Public Declare Function register Lib "api.dll" (ByVal trafficType As
              > > Integer, ByVal listener As Callback) As Long
              > > End Module
              > > .....
              > >
              > > ......
              > > Public Function myCallback(ByVa l messageType As Long, ByVal message As
              > > String) As Long
              > > Try
              > > MsgBox(messageT ype)
              > > MsgBox(message)
              > > Catch ex As Exception
              > > 'MsgBox(ex)
              > > Finally
              > > End Try
              > > End Function
              > > .....
              > > .....
              > > Dim cb As CallbackHandler .myCallback
              > > cb = AddressOf myCallback
              > > CallBackHandler .register(2, cb)
              > > ......
              > > ----------------------------------------------
              > >
              > > However I keep getting the error NullReferenceEx ception which I guess is
              > > because my native declaration is _cdecl while I'm trying to make a
              > > _stdcall.
              > >
              > > Any help would be greatly appreciated.
              > >
              > > Peace![/color]
              >
              >
              >[/color]

              Comment

              • Dragon

                #8
                Re: Implementing a Callback function (_cdecl) in VB.NET

                Hi Danny,

                First I have to disappoint you — I'm not an C expert, and thus I don't
                know much about calling conventions.
                Second, if ErrorCode and SABREAPICODE are int's (long's, INT's, LONG's
                etc.) than it seems that your declarations are correct.

                I don't know if .NET supports Cdecl callbacks, but you may try the
                following.

                1. Make CALLBACK_HANDLE R __stdcall. All WinAPI callbacks I've been
                working with were StdCall ones.

                2. Or, try to replace your Declare statement with DllImportAttrib ute,
                and explicitly specify Cdecl via CallingConventi on parameter.

                Just my thought,
                Roman


                Comment

                • Ralph Heger

                  #9
                  Re: Implementing a Callback function (_cdecl) in VB.NET

                  the difference between stdcall and cdecl is the handling of stack, return
                  values, and so you app crashes. .NET knows how to handle cdecl, but you
                  can't declare it. The only way I found is doing that directly in IL. See the
                  example in:

                  GL CONSEIL, éditeur du progiciel ERP Flow Group et services informatique pour les PME


                  and go to

                  "Interop with the call callback"




                  "kurtcobain1978 " <kurtcobain1978 @discussions.mi crosoft.com> schrieb im
                  Newsbeitrag news:B624693C-B075-4C49-9801-88E18ED97408@mi crosoft.com...[color=blue]
                  >
                  >
                  > --------------------------------------------------------------------------------
                  >
                  > I need to do the exactly same thing in VB.NET.
                  >
                  > Load a unmanaged C DLL dynamically and then call a function in which I
                  > pass
                  > the callback function as an argument. My C function being called callback
                  > as
                  > type _cdecl.
                  >
                  > Does anybody have any ideas?
                  >
                  > Here is what I am trying to do:
                  >
                  > -----------Native Code snippet----------------
                  > typedef ErrorCode (__cdecl * CALLBACK_HANDLE R)(
                  > const int messageType, const char * message) ;
                  >
                  > //This is the native function to be invoked
                  > ErrorCode register(CALLBA CK_HANDLER messageHandler, const char *
                  > parameters);
                  > ----------------------------------------------
                  >
                  > -------------VB.NET code snippet-------------
                  >
                  > ......
                  > Module CallbackHandler
                  > Public Delegate Function Callback(ByVal messageType As Long, ByVal message
                  > As String) As Long
                  > Public Declare Function register Lib "api.dll" (ByVal trafficType As
                  > Integer, ByVal listener As Callback) As Long
                  > End Module
                  > .....
                  >
                  > ......
                  > Public Function myCallback(ByVa l messageType As Long, ByVal message As
                  > String) As Long
                  > Try
                  > MsgBox(messageT ype)
                  > MsgBox(message)
                  > Catch ex As Exception
                  > 'MsgBox(ex)
                  > Finally
                  > End Try
                  > End Function
                  > .....
                  > .....
                  > Dim cb As CallbackHandler .myCallback
                  > cb = AddressOf myCallback
                  > CallBackHandler .register(2, cb)
                  > ......
                  > ----------------------------------------------
                  >
                  > However I keep getting the error NullReferenceEx ception which I guess is
                  > because my native declaration is _cdecl while I'm trying to make a
                  > _stdcall.
                  >
                  > Any help would be greatly appreciated.
                  >
                  > Peace![/color]


                  Comment

                  Working...