我目前正在研究互操作相关的问题,并编写了一个小测试程序,以帮助我弄清楚发生了什么(有问题涉及调用更复杂的本机函数,并且很难发布这里)。
无论如何,我有一个非常简单的本机dll,它只包含以下代码:
extern "C" __declspec(dllexport) void Foo( int* arr, int size );
void Foo( int* arr, int size )
{
for( int i = 0; i < size; ++i )
{
*arr++ = i;
}
}
我从C#调用这个函数就像这样:
[DllImport("Interop.dll")]
public static extern void Foo( int[] arr, int size );
static void Main(...)
{
Test();
}
private static void Test()
{
int[] arr = new int[100];
Foo( arr, arr.Length );
}
执行“测试”后,我收到以下错误:
检测到PInvokeStackImblanace
调用PInvoke函数'WindowsFormsApplication2!WindowsFormsApplication2.Form1 :: Foo'使堆栈失去平衡。这很可能是因为托管PInvoke签名与非托管目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。
所以,我不是互操作专家,但我没有看到这段代码的问题。本机签名需要指向int的指针,我传入对int[]
的引用。那说,它不起作用,所以我一定是错的。提前谢谢。
编辑:好的,我改为测试尽可能简单:
extern "C" __declspec(dllexport) void Foo( int i );
void Foo( int i ) { }
C#:
[DllImport("Interop.dll")]
public static extern void Foo( int i );
private void Test()
{
Foo( 1 );
}
导致同样的错误。我是否错过了关于在互操作中使用的调用约定的整体课程?这是怎么回事?
答案 0 :(得分:4)
您需要指定正确的calling convention。 C / C ++程序的默认调用约定为cdecl,但通过PInvoke导入时的默认调用约定为StdCall。因此,您需要在导入时指定Cdecl
约定,或在导出时指定__stdcall
。例如:
[DllImport("Interop.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo( int i );
private void Test()
{
Foo( 1 );
}