【问题标题】:PInvoke marshalling of integers returning incorrect resultPInvoke 整数编组返回不正确的结果
【发布时间】:2012-01-22 04:09:12
【问题描述】:

我在一个非托管 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 dll 中的 sizeof(long) 是什么?

标签: c# .net pinvoke marshalling unmanaged


【解决方案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】:

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 做到了。所有受访者都提到了长尺寸不匹配,但您包含调用约定不匹配也很有帮助。
      猜你喜欢
      • 2016-10-26
      • 1970-01-01
      • 1970-01-01
      • 2012-04-11
      • 2016-02-06
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多