我正在尝试使用PInvoke来调用非托管C ++ DLL并且我遇到错误(见下文)。使用depends.exe
我可以在导出的函数列表中看到错位的名称,因此是奇怪的EntryPoint
名称。虽然出现此异常,但如果我在调试时继续Step Over
,则函数返回并且ptr
等于1并且打印“成功”。
我已尝试过其他帖子中的一些建议,但没有任何效果。我认为uint32_t
非常自我解释。我已经尝试更改C#PInvoke签名以使用long
和ulong
但是仍然抛出异常并且ptr
的值非常大。我还尝试为CharSet
属性设置ExactSpelling
和DllImport
属性,但这似乎也不起作用。
我的问题是,我在做什么导致异常,如果我不能/不应该忽略异常 - 如何做到这一点?
MyClass.h
class __declspec(dllexport) MyClass
{
public:
uint32_t runCommand(uint32_t start);
};
MyClass.cpp
uint32_t MyClass::runCommand(uint32_t start);
{
uint32_t status = 1;
return status;
}
P / Invoke Signature
[DllImport("myClass.dll",
EntryPoint = "?runCommand@MyClass@myClass@@QAEII@Z",
CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 runCommand(UInt32 baseAddress);
用法
public static void Do()
{
UInt32 a = 0xA000;
UInt32 ptr = runCommand(a);
Console.Write("Success!");
}
错误:
托管调试助手'PInvokeStackImbalance'在'C:\ Users ... \ TestApp.vshost.exe'中检测到问题。
附加信息:对PInvoke函数'TestApp!TestApp.CSMyClass :: runCommand'的调用使堆栈失衡。这很可能是因为托管PInvoke签名与非托管目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。
使用Visual Studio 2015,C#应用程序是.NET Framework 4.6。
答案 0 :(得分:5)
调用约定不匹配,导致堆栈不平衡。
由于runCommand
是MyClass
的成员函数,因此用于它的调用约定是 not __cdecl
,但{ {3}}(请注意,有一个隐含的" this
"指针作为参数传递给C ++类的非静态成员函数。)
您可能希望从DLL中导出纯C 接口函数(不是C ++类成员函数)以进行P / Invoke,或者您可以使用 C ++ / CLI 在本机代码和托管代码之间构建一个微小的桥接层,将C ++本机类包装在用C ++ / CLI编写的.NET托管类中,并使用C#中的托管类包装器。