我在非托管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 的输入值。
我猜测输入值的一些不正确的编组正在弄乱调用堆栈,导致错误的返回值,但错误在哪里?
答案 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位编组(仅在所有其他想法失败时强制编组)