在 C# 中使用 C++

来源:互联网 发布:linux home空间 编辑:程序博客网 时间:2024/06/10 00:50

综述

C# 调用 C++ 中的函数或类是通过调用其 dll 来实现的。对于 unmanaged C++,我们在每个函数前加上 dllexport,并在 C# 代码中通过 dllimportextern 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);        }    }}

运行无误应该出现结果 2040

C# 调用 C++ OpenCV 代码

在 rich UI 的 C# 中调用 rich efficiency 的 C++ OpenCV 代码,结合二者的优势。

参考链接

  1. Use C++ codes in a C# project — unmanaged C++ solution
  2. Youtube 视频 DLL (C++) for C sharp (C#)
  3. Use C++ codes in a C# project — solution of wrapping native C++ with a managed CLR wrapper
  4. Use OpenCV C++ codes in a VC# project — solution of creating a managed CLR wrapper
0 0
原创粉丝点击