Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / June 2004

Tip: Looking for answers? Try searching our database.

Having CLR trouble with a callback function

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Joe Kaplan \(MVP - ADSI\) - 16 Jun 2004 16:35 GMT
Hi all,

I'm having problems with a delegate used as a function pointer in a pinvoke method that takes a callback function.  When I supply a delegate, the CLR seems to just die on me.  By die, the symptom is that during my NUnit test, NUnit simply stops running and disappears.  No catchable exception seems to be thrown.  I'm haven't tried writing a quick console app to see if I can get more details on any exceptions thrown.

the sequence of events is that when I call the vendor unmanaged function, my callback function is called twice (I'm expecting about 15 calls total).  As I leave the function the second time, NUnit simply crashes (no error or anything).  If I pass in a null reference for the callback, everything works fine.  It looks some kind of weird corruption in the CLR or something, but I really don't know.

Things I've tried so far that didn't work:
- GC.KeepAlive on the callback delegate instance.  However, this shouldn't be needed (I don't think) as the calling class has a reference to it so it should not be collected
- Played with the marshaling behavior on the delegate signature with MarshalAs(UnmanagedType.LpStr)

If anyone has any ideas where I should be looking, I'd be very grateful.

Joe K.

----------------------
More details
----------------------

I'm creating a wrapper for a vendor C API using pinvoke.   The API in question takes a function pointer like so:
(all parameter and function names changed to protect the innocent)

int doSomeStuff(
const char * const string1,
const char * const string2,
const char * const string3,
const char * const string4,
const char * const string5,
void (*logCallback)(const char *),
bool bool1,
char **outData);

The signature for the callback function looks like this:

void doLog(const char *message)

It is essentially used for me to intercept trace messages so I can get detailed failure (or success) info.

My managed signatures look like this:
------------------------
<DllImport("vendor.dll", CharSet:=CharSet.Ansi)> _
Private Shared Function doSomeStuff( _
   ByVal string1 As String, _
   ByVal string2 As String, _
   ByVal string3 As String, _
   ByVal string4 As String, _
   ByVal string5 As String, _
   ByVal logCallback As VendorLogCallback, _
   ByVal bool1 As Boolean, _
   ByRef outData As IntPtr _
   ) As Integer
End Function

'note that outData is defined as IntPtr instead of using StringBuilder because I need to use
'the vendors function to free the memory and need the pointer later.  

Friend Delegate Sub VendorLogCallback(ByVal message As String)

'This is the wrapper function that calls the vendor API.  parameters and variable names changed again
Private Shared Function VendorDoStuff( _
   ByVal string1 As String, _
   ByVal string2 As String, _
   ByVal string3 As String, _
   ByVal string4 As String, _
   ByVal string5 As String, _
   ByVal callBack As VendorLogCallback, _
   ByVal message As StringBuilder _
   ) As String

   Dim returnValue As Integer
   Dim returnPtr As IntPtr = IntPtr.Zero
   Dim returnString As String

   returnValue = doSomeStuff(string1, string2, string3, string4, string5, callBack, True, returnPtr)

   If returnValue = 0 Then
If returnPtr.Equals(IntPtr.Zero) Then
   'API did not make a change
   returnString = string1
Else
   'API did make a change!
   returnString = Marshal.PtrToStringAnsi(returnPtr)
   freeReturnData(returnPtr)
End If
   Else
Throw New InvalidOperationException("Stuff didn't work.  I'd like to know what the callback logger said..."))
   End If

   Return returnString

End Function

'this is the method that is the delegate instance above.  _messages is a stringbuilder field in my class
Private Sub LogCallback(ByVal message As String)
   _messages.Append(message)
End Sub
----------------
In the wrapper function, the callback delegate instance is an instance field in the containing class, so it has a root and should not be collected.  The StringBuilder that is passed in is the instance where the logger method sticks the data from callback function.
Mattias Sj?gren - 16 Jun 2004 16:54 GMT
Joe,

>If anyone has any ideas where I should be looking, I'd be very grateful.

My first guess is that it's a calling convention issue. Delegates are
stdcall by default, but your logCallback probably uses the cdecl
calling convention.

For more details on this see
http://groups.google.com/groups?selm=ew6mLkV6BHA.1932%40tkmsftngp03

I'd also recommend enabling CDP if you're running on v1.1 of the
framework, it can be a great help for problems like this.

http://blogs.msdn.com/adam_nathan/archive/2003/05/13/56680.aspx
http://blogs.msdn.com/adam_nathan/archive/2003/05/21/56690.aspx
http://blogs.msdn.com/adam_nathan/archive/2003/06/01/56693.aspx

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Joe Kaplan \(MVP - ADSI\) - 17 Jun 2004 05:03 GMT
Thanks for the tip.  After I posted, I found some more stuff on the web that
started to indicate that the calling convention thing might be at fault.
I'll check out CLR SPY too to make sure.

Luckily, this is custom code from the vendor that we are testing right now,
so it might not be hard for me to convince them to redefine the API for
__stdcall as I doubt it causes them any trouble.  This is definitely better
than hacking the IL (although that probably could be made to work too via
NAnt).

Thanks again,

Joe K.

> Joe,
>
[quoted text clipped - 15 lines]
>
> Mattias

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.