如何从C#调用一个接受stringstream类型参数的C++ DLL函数?

8

我想导入一个未管理的C++ DLL并调用一个需要stringstream作为参数的函数。在C#中,没有stringstream类,所以有人能告诉我如何从C#程序调用这样的函数吗?

5个回答

12

绝对不能通过DLL公开模板对象。

模板对象(例如std::中的几乎所有对象)会被内联。因此,你的DLL将获得其自己的实现的私有副本。调用你的DLL的模块也会获得其自己的stringstream实现的私有副本。在它们之间传递意味着无意中将两个不相关的实现编织在一起。对于许多项目来说,如果你使用完全相同的构建设置,这可能不是问题。

但是,即使你使用相同的编译器,将发布版DLL与调试版EXE混合使用,你也会发现栈/堆破坏和其他难以找到的问题。

而且,这只是在从另一个非托管C++ exe/dll使用你的DLL时。然后要跨越线到.NET就更成问题了。

解决方案是更改你的DLL接口,使其能够在DLL边界之间友好地运行。可以使用COM(例如,你可以使用IStream),或者只是一个类似于winapi的C风格接口。


我尝试将一个以std:string为参数的非托管C++函数导入到C#程序中,但是出现了以下运行时错误:"Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Win32API.processRequestWithStream(String& inputString, String& outputString) at Win32API.Main()" - 这个错误的原因是什么? - user186246
1
std::stringstd::basic_string<char, std::allocator> 的一个 typedef,也就是说,它和 stringstream 一样都是模板化的。 - Max Lybbert
1
那么各种智能指针呢?如果我字面理解,这意味着不应该在 DLL 边界上公开非平凡的 C++。 - user180326
1
重点在于内联代码。有多种方法可以导出C++对象,因为实现只有一个主页。模板化(或任何内联)实现会得到许多独立的实现,并且不会混合。智能指针也是如此。但是它们所指向的对象并不一定如此。 - tenfour
我非常确定VS定义了_USER_DLL自动导出了basic_string系列。请参见http://support.microsoft.com/kb/168958。 - KitsuneYMG
你告诉我吧。我不知道有多少次因为一个组件没有定义“_SECURE_SCL=0”而不得不在工作中修复崩溃。 - Ed S.

3

如果您可以修改C++ dll,请导出一个纯字符串版本。否则,您需要构建一个托管的C++包装器项目,导入其他C++ dll,将其导出为托管函数,并从您的C#代码中调用该函数。C++互操作真的很麻烦。


3
很抱歉,您需要在C#中创建自己的StringStream类才能使用从该DLL导出的函数。正如您提到的,.NET Framework没有提供任何类似的功能。
最简单的方法可能是封装.NET Framework提供的StringBuilder类,使其可以作为流运行。请参见此博客文章以获得更多说明和一些示例代码:http://web.archive.org/web/20130414075835/http://www.codingday.com/string-stream-for-net/
类似的问题也有回答在MSDN杂志上:http://msdn.microsoft.com/en-us/magazine/cc163768.aspx。您可能会发现其中给出的一些提示和/或示例代码有用。

1

你正在尝试将本地的C++代码绑定到C#中的托管代码。一般而言,最好的方法是在托管的C++中引入中间层,它将为来自C#的调用提供接口。


0
创建一个包装器dll,使用c或c++语言,以便友好地调用该函数。这是更好的方法。
例如:
BOOL getString(TCHAR * myreturnString, DWORD *size);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接