基于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. 效果如下:

以上です。
浙公网安备 33010602011771号