【问题标题】:How to call managed code from unmanaged code?如何从非托管代码调用托管代码?
【发布时间】:2010-09-18 12:35:21
【问题描述】:

我想从非托管 C++ 调用我的 .NET 代码。我的进程入口点是基于 .NET 的,所以我不必担心托管 CLR。我知道它可以使用 .NET 对象的 COM 包装器来完成,但我想访问托管类的各个静态方法,所以 COM 不是我最短/最简单的路线。

【问题讨论】:

标签: .net c++-cli interop clr unmanaged


【解决方案1】:

看看这个解决方案: 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

更新:cmets中有一个问题和一个很好的答案:

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

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

【讨论】:

  • 如何在非托管项目中包含 dll?某处是否有示例项目(例如,用于 Visual Studio)?
  • @habakuk 我知道已经有好几年了,但我把它放在这里,以便其他人将来可以看到它。我这样做的方式是使用 x64/x86 编译 .cs 项目。然后我链接到在我的本机 c++ 项目中生成的 .lib 文件。在头文件中,我引用了方法签名: extern "C" { void ExportedMethodName();然后就正常使用了。
【解决方案2】:

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

您可以使用它们在本机代码中保存对 CLR 对象(或装箱值)的引用。

MSDN 有基础教程here.

【讨论】:

  • 请注意,这需要启用 /clr。
【解决方案3】:

假设您谈论的是真正的非托管代码 - 不仅仅是在使用 /clr 编译的混合模式程序集中运行的本机 C++ - 最简单的方法是在 C++/CLI 中为您的 .NET 代码创建一个包装器。然后,您只需用 __declspec(dllexport) 标记即可导出 C++/CLI 方法。

或者,如果您可以控制非托管代码的调用,则可以将函数指针编组到您的 .NET 方法并将它们传递给非托管代码。

【讨论】:

  • 一个非常抽象的答案,对于提出这个问题的初学者来说肯定没有用处。这里缺少代码示例!
【解决方案4】:

我相信您正在寻找反向 PInvoke。如果你用谷歌搜索反向 pinvoke,你会得到很多有用的条目。我认为以下有一个很好的快速而肮脏的例子。

PInvoke-Reverse PInvoke and __stdcall - __cdecl

【讨论】:

    【解决方案5】:

    您的调用代码是启用了/clr 的C++。正确的?

    如果是,那么您可以简单地使用 using 语句在您的代码中使用您的 .NET dll。比如:

    #using <Mydll.dll>
    

    然后您可以简单地创建托管类的对象,例如:

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

    如果你想让这个 obj 成为你的类的数据成员,那么使用 gcroot 是要走的路。

    【讨论】:

    • 有用,但他确实说过“来自非托管 C++”。 /clr 停止它不受管理。
    • 我想这是他特别提到的。 我的进程入口点是基于 .NET 的,所以我不必担心托管 CLR
    • 他可能还意味着他正在 P/Invoking 到一个完全非托管的 C++ dll 并想再次回调到 CLR。​​
    【解决方案6】:

    在这里找到好方法Using C# from native C++ with the help of C++/CLI 集成到不同的解决方案后也发现了这些变化:

    其他IncludeDirectories ...YahooAPIWrapper

    其他依赖项 ...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) ...
    }
    

    当表单初始化完成时,ready 是我的 bool 成员集

    【讨论】:

      猜你喜欢
      • 2013-08-24
      • 1970-01-01
      • 2015-02-24
      • 1970-01-01
      • 2013-12-29
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      相关资源
      最近更新 更多