C++/CLI入門系列 第三篇:C#通過C++/CLI,實現C++的回調函數

前言:照例囉嗦一下,心急的可略過。做程序員也好些年了,從 iOS 強轉 C++ 也有四年了。給後來者一個忠告:如果想要延長自身技術壽命,一定要珍惜時間,好好利用,拼命提升自己技術。

不說了,怎麼過都是一生,即便未來失業了,也不代表活不下去。這個時代,不要給自己添加承受不了的重擔,選擇自己喜歡的,輕裝度過這一生。

O了,開始搞起!

已經2020年了,公司要求用VS2019,所以就用這個版本做演示,大差不差~

第一步:打開VS2019,依次創建三個空的 C# 工程、CLR 工程和 C++ 工程。步驟如下圖所示:

第二步:擼代碼,如下所示:

//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<unsigned char>^ 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<unsigned char>^ 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<unsigned char> 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 吧,建議最好還是敲一遍。我不會告訴你在倉庫代碼上添加了註釋的(手動狗頭)。。。

演示結果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章