首页 > 解决方案 > P/Invoke:C# P/Invoking C 函数根据平台返回不同的值(X86 与 X64)?

问题描述

问这个问题我觉得很荒谬,但我有一个问题我已经研究了好几个小时了,我一辈子都无法弄清楚出了什么问题。

我在 C DLL 中定义了以下函数签名:

__declspec(dllexport) _Bool __cdecl cs_support(int query);

我在内部类中创建了以下 P/Invoke 签名等效项:

[DllImport("capstone", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool cs_support(int queryOption);

内部类在构建 2 个程序集的 .NET 项目中定义,1 个用于 .NET Framework,1 个用于 .NET Core。

我创建了一个小的 .NET 命令行应用程序,它同时加载 .NET 程序集和 C DLL,并按如下方式调用函数:

var isSupported = NativeImport.cs_support(65503);

现在这是我无法弄清楚的有趣之处。如果应用程序以 X86 为目标,我调用该函数一次,如果它以 X64 为目标(因此加载了 C DLL 的 X86 或 X64 版本),我得到不同的值!更奇怪的是X64版本返回正确的值,而X86版本没有!

我可以访问 C DLL 的源代码,它没有处理器指令可以根据目标平台为相同的输入返回不同的值。无论目标平台如何,C 代码实际上都非常简单,应该为相同的输入返回相同的值。

此外,当我创建一个小型 C 命令行应用程序进行测试时,无论目标平台如何,都会返回相同的正确值。

因此,似乎只有当 C DLL 由 .NET 和 P/Invoked 加载时,我才会看到这种行为!

所以我的问题是,为什么会这样?是否有一些奇怪的 P/Invoke 行为会导致我不得不提防这种情况?

如果这很重要,我正在 Windows 10 64 位上运行。

谢谢!

标签: c#.net.net-corepinvoke

解决方案


从评论中的讨论可以清楚地看出,问题是由本机函数返回一个_Bool值引起的,该类型_Bool的字节大小为 1。

但是,默认情况下,.NET 编组器将 C# 编组bool到和来自 Windows API 数据类型BOOL,其字节大小为 4(另见此处)。

要正确编组单字节_Bool值,需要明确指示编组器将 C#bool值编组为单字节:

[DllImport("capstone", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool cs_support(int queryOption);

推荐阅读