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 吧,建议最好还是敲一遍。我不会告诉你在仓库代码上添加了注释的(手动狗头)。。。

演示结果如下:

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值