在 C# 中使用 C++

综述

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 implementaion
managedDllWrapper::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
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值