基于CLR实现C#调用C++类的一种方式

背景:

  最近开始学习新项目,使用C++ / OpenCV处理图像,然后C#制作显示界面。涉及到C#与C++通信相关,结合他人文章及自己实践整理。

 

始めましょう~

  思路:

  C++与OpenCV的部分,将算法封装到具体的类中实现,然后将具体类编译为.lib文件,与头文件(.h)一起放到使用通用语言运行时(CLR:Common Language Runtiome)实现的扩展类中,通过将扩展类编译为.dll文件提供给C#,使具体类中的接口暴露给C#,从而实现目标。下面使用VS2017演示具体图文步骤。

 

  一,具体C++类。

  1. VS2017中新建一个空项目。

 

2. 在新建项目中,添加具体类(MyFuncClass)。

 

3. 添加方法。

 1 /* MyFuncClass.h */
 2 
 3 #pragma once
 4 
 5 namespace MyFuncClassApplication
 6 {
 7     class MyFuncClass
 8     {
 9     public:
10         /* return a + b */
11         double Add(double a, double b);
12         
13         /* return a - b */
14         double Subtract(double a, double b);
15         
16         /* return a * b */
17         double Multiply(double a, double b);
18         
19         /* return a / b */
20         /* Throws const std::invalid_argument& if b is 0 */
21         double Divide(double a, double b);
22     };
23 }
 1 /* MyFuncClass.cpp */
 2 
 3 #include <stdexcept>
 4 #include "MyFuncClass.h"
 5 
 6 using namespace std;
 7 
 8 namespace MyFuncClassApplication
 9 {
10     double MyFuncClass::Add(double a, double b)
11     {
12         return a + b;
13     }
14 
15      double MyFuncClass::Subtract(double a, double b)
16     {
17         return a - b;
18     }
19 
20     double MyFuncClass::Multiply(double a, double b)
21     {
22         return a * b;
23     }
24 
25     double MyFuncClass::Divide(double a, double b)
26     {
27         if (b == 0)
28         {
29             throw invalid_argument("b cannot be zero!");
30         }
31 
32         return a / b;
33     }
34 }

 

4. 在 "项目" -> "属性" -> "配置属性" -> "常规" -> "项目默认值"-> "配置类型"中,将配置类型修改为 "静态库(.lib)",然后生成解决方案。在工程路径下的debug文件夹中,将生成 .lib 文件。

 

 

  二,CLR扩展类

  1. VS2017中新建CLR项目,并选择"类库"。

  2. 在新建项目中,添加扩展类(MyFuncClassEx)。

  

  

  3. 将具体类的头文件以及生成的.lib文件,拿到当前工程目录下。

    然后在"解决方案资源管理器" -> "项目"右键 -> "添加" -> "现有项"中将头文件及.lib添加到当前工程。

 

  4. 扩展类内容如下,具体见注释。

 1 /* MyFuncClassEx.h */
 2 
 3 #pragma once
 4 
 5 #include "MyFuncClass.h"    //引用具体类的头文件
 6 
 7 using namespace System;
 8 using namespace MyFuncClassApplication;    //具体类的命名空间
 9 
10 namespace MyFuncClassExApplication {
11     //public ref:C++/CLI创建一个位于托管堆上的引用类型
12     public ref class MyFuncClassEx
13     {
14         // TODO: 在此处添加此类的方法。
15     private:
16         /* 使用具体类指针来访问其方法。 */
17         MyFuncClass* pInstance;
18 
19     public:
20         MyFuncClassEx();
21         ~MyFuncClassEx();
22 
23         double Add(double a, double b);
24         double Subtract(double a, double b);
25         double Multiply(double a, double b);
26         double Divide(double a, double b);
27     };
28 }

 

 1 /* MyFuncClassEx.cpp */
 2 
 3 // 这是主 DLL 文件。
 4 
 5 #include "stdafx.h"
 6 
 7 #include "MyFuncClassEx.h"
 8 
 9 namespace MyFuncClassExApplication
10 {
11     MyFuncClassEx::MyFuncClassEx()
12     {
13         this->pInstance = new MyFuncClass();
14     }
15 
16     MyFuncClassEx::~MyFuncClassEx()
17     {
18         delete this->pInstance;
19     }
20 
21     double MyFuncClassEx::Add(double a, double b)
22     {
23         return this->pInstance->Add(a, b);
24     }
25     double MyFuncClassEx::Subtract(double a, double b)
26     {
27         return this->pInstance->Subtract(a, b);
28     }
29     double MyFuncClassEx::Multiply(double a, double b)
30     {
31         return this->pInstance->Multiply(a, b);
32     }
33     double MyFuncClassEx::Divide(double a, double b)
34     {
35         return this->pInstance->Divide(a, b);
36     }
37 }

 

  5. 生成解决方案。debug目录下生成MyFuncClassEx.dll。

 

 

  三,C# GUI层。(WPF还没学,暂时用简单的控制台程序测试)

  1. 新建C# 控制台应用(.NET Framework)。

 

  2. 将生成的.dll文件,拿到当前工程目录下。

    然后在"解决方案资源管理器" -> "项目"右键 -> "添加" -> "引用",添加对dll文件的引用。

  

  3. C#侧代码如下,通过引用扩展类的命名空间,就可以很方便的使用扩展类,从而调用到具体类来使用OpenCV:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;   // 必须

/* 引用C++扩展类的命名空间 */
using MyFuncClassExApplication;

namespace MyFuncClassCSharp
{
    class MyFuncClassCSharp
    {
        static void Main(string[] args)
        {
            /* 声明C++中的类对象 */
            MyFuncClassEx m = new MyFuncClassEx();
            Console.WriteLine("Call Function Add: {0}", m.Add(2.5, 6.99));
            Console.ReadKey();
        }
    }
}

 

  4. 效果如下:

 

以上です。

posted on 2017-12-27 13:19  zuodw  阅读(2262)  评论(0)    收藏  举报

导航