简单的互操作测试;堆栈通过简单的呼叫不平衡

时间:2011-02-21 20:12:05

标签: c# interop

我目前正在研究互操作相关的问题,并编写了一个小测试程序,以帮助我弄清楚发生了什么(有问题涉及调用更复杂的本机函数,并且很难发布这里)。

无论如何,我有一个非常简单的本机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 );
}

导致同样的错误。我是否错过了关于在互操作中使用的调用约定的整体课程?这是怎么回事?

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 );
}