11

我正在编写一个小 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) 上有一个断点,调试器将其报告为“真”,与 C++ 函数返回的内容无关。

C# bool 是否与 C++ bool 相同?尽管即使不是这种情况,我仍然不明白它如何找到返回值是“真”:)

谁能帮我解决这个奇怪的差异?

提前致谢!

4

3 回答 3

16

试试[return: MarshalAs (UnmanagedType.I1)]。默认情况下,C# interop将 C#编组bool为 Win32BOOL,这与 相同int,而 C++bool是一个字节的 AFAIR。因此,C# 的默认封送处理期望返回值是BOOL寄存器中的a eax,并拾取一些非零垃圾,因为 C++boolal.

于 2009-11-24T20:31:02.157 回答
3

您发布的代码段无法正常工作。如果这是使用 C++ 编译器编译的,那么函数名称将是 ?Foo@@YA_NXZ 并且您的 C# 代码永远找不到它。调用约定也很重要,除非您告诉编译器,否则它不是默认的 (CallingConvention.StdCall)。你应该在某个地方告诉链接器导出函数。

首先声明导出的函数,使其与默认的 P/Invoke 属性兼容:

extern "C" __declspec(dllexport) 
bool __stdcall Foo() {
    return false;
}

下一个问题是 C++ 编译器只使用一个字节来存储布尔值。为您的 return 语句生成的机器代码是:

013D138E  xor         al,al

然而,P/Invoke 编组器将假定它是一个 32 位整数并检查 eax 寄存器的值。要么将函数的返回类型声明为 int 或 BOOL,要么在 C# 声明中使用 [return: MarshalAs(UnmanagedType.U1)] 属性。

于 2009-11-24T20:22:31.347 回答
0

我使用了带符号的 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);
于 2017-03-06T05:18:15.580 回答