PInvoke对整数进行编组,返回不正确的结果

本文关键字:返回 不正确 结果 整数 PInvoke | 更新日期: 2023-09-27 18:18:00

我在非托管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的输入值。

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

PInvoke对整数进行编组,返回不正确的结果

这里有两个问题。首先,c# long与c long不匹配。在Windows操作系统下,C长度为32位。在你的c#代码中使用int来匹配你的long

另一个问题是调用约定可能不匹配。你很可能在你的C DLL中有cdecl,但c#默认是stdcall。修改你的p/invoke.

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

您可能会遇到托管部分将long定义为64位整数的问题,而您的C编译器将其定义为32位整数。

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

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

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