在进程跳跃期间将非托管转换为托管
首先,我要感谢马特·戴维斯这篇文章。我知道这篇文章没有被选为该特定问题的答案,但这篇文章对我非常有帮助。我有几个小问题需要修复(主要是调整他提供的代码中的文件路径),但我可以使用他的 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()
方法时,可能会创建另一个副本 - 该字符串被复制到 WCF 消息中 它会发送到 C# 服务
- 我不确定
- ,但 C# 服务在收到消息时可能会创建另一个副本,我认为调用
String.Format
时会创建该字符串的另一个副本 - 新的“Hello”字符串被复制到发送到客户端的 WCF 消息中,
- 我不确定,但 C# 客户端在收到
- 我不确定的消息时可能会创建另一个副本,但另一个副本可能是当 C# 客户端将字符串返回到 C++ 桥时
- 创建 调用
Marshal::StringToHGlobalAnsi(message)
时会创建新字符串的非托管副本 - 我不确定,但可能会创建另一个副本 复制
现在,我意识到当我们使用非托管和托管互操作和进程间通信时,一些复制是不可避免的,但我想知道是否有一些 是可以避免的。对于简单的 HelloWorld 类型示例来说,这并不是什么大问题,但如果传递大量数据,从非托管复制到托管,然后再从一个进程复制到另一个进程的成本可能会很大。因此,我想知道是否有一种方法可以在进程间通信发生的同时进行从非托管到托管的编组和/或反之亦然。
我考虑的一种可能性是修改代码,以便可以将字符串从非托管字符串直接复制到格式化为托管字符串的 WCF 消息中。我想,既然我们无论如何都必须制作一份副本,如果该副本也具有早期副本之一的功能,那就太好了,这样我们就可以一石二鸟。
我考虑的另一种可能性是通过 WCF 消息将非托管指针从 C++ 进程传递到 C# 服务,然后由 C# 服务将其编组为托管字符串。当然,确定谁负责为该指针分配内存和取消分配内存可能会变得非常混乱,但复制会减少,并且 WCF 消息大小可能会显着减小。
感谢您的任何想法!
First, I want to thank Matt Davis for this post. I know the post was not chosen as the answer to that specific question, but the post was extremely helpful to me. I had a couple small issues to fix (mostly adjusting the filepaths in the code he provided), but I was easily able to create an unmanaged C++ client for a C# WCF service using his C++ bridge method.
I am now exploring how to improve on the basic concepts presented there. Here is a bit of code from the HelloServiceClientBridge.cpp file in Matt's post:
String^ message = client->SayHello(gcnew String(name));
client->Close();
IntPtr ptr = Marshal::StringToHGlobalAnsi(message);
rv = std::string(reinterpret_cast<char *>(static_cast<void *>(ptr)));
It seems like a lot of copies of a string are going to be created here. Here are all of the potential places I see where a copy of the string may be made:
- The original unmanaged copy of the string in the
name
variable - A managed copy of the string when
gcnew String(name)
is invoked - I'm not sure, but another copy might be created when the managed string is passed as a parameter to the
SayHello()
method - The string is copied into the WCF message which is sent to the C# service
- I'm not sure, but another copy might be created by the C# service when it receives the message
- I think another copy of the string is created when
String.Format
is called - The new "Hello" string is copied into the WCF message which is sent to the client
- I'm not sure, but another copy might be created by the C# client when it receives the message
- I'm not sure, but another copy might be created when the C# client returns the string to the C++ bridge
- An unmanaged copy of the new string is created when
Marshal::StringToHGlobalAnsi(message)
is invoked - I'm not sure, but another copy might be created when the string is converted to a
std::string
Now, I realize that some copying is unavoidable when we're working with unmanaged and managed interop and interprocess communication, but I'm wondering if some this copying could be avoided. It isn't a big deal for a simple HelloWorld type example, but the cost of copying from unmanaged to managed and then again from one process to another process could be significant if a large amount of data was being passed. So, I'm wondering if there is a way to do the marshalling from unmanaged to managed and/or vice versa at the same time that the interprocess communication is happening.
One possiblity I considered was modifying the code so that the string could be copied from the unmanaged string directly into the WCF message formatted as a managed string. I thought since we have to make a copy at that point anyways, it would be nice if that copy also served the function of one of the earlier copies so we can kill two birds with one stone.
Another possibility I considered was passing an unmanaged pointer from the C++ process to the C# service through the WCF message which could then be marshalled to a managed string by the C# service. Of course, this has potential to be pretty messy figuring out who is responsible for allocating the memory and deallocating the memory for that pointer, but the copying would be reduced and the WCF message size could be significantly reduced.
Thanks for any ideas you may have!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我已经开始探索 WWSAPI 作为一种为 WCF 服务创建 C++ 客户端的方法。到目前为止,看起来这个解决方案运行得很好。
I have begun exploring WWSAPI as a way to create a C++ client for a WCF service. So far, it looks like this solution is working quite well.