C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数

前言:照例啰嗦一下,心急的可略过。做程序员也好些年了,从 iOS 强转 C++ 也有四年了。给后来者一个忠告:如果想要延长自身技术寿命,一定要珍惜时间,好好利用,拼命提升自己技术。

不说了,怎么过都是一生,即便未来失业了,也不代表活不下去。这个时代,不要给自己添加承受不了的重担,选择自己喜欢的,轻装度过这一生。

O了,开始搞起!

已经2020年了,公司要求用VS2019,所以就用这个版本做演示,大差不差~

第一步:打开VS2019,依次创建三个空的 C# 工程、CLR 工程和 C++ 工程。步骤如下图所示:

C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数_第1张图片

C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数_第2张图片

C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数_第3张图片

C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数_第4张图片

C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数_第5张图片

第二步:撸代码,如下所示:

//Cpp.h
#pragma once

using CppCallBack = void (__stdcall*)();

class __declspec(dllexport) MyArith
{
public:
    MyArith();
    ~MyArith();

    int GetCppData(unsigned char ch[], int len);
    int RegistCall(CppCallBack pFun);
    void execute();

private:
    CppCallBack cppCall;
};



//Cpp.cpp
#include "Cpp.h"

MyArith::MyArith(){}

MyArith::~MyArith(){}

int MyArith::GetCppData(unsigned char ch[], int len)
{
    unsigned char* p = ch;
    for (int i = 0; i < len; i++)
    {
        *(p++) = i % 26 + 65;
    }
    return 0;
}

int MyArith::RegistCall(CppCallBack pFun)
{
    if (pFun != nullptr)
    {
        cppCall = pFun;
        return 0;
    }
    else
    {
        return -1;
    }
}

void MyArith::execute()
{
    cppCall();
}




//Cli.h
#pragma once

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Collections::Generic;
using namespace System::Collections;
using namespace std;

#pragma managed
namespace CliDll {

	public delegate void CliCallBack();

	public ref class Arith
	{
	public:
		Arith();
		~Arith();

		int GetCliData(array^ ch, int len);
		int RegistCall(CliCallBack^ pFun);
		void execute();
	};
}




//Cli.cpp
#include "Cli.h"
#include "Cpp/Cpp.h"

MyArith *myArith;

CliDll::Arith::Arith()
{
    myArith = new MyArith();
}

CliDll::Arith::~Arith()
{
    myArith->~MyArith();
}

int CliDll::Arith::GetCliData(array^ ch, int len)
{
    unsigned char* src = new unsigned char[len];
    if (src == nullptr)
    {
        return -1;
    }

    int mark = myArith->GetCppData(src, len);
    if (mark)
    {
        return -2;
    }

    unsigned char* clisrc = src;
    pin_ptr cssrc = &ch[0];
    for (int i = 0; i < len; i++)
    {
        *(cssrc++) = *(clisrc++);
    }
    delete[] src;

    return 0;
}

int CliDll::Arith::RegistCall(CliCallBack^ pFun)
{
    CppCallBack cliCall = (CppCallBack)Marshal::GetFunctionPointerForDelegate(pFun).ToPointer();
    myArith->RegistCall(cliCall);
    return 0;
}

void CliDll::Arith::execute()
{
    myArith->execute();
}




//MyCS.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CliDll;

namespace CSharp
{
    public partial class MyCS
    {
        static Arith arith = new Arith();
        public static void MyCallBack()
        {
            byte[] data = new byte[26];
            int mark = MyCS.arith.GetCliData(data, 26);
            for(int i = 0; i < 26; i++)
            {
                Console.WriteLine(data[i]);
            }
        }

        static void Main(string[] args)
        {
            CliCallBack cliCall = new CliCallBack(MyCallBack);
            MyCS.arith.RegistCall(cliCall);
            MyCS.arith.execute();

            Console.ReadLine();
        }
    }
}

第三步:配置,参考此系列 第二篇:封装C++ dll库,提供接口给C#调用

如果和我一样懒,去 Git 仓库 上 clone 吧,建议最好还是敲一遍。我不会告诉你在仓库代码上添加了注释的(手动狗头)。。。

演示结果如下:

C++/CLI入门系列 第三篇:C#通过C++/CLI,实现C++的回调函数_第6张图片

你可能感兴趣的:(C++/CLI)