在 C# 中使用 C++
来源:互联网 发布:linux home空间 编辑:程序博客网 时间:2024/06/10 00:50
综述
C# 调用 C++ 中的函数或类是通过调用其 dll 来实现的。对于 unmanaged C++,我们在每个函数前加上 dllexport
,并在 C# 代码中通过 dllimport
和 extern static
来调用 dll 中的函数。这样需要为每个函数添加 dllimport/dllexport
,很不方便。注意 C# 是可以直接调用 C++/CLR (managed C++) 的 dll 的。因此,为了两端(调用端/实现端)代码编写的便利,我们可以用 C++/CLR 作为联系 unmanaged C++ 和 C# 的 wrapper,写出更简洁的代码。
C# 调用 C++ 代码 —— dllimport 方式
编写 C++ DLL
新建 VC++ 控制台空项目,项目类型选 DLL,新建 MathFuncDll.h 和 MathFuncDll.cpp 文件,代码如下:
// MathFuncsDll.h#include <stdexcept>using namespace std;namespace MathFuncs{ extern "C" { __declspec(dllexport) double Add(double a, double b); } extern "C" { __declspec(dllexport) double Subtract(double a, double b); } extern "C" { __declspec(dllexport) double Multiply(double a, double b); } extern "C" { __declspec(dllexport) double Divide(double a, double b); }}
// MathFuncsDll.cpp#include "MathFuncsDll.h"namespace MathFuncs{ double Add( double a, double b ) { return a+b; } double Subtract( double a, double b ) { return a-b; } double Multiply( double a, double b ) { return a*b; } double Divide( double a, double b ) { if ( b == 0 ) throw invalid_argument("b cannot be zero!"); return a/b; }}
编译后在 Debug 或 Release 文件夹中可找到 MathFuncsDll.dll 文件。
编写 C# 测试程序
新建 C# 控制台项目,Program.cs 的代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Runtime.InteropServices;namespace cppdll_test_csharp{ class Program { [DllImport("C:/Users/huanglianghua/Documents/Visual Studio 2012/Projects/cppdll_test/Debug/cppdll_test.dll", CallingConvention = CallingConvention.Cdecl)] public static extern double Add(double a, double b); static void Main(string[] args) { double c = Add(10, 10); Console.WriteLine(c); } }}
运行后输出 20
代表程序正确。
C# 调用 C++ 代码 —— C++ wrapper 方式
以上代码能够正确运行。但是需要 dllimport/dllexport
,且调用时每个函数需要定义 static extern
。当函数数量不多时,这种方法容易使用。但当函数数量很大时,调用会很不方便。
注意到虽然 C# 调用普通的 C++ 代码(unmanaged C++)很麻烦,但 C# 是可以直接调用 C++/CLI (managed C++) 的 dll 的。C++/CLI 即托管的 C++ —— 以 C++ 的名义写 C#。CLI 是 Common Language Infrastructure 的缩写。所以我们可以将 C++/CLI 作为 C++ 和 C# 的接口 —— 为 C++ 程序写一个 wrapper,然后在 C# 里直接调用。
简而言之,需要三个项目:
- 一个 VC++ 项目,采用 unmanaged C++,编写主要的函数体;
- 一个 VC++ 项目,采用 managed C++,编写 C++/CLI wrapper;
- 一个 VC# 项目,测试 C++/CLI wrapper 的 dll。
C++ 主体代码
建立 VC++ 空项目,项目类型为控制台应用程序,建立 MathFuncs.h, MathFuncs.cpp 和 main.cpp 文件,其中 main.cpp 主要用于测试 MathFuncs.cpp 中的函数。代码如下:
// MathFuncs.h#pragma once#include <stdexcept>using namespace std;class MyMathFuncs{public: double Add(double a, double b); double Subtract(double a, double b); double Multiply(double a, double b); double Divide(double a, double b);};
// MathFuncs.cpp#pragma once#include "cli_cpp.h"double MyMathFuncs::Add(double a, double b){ return a+b; }double MyMathFuncs::Subtract(double a, double b){ return a-b; }double MyMathFuncs::Multiply(double a, double b){ return a*b; }double MyMathFuncs::Divide(double a, double b){ if ( b == 0 ) throw invalid_argument("b cannot be zero!");}
// main.cpp#include <stdio.h>#include "cli_cpp.h"using namespace std;int main(){ MyMathFuncs* m = new MyMathFuncs(); double c = m->Add (10.1,20.2) ; printf("Result is %f\n", c); free(m); return 0;}
代码无误的话运行会出现 “Result is 30.300000”。
C++ wrapper 代码
新建 VC++ CLI Class Library 项目 managedDllWrapper,修改 managedDllWrapper.h 和 managedDllWrapper.cpp 如下:
// managedDllWrapper.h#pragma once#include "C:\Visual Studio 2012/Projects/MathFuncs/MathFuncs.h"#include "C:\Visual Studio 2012/Projects/MathFuncs/MathFuncs.cpp"using namespace System;namespace managedDllWrapper { public ref class MyMathFuncsWrapper { public: // constructor MyMathFuncsWrapper(); // wrapper methods double AddWrapper ( double a, double b); double SubtractWrapper ( double a, double b); double MultiplyWrapper ( double a, double b); double DivideWrapper ( double a, double b); // public variable double initVal; private: MyMathFuncs* myCppClass; // an instance };}
// managedDllWrapper.cpp#include "stdafx.h"#include "managedDllWrapper.h"#include "C:\Visual Studio 2012/Projects/MathFuncs/MathFuncs.h"#include "C:\Visual Studio 2012/Projects/MathFuncs/MathFuncs.cpp"// Constructor implementaionmanagedDllWrapper::MyMathFuncsWrapper::MyMathFuncsWrapper(){ initVal = 20.0; myCppClass = new MyMathFuncs(); //initiate C++ class's instance}double managedDllWrapper::MyMathFuncsWrapper::AddWrapper ( double a, double b){ return myCppClass->Add(a,b);}double managedDllWrapper::MyMathFuncsWrapper::SubtractWrapper (double a, double b){ return myCppClass->Subtract(a,b);}double managedDllWrapper::MyMathFuncsWrapper::MultiplyWrapper (double a, double b){ return myCppClass->Multiply(a,b);}double managedDllWrapper::MyMathFuncsWrapper::DivideWrapper (double a, double b){ return myCppClass->Divide(a,b);}
以 Debug 或/和 Release 模式编译后会生成 managedDllWrapper.dll 文件。我们将在 C# 中使用它们。
C# 测试代码
新建 C# 控制台应用程序,在 References
中右键添加,选择 Browse...
找到 managedDllWrapper.dll 并添加,即可直接在 C# 代码中使用 dll 中的函数。C# 测试代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using managedDllWrapper;namespace testCSharpInterface{ class Program { static MyMathFuncsWrapper mymath = new MyMathFuncsWrapper(); static void Main(string[] args) { double c = mymath.initVal; Console.WriteLine(c); c = mymath.AddWrapper(c, c); Console.WriteLine(c); } }}
运行无误应该出现结果 20
和 40
。
C# 调用 C++ OpenCV 代码
在 rich UI 的 C# 中调用 rich efficiency 的 C++ OpenCV 代码,结合二者的优势。
参考链接
- Use C++ codes in a C# project — unmanaged C++ solution
- Youtube 视频 DLL (C++) for C sharp (C#)
- Use C++ codes in a C# project — solution of wrapping native C++ with a managed CLR wrapper
- Use OpenCV C++ codes in a VC# project — solution of creating a managed CLR wrapper
- 在C#中使用C/C++写的DLL
- 在C#中使用C/C++写的DLL
- 如何在C#中使用C/C++写的DLL。
- 在C#中使用C/C++写的DLL
- 【问题解决】在C#中使用C++编写的类 使用托管c++(managed c++)
- 在C#中使用LOG4NET
- 在C#中使用SendMessage
- 在C#中使用颜色
- 在C#中使用LOG4NET
- 在 C# 中使用设置
- 在C#中使用Delegates
- 在 C# 中使用设置
- 在C#中使用颜色
- 在C#中使用WMI
- 在 C# 中使用画笔
- 在C#中使用钩子
- 在C#中使用SendMessage
- 在C#中使用LOG4NET
- 算法原理 第七章 快速排序
- Java类加载过程
- Linux中启动Tomcat:bash: ./startup.sh: Permission denied问题
- MemCache超详细解读
- leetcode:69. Sqrt(x)
- 在 C# 中使用 C++
- MySQL索引的使用
- 第6天HBase笔记
- 关于SurfaceView横竖屏切换显示问题
- iOS 基于环信SDK实现即时通讯-文字聊天
- Apache Thrift 配置和使用指南
- selenium 如何获取分页数据
- Retrofit2学习笔记-1
- 素数筛法详解