从c++ /CLI函数调用c#函数

本文关键字:函数 函数调用 CLI c++ | 更新日期: 2023-09-27 17:51:07

我的项目要求我使用c#为c++提供一个用户界面。我调用的一个c++函数做了很多工作,并通过另一个"对象"提供周期性的进度更新。这里有一个例子来说明我的意思。

c++

class AppDelegate : public ProgressDelegate
    {
    void AppDelegate::UpdateStatusText(const char* text)
        {
        // Go() will end up calling me at some point.
        OutputDebugString(text);
        }
    void AppDelegate::ShowMessage(const char* text)
        {
        // Go() will end up calling me at some point.
        OutputDebugString(text);
        }
     };
int CppWrapper::Go()
    {
    return cppInstance->Go()
    }

CSharp

void UpdateStatusText(String text)
   {
   //update UI
   }
void ShowMessage(String text)
   {
   //update UI
   }

我想做的是采取updateStatusText和ShowMessage和传递文本到c#来更新我的UI。我的问题是如何公开适当的c#方法,以便我的c++代码可以调用它们?请注意,修改Go对我来说不是一个选项。

从c++ /CLI函数调用c#函数

也许这个例子可以帮助你:

写托管DLL

要创建一个简单的托管DLL,它具有一个公共方法来添加两个数字并返回结果,请遵循以下步骤:

启动Microsoft Visual Studio . net或Microsoft Visual Studio 2005。在"文件"菜单上指向"新建",然后单击"项目"。打开"新建项目"对话框。在项目类型下,单击Visual c#项目。

注意在Visual Studio 2005中,在项目类型下单击Visual c#。在模板下,单击类库。在"名称"文本框中键入sManagedDLL,然后单击"确定"。在Code视图中打开Class1.cs文件。要声明一个具有两个数字相加方法的公共接口,请将以下代码添加到Class1.cs文件:

// Interface declaration.
public interface ICalculator
{
    int Add(int Number1, int Number2);
};
要在类中实现这个公共接口,请将以下代码添加到Class1.cs文件中:
// Interface implementation.
public class ManagedClass:ICalculator
{
    public int Add(int Number1,int Number2)
        {
            return Number1+Number2;
        }
}

注册托管DLL以便与COM或本机c++一起使用要与COM或本机c++一起使用托管DLL,必须在Windows注册表中注册DLL的程序集信息。要做到这一点,请遵循以下步骤:

从本地c++代码调用托管DLL

// Import the type library.
#import "..'ManagedDLL'bin'Debug'ManagedDLL.tlb" raw_interfaces_only

如果计算机上的路径与此路径不同,则更改类型库的路径。要声明要使用的名称空间,请将以下代码添加到CPPClient.cpp文件中:

using namespace ManagedDLL;

完整的代码清单

  //Managed DLL
  // Class1.cs
  // A simple managed DLL that contains a method to add two numbers.
  using System;
  namespace ManagedDLL
  {
    // Interface declaration.
      public interface ICalculator
      {
          int Add(int Number1, int Number2);
      };
      // Interface implementation.
    public class ManagedClass:ICalculator
    {
         public int Add(int Number1,int Number2)
              {
                  return Number1+Number2;
              }
    }
  }

  //C++ Client
  // CPPClient.cpp: Defines the entry point for the console application.
  // C++ client that calls a managed DLL.
  #include "stdafx.h"
  #include "tchar.h"
  // Import the type library.
  #import "..'ManagedDLL'bin'Debug'ManagedDLL.tlb" raw_interfaces_only
  using namespace ManagedDLL;
  int _tmain(int argc, _TCHAR* argv[])
  {
      // Initialize COM.
      HRESULT hr = CoInitialize(NULL);
      // Create the interface pointer.
      ICalculatorPtr pICalc(__uuidof(ManagedClass));
      long lResult = 0;
      // Call the Add method.
      pICalc->Add(5, 10, &lResult);
      wprintf(L"The result is %d'n", lResult);

      // Uninitialize COM.
      CoUninitialize();
      return 0;
  }

参考:如何在Visual Studio中从本机Visual c++代码调用托管DLL。. NET或Visual Studio 2005

或者,我过去经常做的(在我切换到使用p/Invoke方法从c#调用到c++之前)是有3个项目(正如直线所提到的),但我会有c#, Managed c++和Native c++,并且让Managed c++成为我在两者(Native c++和c#)之间进行对话的桥梁/代理。这样在我的Native c++端工作就更容易了。需要注意的是,一些STL(主要是容器)不受managed支持,或者有时std::string (managed c++版本)的行为在Native c++ std::string中使用时会导致异常,因此要注意哪些STL库是受managed c++支持的。

此外,正如直线所提到的,桥接代码(在我的情况下,托管c++)必须有一个包装器,它将从托管封送到本机,反之亦然(即您的"const char*"到System)。

您必须将相关的c#代码构建到程序集中,然后在c++ CLI项目中引用该程序集。在c++ CLI包装器中,您将调用通过该c#程序集公开的函数,还将调用本机c++代码。

c++ CLI项目可以包含本地c++代码,只要确保本机文件没有启用CLR开关。因此,您将有3个项目-

  1. c#项目的GUI将调用main。还引用了用于公开c#函数以通过c++互操作调用的程序集。
  2. 暴露某些托管函数(因此可从c++ CLI调用)的c#程序集
  3. c++ CLI项目,它将封装并包含本机代码。