如何从非托管代码调用托管代码?

22

我想从非托管的C++中调用我的.NET代码。我的进程入口点是基于.NET的,因此我不必担心CLR的托管问题。我知道可以使用.NET对象的COM包装器来实现这一点,但是我希望访问托管类的单个静态方法,因此COM不是我最短/最简单的路线。


可能是将DLL函数导出到非托管程序的重复问题。 - Rohit
6个回答

26

看看这个解决方案: https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports 这个解决方案允许通过使用[DllExport]属性(与P / Invoke DllImport相反)对函数进行装饰,从而从C中调用C#函数。

示例:

C# 代码

class Test
{
     [DllExport("add", CallingConvention = CallingConvention.StdCall)]
     public static int Add(int left, int right)
     {
         return left + right;
     } 
}

C 代码:

 extern "C" int add(int, int);

 int main()
 {
      int z = add(5,10);
      printf("The solution is found!!! Z is %i",z);
      return 0;
 }

输出:

The solution is found!!! Z is 15

更新:评论区中有一个问题和一个很好的答案:

如何在非托管项目中包含dll?

您需要链接到编译C#代码时生成的.lib文件 (https://msdn.microsoft.com/en-us/library/ba1z7822.aspx?f=255&MSPPError=-2147217396)


2
我该如何在非托管项目中包含dll?是否有示例项目(例如,针对Visual Studio)可供参考? - habakuk
1
@habakuk 我知道已经过了几年,但我把它放在这里,以便将来其他人可以看到它。我的做法是使用x64 / x86编译.cs项目。 然后在我的本机c ++项目中链接到生成的.lib文件。在头文件中引用方法签名:extern "C" { void ExportedMethodName(); }然后正常使用它。 - CodingMadeEasy

7
假设您说的是真正的非托管代码-不仅是在使用/clr编译的混合模式程序集中运行的本地C ++-最简单的方法是在C ++ / CLI中创建对您的.NET代码的包装器。 然后,您只需使用__declspec(dllexport)标记标记C ++ / CLI方法即可导出它们。
或者,如果您可以控制非托管代码的调用,则可以将函数指针转换为.NET方法并将其传递给非托管代码。

3
对于一个初学者来说,这个非常抽象的答案肯定不是很有用。这里缺少代码示例! - Elmue
@Elmue:必须反对。首先,将C#与C++进行接口处理绝不是初学者话题。这个答案提供了所有必要的关键词以供进一步阅读,并概述了必要步骤的大纲。 - nick

6

请看 GCHandle 类和 gcroot 关键字,它们提供了一个类型安全的、带模板的 GCHandle 包装器。

你可以在本机代码中使用这些来持有对 CLR 对象(或装箱值)的引用。

MSDN 在这里提供了一个基本教程 here


2
请注意,这需要启用/clr。 - Rasmus Faber

4

2

你的调用代码是启用了/clr的C++,对吗?

如果是的话,你可以简单地使用using语句在你的代码中使用你的.NET dll。像这样:

#using <Mydll.dll>

然后,您可以简单地创建您管理的类的对象,如下所示:

MyNameSpace::MyClass^ obj = new MyNameSpace::MyClass();

如果您想将此 obj 作为类的数据成员,则使用 gcroot 是正确的方法。

2
有用,但他确实说“来自非托管C++”。/clr 使其成为托管代码。 - gbjbaanb
我认为这就是他特别提到的事情。 <i>我的进程入口点是基于.NET的,所以我不必担心托管CLR。</i> - Aamir
他可能也是指他正在P/Invoke到一个完全不受管理的C++ dll,并希望再次调用CLR。 - Rasmus Faber

1

在将其集成到不同的解决方案后,找到了这里的好方法 使用C++/CLI帮助从本机C++中使用C#

附加IncludeDirectories ...YahooAPIWrapper

附加Dependencies ...YahooAPIWrapper.lib

并且与两个项目相关,能够通过最后一个DLL中的线程打开C#表单并从本机C++发送信息,只需要 ...APIWrapper.h 包含 - 应该更好地完成,但是它可以工作;-)

public YahooAPI()
{
    new Thread(() =>
    {
        Thread.CurrentThread.IsBackground = true;
        ShowForm();
    }).Start();
}

private static Form1 form = null;
public static void ShowForm()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    form = new Form1();
    Application.Run(form);
}

public void SendValues(bool[] values)
{
    if (form != null && form.ready) ...
}

准备好的布尔成员是在表单初始化完成后设置的。

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