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的输入值。
我猜输入值的一些不正确的编组混淆了调用堆栈,导致坏的返回值,但错误在哪里?
这里有两个问题。首先,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);