【发布时间】:2011-06-04 06:41:15
【问题描述】:
我在 C++ DLL 中有以下函数
extern "C" __declspec(dllexport) bool Exist(const char* name)
{
//if (g_Queues.find(name) != g_Queues.end())
// return true;
//else
// return false;
return false;
}
在我的 C# 类中,我有以下内容:
[DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)]
public static extern bool Exist(string name);
然而,每当我调用我的函数时,它总是返回 true,即使我注释掉了我的小函数并使其返回 false。我觉得我的调用约定有问题,或者 P/Invoking 我的 DLL 有任何其他问题,可能与字符串和 const char* 相对应,但现在我完全一无所知。我究竟做错了什么?为什么返回的是 true 而不是 false?
编辑: 我发现这与 const char* 或字符串无关,因为空函数仍然存在问题。我尝试更改 Cdecl 和 StdCall 之间的调用约定,但都不能正常工作。我还设法调试了我的 DLL,它被正确调用并且确实返回 false,但是一旦回到 C#,它就以某种方式为真。更改 CharSet 也没有效果。我确保每次都为我的 C# 程序提供了最新且正确版本的 DLL,所以这也不应该成为问题。同样,当我实际上返回 false 时,我完全不知道为什么结果为 true。
EDIT2: SOReader 为我提供了解决另一个重要问题的建议,请参阅我的评论。遗憾的是,它并没有解决退货问题。
EDIT3: 我已经得出结论,将 Exist (bool) 的返回类型更改为 (int) 突然使它返回正确的数字 (true = 1, false = 0)。这意味着 C++ 的 bool 和 C# 的 bool 之间可能存在问题。我可以继续使用 int 作为布尔值,但这仍然不能解释原始问题。也许其他人可以在这个问题上启发我?也许这与我使用 x64 的事实有关(尽管两个项目都编译为 x86)
【问题讨论】:
-
首先要检查的是该函数实际上是
cdecl。如果您的makefile 将Gz或Gr传递给编译器,则上面的函数不是cdecl。将__cdecl添加到您的 C 代码中,或启用pInvokeStackImbalance托管调试助手。 -
如果指定了 /Gr 或 /Gz,我认为它不会链接。关于托管调试助手的要点。
-
我测试过,__fastcall 不会与/clr 链接。但是 __stdcall (/Gz) 链接,但是在运行时找不到 Exist 入口点,因为函数签名不同。
-
调试到
Exist,在函数右括号上设置断点。查看断点命中时EAX寄存器的值。EAX中的任何内容都是 false 定义的内容。