我正在编写一个小型 C# 应用程序,它调用 C++ API 中的一些函数。我将 C++ 代码构建到 DLL 中,C# 代码使用 DllImport 调用 API。 (我正在为 C++ DLL 使用 .DEF 文件,因此不需要 extern“C”。)
到目前为止,API 有一个函数,但目前它什么也没做:
bool Foo()
{
return false;
}
在 C# 中,我有以下内容:
public class FooAPI
{
[DllImport("Foo.dll")]
public static extern bool Foo();
}
...
bool b = FooAPI.Foo();
if (!b)
{
// Throw an exception
}
我的问题是,由于某种原因,b 总是评估为 TRUE。我在 if (!b) 上有一个断点,调试器将其报告为“true”,与 C++ 函数返回的内容无关。
C# bool 与 C++ bool 相同吗?尽管即使情况并非如此,我仍然不明白它如何发现返回值为“true”:)
任何人都可以帮我解决这个奇怪的差异吗?
提前致谢!
尝试
[return: MarshalAs (UnmanagedType.I1)]
。默认情况下,C# 互操作 将 C# bool
编组为 Win32 BOOL
,与 int
相同,而 C++ bool
是一个字节 AFAIR。因此,C# 的默认封送处理期望返回值是 BOOL
寄存器中的 eax
,并拾取一些非零垃圾,因为 C++ bool
在 al
中返回。
您发布的代码片段无法工作。如果这是用 C++ 编译器编译的,那么函数名称将是
?Foo@@YA_NXZ
,而你的 C# 代码永远找不到它。调用约定也很重要,它不是默认的(CallingConvention.StdCall
),除非你告诉编译器。您应该在某个地方告诉链接器导出该函数。
首先声明导出的函数,使其与默认的 P/Invoke 属性兼容:
extern "C" __declspec(dllexport)
bool __stdcall Foo() {
return false;
}
下一个问题是 C++ 编译器仅使用一个 byte 来存储
bool
。为您的返回语句生成的机器代码是:
013D138E xor al,al
然而,P/Invoke 编组器将假定它是 32 位整数并检查 eax
寄存器的值。将函数的返回类型声明为
int
或
BOOL
,或者在 C# 声明中使用
[return: MarshalAs(UnmanagedType.U1)]
属性。
signed int。
C++代码
extern "C" __declspec(dllexport) signed int TestDouble(double* output)
{
*output = 1.3;
return true;
}
C#代码
[DllImport("abc.dll", EntryPoint = "TestDouble", CallingConvention = CallingConvention.Cdecl)]
public static extern bool TestDouble(out double output);