对PInvoke函数[函数名称]的调用使堆栈失衡

时间:2016-10-20 15:10:00

标签: c# c++ pinvoke unmanaged

我正在尝试使用PInvoke来调用非托管C ++ DLL并且我遇到错误(见下文)。使用depends.exe我可以在导出的函数列表中看到错位的名称,因此是奇怪的EntryPoint名称。虽然出现此异常,但如果我在调试时继续Step Over,则函数返回并且ptr等于1并且打印“成功”。

我已尝试过其他帖子中的一些建议,但没有任何效果。我认为uint32_t非常自我解释。我已经尝试更改C#PInvoke签名以使用longulong但是仍然抛出异常并且ptr的值非常大。我还尝试为CharSet属性设置ExactSpellingDllImport属性,但这似乎也不起作用。

我的问题是,我在做什么导致异常,如果我不能/不应该忽略异常 - 如何做到这一点?

非托管C ++

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;
}

托管C#

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。

1 个答案:

答案 0 :(得分:5)

调用约定不匹配,导致堆栈不平衡。

由于runCommandMyClass成员函数,因此用于它的调用约定是 not __cdecl,但{ {3}}(请注意,有一个隐含的" this"指针作为参数传递给C ++类的非静态成员函数。)

您可能希望从DLL中导出纯C 接口函数(不是C ++类成员函数)以进行P / Invoke,或者您可以使用 C ++ / CLI 在本机代码和托管代码之间构建一个微小的桥接层,将C ++本机类包装在用C ++ / CLI编写的.NET托管类中,并使用C#中的托管类包装器。