IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C/C++通过函数指针与C#通信----C#与C/C++的交互 -> 正文阅读

[C++知识库]C/C++通过函数指针与C#通信----C#与C/C++的交互

在这里插入图片描述

大家都知道,C#适合在windows端写上层代码,进行UI编程。C/C++适合写驱动,用于与设备通信。
并且,我们所遇到的C#调用C/C++ 的DLL都是C#主动向C++通信,发送数据,可以发送结构体,基本数据类型等等。
所以我们就用到了在C#中利用PInvoke实现直接调用,就是如下形式:

		[DllImport("CPPDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		public extern static int Add(int x, int y);

比如,我可以在C#编写的UI上调用上述C/C++函数,那么C/C++函数就会驱动设备完成特定的指令。

但反过来呢?很多时候都是设备主动发出数据与消息,让C/C++里的函数处理,然后交由C#端进行显示或者二次处理。
答案就是利用C/C++里的函数指针与C#里的委托交互。
本文不做过多关于C#调用C/C++ DLL的讲解,主要讲解C/C++里的函数指针与C#里的委托交互用法。

大家可能会问,为什么要传递函数指针呢?利用PInvoke可以实现C#对C/C++函数的调用,反过来,我们能不能在C/C++程序运行的某一时刻,来调用一个C#对应的函数呢?(例如在C++中存在一个独立线程,该线程可能在任意时刻触发一个事件,并且需要通知C#)。这个时候,我们就有必要将一个C#中已经指向某一个函数的函数指针(委托)传递给C++。

学过C/C++ 的知道指针,呢么什么是函数指针。
关于什么是函数指针,大家可以自行查找资料,简言之,函数指针就是函数的地址。具体就是用一个特殊的指针表示函数名。那为什么函数名就可以理解为函数地址了呢。我们可以将函数名与数组名类比。在C/C++ 中,数组名就是数组的首地址,那么函数名也是一样。函数的地址存在于内存中某个特定的区域中。详细的内容大家可以参考C/C++ 内存四区 ,并且C/C++的衍生语言一直采用相同的内存模型。其实一切数据类型在内存中都是一个个地址去可以表示的,无论是结构体,基本数据类型,还是某个类,某个函数。他们都可以用一个32位的地址(具体多少位取决于你的操作系统)来表示。理解了这个,你就对函数指针有了初始理解了。

本文假设你已经提前了解了C# 委托,C#调用C/C++ DLL 的方式,C/C++ 编写类库的方法,C/C++的指针操作,以及WINDOWS API 创建线程的方法。不懂的话不要i着急,去查一查资料,写写demo,就会很快理解。

本文基于的IDE是VS2010,操作系统Windows。你使用最新的IDE也可以,但编写C/C++类库的方法可能稍有不同。
下面我会把详细的代码贴出,以及相关的注释。

C/C++ DLL项目:
在这里插入图片描述
C/C++ 代码
CPPDLL.h

// CPPDLL.h
///
#ifndef __CPPDLL_H__
#define __CPPDLL_H__
#define _EXTERN_C_  extern "C"  _declspec(dllexport)
#include <string>
#include <istream>
#include<Windows.h> //引用WindowsAPI的库
struct  SystemTime
{
	int  year;
	int  month;
	int  day;
	int  hour;
	int  minute;
	int  second;
	int  millsecond;
	SystemTime & operator= (SystemTime st)
	{
		this ->year = st.year;
		this ->month = st.month;
		this ->day = st.day;
		this ->hour = st.hour;
		this ->minute = st.minute;
		this ->second = st.second;
		this ->millsecond = st.millsecond;
		return  * this ;
	}
};
//定义一个函数指针
typedef void (__stdcall *CPPCallback)(int tick);

CPPCallback callbackGlobal;//定义一个函数指针的对象
DWORD WINAPI Function(LPVOID lpParamter);//Windows API 的创建线程的函数
//定义一个用于设置函数指针的方法,并在该函数中调用C#中传递过来的委托
_EXTERN_C_ void SetCallback(CPPCallback callback);

_EXTERN_C_  int  Add( int  x,  int  y);
_EXTERN_C_  int  Sub( int  x,  int  y);
_EXTERN_C_  int   TestChar( char  * src,  char  * res,  int  nCount);
_EXTERN_C_  int   TestStruct(SystemTime & stSrc, SystemTime & stRes);
_EXTERN_C_  void  WriteString(wchar_t*content);
//传入一个整型指针,将其所指向的内容加1
_EXTERN_C_ void  AddInt(int *i);
//传入一个整型数组的指针以及数组长度,遍历每一个元素并且输出
_EXTERN_C_ void  PrintArrayThroughCPP(int *firstElement,int arraylength);
//在C++中生成一个整型数组,并且数组指针返回给C#
_EXTERN_C_ int*  GetArrayFromCPP();
#endif //__CPPDLL_H__

CPPDLL.cpp

// 这是主 DLL 文件。

#include "stdafx.h"

#include "CPPDLL.h"

#include <stdio.h>

#include <time.h>
#include "iostream"

using namespace std;
int  Add( int  x,  int  y)
{
	return  x + y;
}
int  Sub( int  x,  int  y)
{
	return  x - y;
}
int  TestChar( char  * src,  char  * res,  int  nCount)
{
	memcpy (res, src,  sizeof ( char ) * nCount);
	return  1;
}
int  TestStruct(SystemTime & stSrc, SystemTime & stRes)
{
	stRes = stSrc;
	return  1;
}
void  WriteString(wchar_t* content){
	//第一次调用确认转换后单字节字符串的长度,用于开辟空间
	int pSize = WideCharToMultiByte(CP_OEMCP, 0, content, wcslen(content), NULL, 0, NULL, NULL);
	char* pCStrKey = new char[pSize+1];
	//第二次调用将双字节字符串转换成单字节字符串
	WideCharToMultiByte(CP_OEMCP, 0, content, wcslen(content), pCStrKey, pSize, NULL, NULL);
	pCStrKey[pSize] = '\0';
	cout<< pCStrKey<<endl;

	//如果想要转换成string,直接赋值即可
	//string pKey = pCStrKey;
}

void  AddInt(int *i)
{
	(*i)++;
}

void  PrintArrayThroughCPP(int *firstElement,int arrayLength)
{
	int*currentPointer=firstElement;
	for (int i = 0; i < arrayLength; i++)
	{
		cout<<*currentPointer;
		currentPointer++;
	}
	cout<<endl;
}


int*  GetArrayFromCPP()
{
	int *arrPtr=new int[10];
	for (int i = 0; i < 10; i++)
	{
		arrPtr[i]=i;
	}
	return arrPtr;
} 

void SetCallback(CPPCallback callback)
{
	//从C#来的回调对象callback赋值给本地全局函数指针对象callbackGlobal
	callbackGlobal=callback;
	//创建线程
	HANDLE hThread = CreateThread(NULL, 0, Function, NULL, 0, NULL);
	//线程结束关闭线程
	CloseHandle(hThread);
}


DWORD WINAPI Function(LPVOID lpParamter)
{
	//该线程每隔一秒向C#发送一个0到99之间的数字,并让C#处理该数据。
	cout << "A Thread Function Display!" << endl;
	srand((int)time(0));//随机数种子
	for (int i = 0; i < 10; i++){
		//下面的代码是对C#中委托进行调用,意即向C#发送数据
		callbackGlobal(rand()%100);
		Sleep(1000);
	}
	return 0L;
}

编译一下生成CPPDLL.dll, 将该dll 放在C#项目的debug目录下。
在这里插入图片描述

在这里插入图片描述

C#代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CSharpUseCppDll
{
	class Program
	{

		//定义一个委托,返回值为空,存在一个整型参数
		public delegate void CSCallback(int tick);
		//定义一个用于回调的方法,与前面定义的委托的原型一样
		//该方法会被C++所调用,收到来自C++主动发送的数据,并进行处理
		public static void CSCallbackFunction(int tick)
		{
			Console.WriteLine(tick.ToString());
		}
		//定义一个委托类型的实例,
		//在主程序中该委托实例将指向前面定义的CSCallbackFunction方法
		public static CSCallback callback;
		//这里使用CSCallback委托类型来兼容C++里的CPPCallback函数指针
		[DllImport("CPPDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		public extern static void SetCallback(CSCallback callback);
		static void Main(string[] args)
		{
			//在CS的主程序中让callback指向CSCallbackFunction方法,代码如下所示:
			//调用委托所指向的方法
			callback = new CSCallback(CSCallbackFunction);
			//将委托传递给C++
			SetCallback(callback);
			//SetCallback方法被执行后,在C#中定义的CSCallbackFunction就会被C++所调用。
			Console.ReadKey();
		}
	}
}

执行C#,显示结果:
在这里插入图片描述
每隔一秒打印一次随机数,打印十次。

参考博文:https://www.cnblogs.com/warensoft/archive/2011/12/09/Warenosoft3D.html

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-31 23:45:54  更:2022-03-31 23:46:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:58:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码