Interoping CDecl callback on 1.1

U

Udi

Hi All,

I have a C dll exporting the following:
````````````````````````````````````````````````````
typedef void (__cdecl *pCallBack)(int i);

int __cdecl Foo(pCallBack pFunc);


I have written an interop dll:
````````````````````````````````````````
public class FooInterop
{
public delegate void pCallBack(int i);

[DllImport("Foo.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int
Foo([MarshalAs(UnmanagedType.FunctionPtr)]pCallBack pFunc);
}

And I'm trying to call it this way:
```````````````````````````````````````````````

class Class1
{
[STAThread]
static void Main(string[] args)
{
int res = FooInterop.Foo(new FooInterop.pCallBack(Class1.FooCB));
Console.WriteLine(res);
}

static public void FooCB(int i)
{
Console.WriteLine(i);
}
}

For some reason when leaving FooCB I get the following error:

"Run-Time Check Failure #0 - The value of ESP was not properly saved
across a function call. This is usually a result of calling a
function declared with one calling convention with a function pointer
declared with a different calling convention."

I'm assuming this is because 'Foo' (in the C dll) is defined as
__cdecl and 'FooCB' (in .NET assembly) is an __stdcall. Am I right?
How do I tell the marsheler that C# method should behave as __cdecl
in .NET 1.1?
How do I solve this problem?
BTW defining the typedef as stdcall (I.e. typedef void (__stdcall
*pCallBack)(int i); )
works OK, but I'm not surethis is the solution I need.
Any ideas?
Thanks!
 
N

Nicholas Paldino [.NET/C# MVP]

Udi,

You can't do this in 1.1. In 2.0 and beyond, you would apply the
UnmanagedFunctionPointer attribute to the delegate parameter to indicate the
calling convention that the delegate should take on.

In .NET 1.1, you will have to create a shim which will take a function
pointer with the same signature (but not using the CDECL convention) and
returns a function pointer using the CDECL calling convention.

It's a bit of a hack, but your only option (unless you can change the
calling convention of the callback).
 
W

Willy Denoyette [MVP]

Udi said:
Hi All,

I have a C dll exporting the following:
````````````````````````````````````````````````````
typedef void (__cdecl *pCallBack)(int i);

int __cdecl Foo(pCallBack pFunc);


I have written an interop dll:
````````````````````````````````````````
public class FooInterop
{
public delegate void pCallBack(int i);

[DllImport("Foo.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int
Foo([MarshalAs(UnmanagedType.FunctionPtr)]pCallBack pFunc);
}

And I'm trying to call it this way:
```````````````````````````````````````````````

class Class1
{
[STAThread]
static void Main(string[] args)
{
int res = FooInterop.Foo(new FooInterop.pCallBack(Class1.FooCB));
Console.WriteLine(res);
}

static public void FooCB(int i)
{
Console.WriteLine(i);
}
}

For some reason when leaving FooCB I get the following error:

"Run-Time Check Failure #0 - The value of ESP was not properly saved
across a function call. This is usually a result of calling a
function declared with one calling convention with a function pointer
declared with a different calling convention."

I'm assuming this is because 'Foo' (in the C dll) is defined as
__cdecl and 'FooCB' (in .NET assembly) is an __stdcall. Am I right?
How do I tell the marsheler that C# method should behave as __cdecl
in .NET 1.1?
How do I solve this problem?
BTW defining the typedef as stdcall (I.e. typedef void (__stdcall
*pCallBack)(int i); )
works OK, but I'm not surethis is the solution I need.

Callbacks should preferably be declared as __stdcall, this is the standard calling
convention for callbacks in windows and is the default in .NET.
So, Yes, this is the solution.
Willy.
 

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