从 C++ 调用 C# 代码
Posted
技术标签:
【中文标题】从 C++ 调用 C# 代码【英文标题】:Calling C# code from C++ 【发布时间】:2010-10-21 04:26:57 【问题描述】:我需要能够从 C++ 调用任意 C# 函数。 http://www.infoq.com/articles/in-process-java-net-integration 建议使用 ICLRRuntimeHost::ExecuteInDefaultAppDomain() 但这仅允许我调用具有这种格式的方法:int method(string arg)
调用任意 C# 函数的最佳方法是什么?
【问题讨论】:
任意代码是什么意思?可实现的最细粒度不是在功能级别吗? 从.NET 5.0开始,就有了使用共享库的跨平台方式:请看this answer。 【参考方案1】:C++ 应用程序可以通过多种方式调用 C# DLL 中的函数。
-
使用 C++/CLI 作为中间 DLL
http://blogs.microsoft.co.il/sasha/2008/02/16/net-to-c-bridge/
反向 P/Invoke
http://tigerang.blogspot.ca/2008/09/reverse-pinvoke.html
http://blogs.msdn.com/b/junfeng/archive/2008/01/28/reverse-p-invoke-and-exception.aspx
使用 COM
http://msdn.microsoft.com/en-us/library/zsfww439.aspx
使用 CLR 托管 (
ICLRRuntimeHost::ExecuteInDefaultAppDomain()
)
http://msdn.microsoft.com/en-us/library/dd380850%28v=vs.110%29.aspx
http://msdn.microsoft.com/en-us/library/ms164411%28v=vs.110%29.aspx
https://***.com/a/4283104/184528
进程间通信 (IPC)
How to remote invoke another process method from C# application
http://www.codeproject.com/Tips/420582/Inter-Process-Communication-between-Csharp-and-Cpl
编辑:托管 HTTP 服务器并通过 HTTP 动词调用(例如 REST 样式 API)
【讨论】:
这 5 种方法中哪一种更可取,为什么?这将是有效的 如果你正在寻找一个跨平台的解决方案(所以 COM 或 C++ \clr 是不可能的),并且可以容忍一个扁平的 API(没有 OOP 语法,à la C API),there is (将是).NET 5 中的解决方案:使用它,您可以从 C# 代码创建一个 DLL,该 DLL 可以在 Linux 上从 C 或 C++ 使用(允许处理 C# 对象,就像在 C API 中为 C++ 代码所做的那样) .【参考方案2】:使用 /clr 标志编译您的 C++ 代码。这样,您就可以相对轻松地调用任何 .NET 代码。
例如:
#include <tchar.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
System::DateTime now = System::DateTime::Now;
printf("%d:%d:%d\n", now.Hour, now.Minute, now.Second);
return 0;
这算作“C++”吗?好吧,这显然不是标准 C++ ...
【讨论】:
那么它不再是 C++ 调用 C#,而是 C++/CLI 调用 C# - 你已经回避了这个问题。 C++ 与 C++/CLI 是一个非常重要的区别,不应忽视。 你不能导出 C++/CLI 函数,以便它们可以从普通 C++ 代码调用吗? Dan,您能否发布一个示例来展示如何从 C++/CLI 调用 C# 代码? C++/CLI 可以像调用“常规”C++ 函数一样调用任何 C# 函数。添加您的参考资料,/clr 就可以了。 “这算作 C++ 吗?嗯,它显然不是标准 C++”...关键是普通的 C/C++ 代码应该能够调用调用 C# 的 C++/CLI。看到它是如何工作的,我对这个解决方案非常满意。 @Filip:不是;如果你只是添加/clr
,你仍然会得到unsafe
代码,这真的限制了你在很多地方C# 非常有用(例如Windows Phone、Silverlight、ASP.NET,任何其他不受信任的代码正在执行...... )【参考方案3】:
见DllExport。
IOW:与DllImport
的工作方式完全相反。
https://github.com/3F/DllExport
它支持 Windows,并且正在开发跨平台支持。
C# 代码(我们从 C++ 中调用):
[DllExport]
public static int _add(int a, int b)
return a + b;
[DllExport]
public static bool saySomething()
DialogResult dlgres = MessageBox.Show(
"Hello from managed environment !",
".NET clr",
MessageBoxButtons.OKCancel
);
return dlgres == DialogResult.OK;
C++ 代码(调用之前的 C# 代码):
typedef int(__cdecl *_add)(int a, int b);
typedef bool(__cdecl *saySomething)();
auto pAdd = (_add)GetProcAddress(lib, "_add");
int c = pAdd(5, 7);
auto pSaySomething = (saySomething)GetProcAddress(lib, "saySomething");
bool dlgres = pSaySomething();
还有一个带有演示的 YouTube 视频 Managed & Unmanaged; PInvoke; [ Conari vs DllExport]。老实说,文档还不够完美,但不要让你失望:YouTube 视频非常棒。
这个项目的灵感来自另一个project from Robert Giesecke,它有220,000 downloads on NuGet。
有趣的事实:一些 Python 库已经使用它来实现 C++ 和 C# 的混合功能。
最后,感谢 Robert Giesecke 和 Denis Kuzmin,他们的工作非常出色!
【讨论】:
感谢您的捐赠,托尔米!这确实有助于继续开发和支持我的免费产品。 CoreCLR 支持 我计划在我的时间里尽可能通过第 90 期进行审查。关注新闻。 啊,是的,与糟糕的文档相比,每个人都可以使用complete demo project 和其他相关的screencasts,正如您已经注意到的那样。但总的来说,每个人都可以改进我们的文档!我个人仅通过Conari 等添加了关于我们的 DllExport 工具和相关 PInvoke 功能的基本内容。因为我更喜欢使用代码而不是文档:)【参考方案4】:如果您不关心您的 C++ 程序(或其中的一部分)是否使用 /clr 编译,您可以使用 C++/CLI 简单地调用任何 .NET 代码(只要添加对它的引用)。 Try out this article.
编辑:这里是a nice tutorial
另一条路线是让您的 C# 代码公开为 COM。
【讨论】:
好答案,坏教程。如果可能,请链接到更好的教程:)【参考方案5】:最简单的方法是使用 COM 互操作。
【讨论】:
IJW(C++ 互操作)比 COM 互操作容易得多。【参考方案6】:您可以在编译成 DLL 的 C# 代码周围使用COM callable wrapper。
【讨论】:
【参考方案7】:作为一种替代方法,您可以使用Lua 来实例化 CLR 对象、执行并返回结果。
【讨论】:
【参考方案8】:来自微软:Write a custom .NET Core host to control the .NET runtime from your native code。
IOW:在 Windows 和 Linux 上从 C++ 调用 C#。
有sample code on GitHub。
此示例代码是跨平台的,它允许从 Linux 和 Windows 上的任何 C++ 应用程序调用 .NET Core 中的 C# 代码。
老实说,与其他 DllExport
答案相比,此解决方案似乎相当复杂。 C++ 代码在扫描资源和入口点等方面做了很多繁重的工作。这个答案的一个论点可能是它是跨平台的。但是,另一个DllExport
答案也是跨平台的,并且使用起来更简单。
【讨论】:
以上是关于从 C++ 调用 C# 代码的主要内容,如果未能解决你的问题,请参考以下文章
使用 c# 中的 c++ 引用中的引用从 C# 错误调用 C++ 代码