【发布时间】:2010-01-11 17:43:58
【问题描述】:
首先,我要感谢马特戴维斯this post。我知道该帖子未被选为该特定问题的答案,但该帖子对我非常有帮助。我有几个小问题需要解决(主要是在他提供的代码中调整文件路径),但我很容易使用他的 C++ 桥接方法为 C# WCF 服务创建非托管 C++ 客户端。
我现在正在探索如何改进那里提出的基本概念。以下是 Matt 帖子中 HelloServiceClientBridge.cpp 文件中的一些代码:
String^ message = client->SayHello(gcnew String(name));
client->Close();
IntPtr ptr = Marshal::StringToHGlobalAnsi(message);
rv = std::string(reinterpret_cast<char *>(static_cast<void *>(ptr)));
这里似乎要创建一个字符串的很多副本。以下是我看到的可能制作字符串副本的所有潜在位置:
-
name变量中字符串的原始非托管副本 - 调用
gcnew String(name)时字符串的托管副本 - 我不确定,但是当托管字符串作为参数传递给
SayHello()方法时,可能会创建另一个副本 - 字符串被复制到发送到 C# 服务的 WCF 消息中
- 我不确定,但 C# 服务在收到消息时可能会创建另一个副本
- 我认为在调用
String.Format时会创建另一个字符串副本 - 新的“Hello”字符串被复制到发送给客户端的 WCF 消息中
- 我不确定,但 C# 客户端在收到消息时可能会创建另一个副本
- 我不确定,但是当 C# 客户端将字符串返回到 C++ 桥时,可能会创建另一个副本
- 在调用
Marshal::StringToHGlobalAnsi(message)时会创建新字符串的非托管副本 - 我不确定,但是当字符串转换为
std::string时可能会创建另一个副本
现在,我意识到当我们使用非托管和托管互操作和进程间通信时,某些复制是不可避免的,但我想知道是否可以避免某些复制。对于简单的 HelloWorld 类型示例来说,这没什么大不了的,但是如果要传递大量数据,则从非托管复制到托管然后再从一个进程复制到另一个进程的成本可能会很大。所以,我想知道是否有一种方法可以在进程间通信发生的同时进行从非托管到托管和/或反之的编组。
我考虑的一种可能性是修改代码,以便可以将字符串从非托管字符串直接复制到格式化为托管字符串的 WCF 消息中。我想既然我们必须在那个时候制作一个副本,如果那个副本也能起到早期副本的功能,那我们就可以用一块石头杀死两只鸟了。
我考虑的另一种可能性是通过 WCF 消息将非托管指针从 C++ 进程传递到 C# 服务,然后该消息可以由 C# 服务编组为托管字符串。当然,搞清楚谁负责为该指针分配内存和解除分配内存可能会很麻烦,但是复制会减少,WCF 消息的大小也会显着减少。
感谢您提出的任何想法!
【问题讨论】:
标签: c++ wcf interop unmanaged managed