PInvoke整数的编组返回错误的结果

时间:2011-12-16 16:53:48

标签: c# .net pinvoke marshalling unmanaged

我在非托管DLL中有一个非常简单的函数,但是我没有从它获得正确的返回值。

我可以确认一般的PInvoke机制正在使用我的C DLL中的一个函数:

/* Return an integer */
extern "C" __declspec(dllexport) long get_num()
{
    return 42;
}

我从C#.NET调用上面这样的非托管入口点:

[DllImport("My_C_DLL.dll")]
extern static long get_num();
// ...
long ans = get_num();
Console.WriteLine("The answer is {0}.", ans);

这样可以正常工作,但是将编组参数传递给DLL中的另一个函数会返回错误的结果:

/* Add two integers */
extern "C" __declspec(dllexport) long add_num(long a, long b)
{
    long sum = a + b;

    return sum;
}

从C#调用:

[DllImport("My_C_DLL.dll")]
extern static long add_num(long a, long b);

long a = 6, b = 12;
long sum = add_num(a, b);
Console.WriteLine("The answer is {0}.", sum);

这给了我一个“6”的结果,或者我设置的 a 的输入值。

我猜测输入值的一些不正确的编组正在弄乱调用堆栈,导致错误的返回值,但错误在哪里?

3 个答案:

答案 0 :(得分:3)

这里有两个问题。首先,C#long与C long不匹配。在Windows上,C长是32位。在C#代码中使用int以匹配您的C long

另一个问题是调用约定可能不匹配。您的C DLL中很可能有cdecl但C#默认值为stdcall。通过更改您的p / invoke来解决此问题。

[DllImport("My_C_DLL.dll", CallingConvention=CallingConvention.Cdecl)]

答案 1 :(得分:1)

您是将非托管DLL构建为32位还是64位?请记住,C#中的“long”类型与System.Int64相同。这可能是您的编组问题的根源。如果您的DLL是32位,请尝试将您的C#代码更改为:

[DllImport("MY_C_DLL.dll")]
extern static int add_num(int a, int b);

答案 2 :(得分:1)

您可能将托管部件定义为 long 作为64位整数,而C编译器将其定义为32位整数。

您可以在C#代码中将更改为 int ,在C中将更改为 int64_t 代码,或使用MarshalAs(UnmanagedType.I4)强制进行32位编组(仅在所有其他想法失败时强制编组)