在处理C ++ / CLI项目以包装本机C ++ DLL时,我遇到了一个带有std::string
的本机函数。如下所示:
class NativeApi
{
public:
ErrorCode readFile(std::string filename = "path.csv");
};
在我的托管包装器实现中,我分配了一个本机类的新实例并调用了这个函数:
ref class ManagedApi
{
private:
NativeApi *api;
public:
ManagedApi(): api(new NativeApi()) { }
void Read()
{
api->readFile("apath.csv") // or with nothing to use default value
}
}
当我运行此操作时,我得到MDA PinvokeStackImbalance
抱怨此调用已使堆栈失衡。我很惊讶,因为我唯一一次得到这个MDA来自C#,当调用约定不匹配时。我从未在C ++ / CLI中看到过这种情况,其中大概所有匹配都是由编译器自动完成的。
有没有人见过这个?谷歌搜索空了。我查看了DLL签名,它看起来像:
?readFile@NativeApi@@QAE?AW4ErrorCode@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z
这告诉我函数在那里,并且basic_string
作为唯一参数,它应该与标准std::string
typedef匹配。
不知道什么可能出错。我可以对本地API进行其他调用,这些调用不完全正确。
答案 0 :(得分:1)
您使用的std::string
的定义与用于编译本机C ++ DLL的定义之间可能存在差异。即使定义相同,本机DLL可能没有使用与您相同版本的C运行时,因此当您的DLL为std::string
分配内存时,Native DLL将尝试调用{{ 1}}在它上面(当字符串在delete
方法的末尾被销毁时),并且对readFile
的调用将转到与分配对象不同的堆!
如果要使其工作,则必须使用与本机DLL上使用的完全相同版本的编译器。请注意,您将仅限于项目的Release版本,因为您没有使用调试运行时编译的本机DLL。
正确修复此问题的方法是在跨越DLL边界调用时使用原始类型(在本例中为delete
)。如果您可以请求更改本机DLL,我会这样做。如果只使用原始类型,那么使用不同的运行时没有问题,一切都按照应有的方式工作。