|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
The problemLet's assume that the following is presented:
Here is an example: DLL library header filetypedef void (__cdecl *func_type)(int count); TESTLIB_API void __cdecl SetCallback( func_type func ); C# code[DllImport("TestLib.dll",CallingConvention=CallingConvention.Cdecl)] public static extern void SetCallback( MulticastDelegate callback ); What you would do is define a delegate type: public delegate void CallbackDelegate( int count );
and pass an instance of it to the unmanaged function. [STAThread]
static void Main(string[] args)
{
CallbackDelegate del = new CallbackDelegate( Callback );
SetCallback( del );
}
private static void Callback( int count )
{
Console.WriteLine( "Callback invoked for " +
count + " time" );
}
Then your delegate should be invoked one or more times. The problem is that the function pointer that the unmanaged function accepts should respect the C calling convention but the delegate instance you pass to it does not (it respects the standard calling convention ( Description of the same problem can be found here. Note that the problem exists only for callback functions that accept parameters. SolutionThe solution can be found here and here. The solution is (as the above posts suggest) apply modification option on the " .method public hidebysig virtual instance native int
modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
Invoke(int32 cb) runtime managed
{
} // end of method ...::Invoke
The original method generated by the C# and VB compilers look like this: .method public hidebysig virtual instance native int
Invoke(int32 cb) runtime managed
{
} // end of method ...::Invoke
(without modification option) This cannot be done directly in your code as there is no way to specify modification options (or at least modification options that concern calling conventions) in C# and VB. The drawback of the solution is that you need to disassemble your assembly, add the modification option and compile it. This is not a big deal, but what if you can apply the solution at run-time without the need to disassemble and recompile the code! Run-time delegate type generationThe solution presented in this article does exactly the same but at run-time by generating the delegate types: it allows you to generate and use delegate types for any method. More specifically it:
However, something is not implemented: a delegate generated by C# or VB compiler can have marshaling information on parameters. If you apply Using the solutionTo obtain a delegate instance simply invoke one of the To make the delegate generation transparent to your code you can use the code like this: /// <summary>
/// Callback delegate.
/// </summary>
public delegate void CallbackDelegate( int count );
/// <summary>
/// Sets specified callback method.
/// </summary>
/// <param name="callback"></param>
public static void SetCallback( CallbackDelegate callback )
{
SetCallback( DelegateGenerator.CreateDelegate( callback ) );
}
/// <summary>
/// Sets specified callback method.
/// </summary>
/// <param name="callback"></param>
[DllImport("TestLib.dll",
CallingConvention=CallingConvention.Cdecl)]
private static extern void SetCallback(
MulticastDelegate callback );
You expose a delegate type and a "proxy" method that accepts an instance of that delegate type and passes adjusted version of it to the imported method. ImplementationDelegate types are generated by using the types declared in the Source code and demoThe source code includes the There are two demo projects implemented in C# and VB that demonstrate the usage of generated delegate and normal delegate. Usage of normal delegate leads to stack corruption and The demo includes C++ unmanaged library.
|
||||||||||||||||||||||