Implementing a Callback function (_cdecl) in VB.NET

G

Guest

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

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_HANDLER)(
const int messageType, const char * message) ;

//This is the native function to be invoked
ErrorCode register(CALLBACK_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(ByVal messageType As Long, ByVal message As
String) As Long
Try
MsgBox(messageType)
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 NullReferenceException 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!
 
K

Ken Tucker [MVP]

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
 
?

=?ISO-8859-2?Q?=A3ukasz?=

kurtcobain1978 said:
--------------------------------------------------------------------------------

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_HANDLER)(
Why can't you change it to __stdcall?
const int messageType, const char * message) ;

//This is the native function to be invoked
ErrorCode register(CALLBACK_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(ByVal messageType As Long, ByVal message As
String) As Long
Try
MsgBox(messageType)
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 NullReferenceException 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!

£ukasz
 
D

Dragon

Hi,

"kurtcobain1978" <[email protected]>
ÓÏÏÂÝÉÌ/ÓÏÏÂÝÉÌÁ × ÎÏ×ÏÓÔÑÈ ÓÌÅÄÕÀÝÅÅ:
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.

Well, I see that in your header it is __cdecl, not _cdecl.
-----------Native Code snippet----------------
typedef ErrorCode (__cdecl * CALLBACK_HANDLER)(
const int messageType, const char * message) ;

//This is the native function to be invoked
ErrorCode register(CALLBACK_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

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_HANDLER ( _
ByVal messageType As Integer, _
<MarshalAs(UnmanagedType.LPStr), [In]()> ByVal message As String _
) As Integer
~
Public Declare Function register Lib "api.dll" (ByVal trafficType As
Integer, ByVal listener As Callback) As Long

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

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

I hope this helps,
Roman
 
G

Guest

Hey Roman,
Thanks for your valuable suggestions. Actually the NullReferenceException
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\thirdpartyapplication.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(UnmanagedType.LPStr), [In]()> ByVal message As String ) As
Integer
---------------------------
Public Function localCallback(ByVal 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.beginSabreTrafficListener(2, cb)
--------------------------
-----------Native Code snippet----------------
typedef ErrorCode (__cdecl * CALLBACK_HANDLER)(
const int messageType, const char * message) ;

//This is the native function to be invoked
ErrorCode register(CALLBACK_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 said:
Hi,

"kurtcobain1978" <[email protected]>
ÓÃÃÂÃÉÌ/ÓÃÃÂÃÉÌà × ÃŽÃ×ÃÓÔÑÈ ÓÌÅÄÕÀÃÃ…Ã…:
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.

Well, I see that in your header it is __cdecl, not _cdecl.
-----------Native Code snippet----------------
typedef ErrorCode (__cdecl * CALLBACK_HANDLER)(
const int messageType, const char * message) ;

//This is the native function to be invoked
ErrorCode register(CALLBACK_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

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_HANDLER ( _
ByVal messageType As Integer, _
<MarshalAs(UnmanagedType.LPStr), [In]()> ByVal message As String _
) As Integer
~
Public Declare Function register Lib "api.dll" (ByVal trafficType As
Integer, ByVal listener As Callback) As Long

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

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

I hope this helps,
Roman
 
G

Guest

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

the native functions are actually..

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

ErrorCode register(const int trafficType, CALLBACK_HANDLER listener);
-----------------------------------

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

Regards.
 
G

Guest

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

Dragon

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_HANDLER __stdcall. All WinAPI callbacks I've been
working with were StdCall ones.

2. Or, try to replace your Declare statement with DllImportAttribute,
and explicitly specify Cdecl via CallingConvention parameter.

Just my thought,
Roman
 
R

Ralph Heger

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:

http://www.flowgroup.fr/tech_sipXtapi_us.htm

and go to

"Interop with the call callback"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top