C# DllImport with C++ boolean function not returning correctly
我在C++ DLL中有以下功能
1 2 3 4 5 6 7 8 | 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课程中,我有以下内容:
1 2 | [DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)] public static extern bool Exist(string name); |
然而,每当我调用我的函数时,它总是返回真的,即使当我注释掉我的小函数并使它返回假的时候。我觉得我的调用约定有问题,或者P/Invoking my dll有其他问题,可能与字符串和const char*相对应,但现在我完全不知道了。我做错什么了?为什么它会返回真而不是假?
编辑:我发现这与const char*或字符串无关,因为空函数仍然存在问题。我试过更改cdecl和stdcall之间的调用约定,但都不能正常工作。我还设法调试了我的DLL,它被正确调用,并且确实返回了false,但是一旦返回到c中,不知何故它是真的。更改字符集也没有效果。我已经确保每次都为我的C程序提供最新和正确版本的DLL,所以这也不应该是问题。再一次,当我实际上返回错误时,我完全不知道为什么结果是正确的。
伊迪丝2:索瑞德给我提了一个建议,可以解决另一个重要问题,请看我的评论。遗憾的是,它不能解决退货问题。
edit3:我得出的结论是,将exist(bool)的返回类型更改为(int)会使它突然返回正确的数字(true=1,false=0)。这意味着C++的布尔和C的布尔可能会有问题。我可以继续使用int作为bool,但这仍然不能解释最初的问题。也许有人能在这方面启发我?也许这与我使用x64的事实有关(尽管两个poject都编译为x86)
我找到了解决你问题的办法。您的声明应在此封送处理之前:6
所以一切都应该是这样的:
1 2 3 | [DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)] [return:MarshalAs(UnmanagedType.I1)] public static extern bool Exist([MarshalAs(UnmanagedType.LPStr)] string name); |
我用我的简单例子测试了它,它成功了!
编辑为什么会这样?C将BoOL定义为4字节int(正如你们所说的),C++将其定义为1字节。C团队决定在pinvoke期间使用4字节的bool作为默认值,因为大多数系统API函数使用4字节的值作为bool。如果要更改此行为,必须通过指定要使用1字节值的封送处理来完成。
c's
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx
这表示unmanagedType.bool是win32
这实际上是由于EAX没有完全被典型的C++代码清除,返回返回一个EDCOX1×0。EAX在输入函数时通常包含一些伪值,对于
也许整理函数的参数可能有助于:
1 | [MarshalAs(UnmanagedType.LPStr)] |
以下是声明的外观:
1 2 | [DllImport("Whisper.dll", EntryPoint="Exist", CallingConvention=CallingConvention.Cdecl)] public static extern bool Exist([MarshalAs(UnmanagedType.LPStr)] string name); |
我使用带符号的int,它可以正确返回真/假。
https://stackoverflow.com/a/42618042/1687981
我使用以下系统发送布尔变量
1 2 3 4 5 6 7 8 9 10 11 | __declspec(dllexport) const bool* Read(Reader* instance) { try { bool result = instance->Read(); bool* value = (bool*)::CoTaskMemAlloc(sizeof(bool)); *value = result; return value; } catch (std::exception exp) { RegistryException(exp); return nullptr; } } |
在C,我做
1 2 3 4 5 6 7 8 9 10 11 12 13 | DllImport(WrapperConst.dllName)] public static extern IntPtr Read(IntPtr instance); public bool Read() { IntPtr intPtr = ReaderWrapper.Read(instance)); if(intPtr != IntPtr.Zero) { byte b = Marshal.ReadByte(intPtr); Marshal.FreeHGlobal(intPtr); return b != 0; } else { throw new Exception(GetLastException()); } } |
我测试了您的代码,它为我返回了false。所以肯定还有别的事情发生。
您确定要正确重新编译DLL吗?尝试删除.dll并重新生成。
除此之外,一切似乎都是好的假设。默认情况下,封送处理将.NET字符串处理为const char*而不必使用封送属性来修饰它,不管该dll是编译为ansi还是unicode。
请参阅http://msdn.microsoft.com/en-us/library/s9ts558h.aspx cpCondeFaultmarsHalingForStringsanchor5