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 / September 2005

Tip: Looking for answers? Try searching our database.

Marshal callback containing unsigned char * in signature

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Brandon - 22 Aug 2005 21:00 GMT
Hello all,
I'm running into a brick wall here. I have a C dll I'm trying to use from my
C# code. I've read a lot on this and can't figure out what is going wrong.
This dll is working from a C program, so I feel it must be something I've
done wrong in the C# client. The main roadblock is on creating a callback. In
the C program the callback is declared (not sure if this is the correct
nomenclature) like this ... (watch for wrapping)...

somefile.h
......

__declspec (dllimport) int __cdecl FunctionX( void (__cdecl *)(int, unsigned
char * ));

......

Then in the c file

#include somefile.h

void __cdecl Callback( int param1, unsigned char * param2 )
{
  ...
}

main()
{
  FunctionX(Callback);
}

This all works fine in the C program. Here is my implementation in C# ...
remember from above that FunctionX requires a function pointer with a void
return type and accepting prameters of type int and unsigned char * .....

........

public delegate void CallbackProc( int param1, IntPtr param2 );
[DllImport("somedll.dll")] public static extern int FunctionX( CallbackProc );

//constructor
MyClass( )
{
  FunctionX( new CallbackProc( CallbackFunc ) );
}

public void CallbackFunc( int param1, IntPtr param2 )
{
  // do some stuff
}

........

This causes memory violations. In lieu of IntPtr I have also tried
StringBuilder and string types as the signature for this callback function.
All result in memory violations. Any ideas? All input appreciated.

-Brandon
Willy Denoyette [MVP] - 22 Aug 2005 23:13 GMT
> Hello all,
> I'm running into a brick wall here. I have a C dll I'm trying to use from
[quoted text clipped - 58 lines]
>
> -Brandon

1. You need to export the C function declaration!
2. Callbacks are by default __stdcall in windows (CALLBACK or WINAPI
macros ) and .NET, not __cdecl.

Herewith a sample to get you started...

// nativecode.cpp
#include <vector>
typedef void (__stdcall *Ptr) (int, unsigned char*);

// export function using C binding without name mangling
extern "C" {
__declspec(dllexport) void __stdcall CallMeBack (Ptr Function);
}
typedef   std::vector<unsigned char> buf;
void __stdcall CallMeBack(Ptr fptr)
{
  buf v1(10, 'a');
  fptr(v1.size(), &v1[0]);
}

// C# file
..
public delegate void SomeFunctionDelegate(int arg1, IntPtr arg2);

class Tester
{
 [DllImport("nativecode.dll")]
 public static extern void CallMeBack(SomeFunctionDelegate f);

 public static void Main()
 {
  SomeFunctionDelegate pd = new SomeFunctionDelegate(SomeMethod);
  CallMeBack(pd);
 }
 static void SomeMethod(int length, IntPtr s)
 {
     byte[] ba = new byte[length];
  Marshal.Copy(s, ba, 0, length);
     foreach(byte b in ba)
       Console.WriteLine(b);
 }
}

Willy.
Brandon - 23 Aug 2005 15:46 GMT
Willy,

Firstly, thanks for the reply. It is much appreciated.

The C function is exported in the dll. This is a third party dll that I'm
trying to incorporate into a piece of software we have written in C#. The 'C'
code that I posted is a few snippets from the sample program that shipped
with thier dll, which is supposed to show how to use the dll. I posted that
simply because I know that it is a working piece of 'C' code to compare to
what I did in C#.

The guys that wrote the dll controlled how these functions got exported, I'm
just trying to consume them. I noticed at the top of their .h file for using
the dll in c++ or 'C', that they do have a preprocessor directive which will
change the declaration of these prototypes between __cdecl and __stdcall
based on a compiler option. Regardless, I've tried changing the calling
convention in the DllImport attibute in my declaration as well, from stdcall
to cdecl. Oddly, this seemed to make no difference.

I've looked at the C# code you posted. As far as I can tell, the only
differences between your code and mine is that you declared your delegate
type outside of the class declaration and your callback function is static. I
made these two modifications to my code and I"m still receiving memory
violations when the dll calls back to my program.

Perhaps a bit more information is needed on what's going on here. What I'm
doing  is incorporating this dll which runs a scanner into a C# windows
application. Everytime this scanner scans a document, it should call back
into my software with a document id in the int parameter and further info
from the document in the unsigned char *. So, in a way, this callback is an
event handler. Anyway, whenever it tries to fire off the callback after
scanning a document, I get a memory violation. I'm pretty sure I've got
everything hooked up correctly, because I can fire off commands to the
scanner such as start and stop. These work fine. The problem is the
communication coming back from the scanner to my program.

I did entertain the notion that the delegate could be getting garbage
collected before the dll called back to it. I believe that would result in a
memory violation. To avoid this I tried creating a class member of my
delegate type and passed that into the dll as the callback. This didn't solve
the problem either.

I'm at my wits end here. I'm sure there is some small overlooked trick that
I'm missing here. If you or anyone else has any further input I'm very open
to suggestions.

Thanks,
Brandon

> > Hello all,
> > I'm running into a brick wall here. I have a C dll I'm trying to use from
[quoted text clipped - 104 lines]
>
> Willy.
Willy Denoyette [MVP] - 23 Aug 2005 17:26 GMT
Brandon,

What's important is the calling convention used by the callback, not the
calling convention used by the exported function. Callbacks are __stdcall by
default  and can't be changed in .NET v1.x, that is the syntesized delegate
function pops the parameters off the stack on return, while the caller
(using the misdeclared __cdecl) does exactly the same.

Compare my sample:
typedef void (__stdcall *Ptr) (int, unsigned char*);

to yours:
__declspec (dllimport) int __cdecl FunctionX( void (__cdecl *)(int, unsigned
char * ));
------------------------------------------------------------------------^
So, you have to change it into:
__declspec (dllimport) int __cdecl FunctionX( void (__stdcall*)(int,
unsigned char * ));

Note, I'm not 100% sure this relates to your problem, but your calling
convention do not match, so this should be corrected anyway.

Willy.

> Willy,
>
[quoted text clipped - 172 lines]
>>
>> Willy.
Stu Mackellar - 01 Sep 2005 17:21 GMT
Guys,

It is possible to change the calling convention for a callback to __cdecl,
but not particularly easy or neat.

See http://www.dotnet247.com/247reference/msgs/17/87210.aspx for details on
how to achieve this. I've successfully used this technique in production
code with no problems. According to a response I had from Microsoft when I
enquired a year or so ago this will also be supported natively from .Net 2.0
onwards.

HTH,

Stu

> Brandon,
>
[quoted text clipped - 199 lines]
>>>
>>> Willy.
Willy Denoyette [MVP] - 01 Sep 2005 19:35 GMT
> Guys,
>
[quoted text clipped - 10 lines]
>
> Stu

Just to confirm that it's supported from v2.0 onwards.
Note that the solution for 1.x is a terrible hack, but so is choosing the
wrong calling convention for windows callbacks a terrible mistake :-).

Willy.

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.