当前位置: 首页 > news >正文

HID 异步访问和同步访问

使用 Windows 自带 API 枚举并完成读写的详细步骤,参考下面两篇文章:

https://blog.csdn.net/phenixyf/article/details/72478933

https://blog.csdn.net/phenixyf/article/details/9153195

根据上面文章自己完成的 HID GUI 模板位置如下:

 

本文主要讲一下异步和同步方式读写 HID 的区别。

使用同步还是异步方式访问 HID 在下面两个地方确定:

  • 枚举 HID 设备过程中,用 CreateFile 打开 HID 设备时。(主要区别就是 CreateFile 倒数第二个参数)

        用同步方式打开 HID 设备:

hidHandle = CreateFile(devDetail->DevicePath,
					NULL,		// 第一次必须用非读写模式打开
					FILE_SHARE_READ | FILE_SHARE_WRITE,
					NULL,
					OPEN_EXISTING,
					0,		// 用同步方式
					NULL);

        用异步方式打开 HID 设备:

hidHandle = CreateFile(devDetail->DevicePath,
					NULL,		// 第一次必须用非读写模式打开
					FILE_SHARE_READ | FILE_SHARE_WRITE,
					NULL,
					OPEN_EXISTING,
					FILE_FLAG_OVERLAPPED,	// 用异步方式 (overlap)
					NULL);
  • 用 WriteFile 和 ReadFile 函数读写 HID 时。(主要区别就是 WriteFile, ReadFile 的最后一个参数)

        用同步方式读写

//写操作
WriteFile(hidHandle, Write_HID_Buf, HIDREPORTNUM, &bytesWritten, NULL);

//读操作
ReadFile(hidHandle, Read_HID_Buf, HIDREPORTNUM, &bytesRead, NULL);

        用异步方式读写 

//写操作
OVERLAPPED hid_write_overlap;	//定义 overlap 对象
WriteFile(hidHandle, Write_HID_Buf, HIDREPORTNUM, &bytesWritten, &hid_write_overlap);

//读操作
OVERLAPPED hid_read_overlap;    //定义 overlap 对象
ReadFile(hidHandle, Read_HID_Buf, HIDREPORTNUM, &bytesRead, &hid_read_overlap);

同步方式和异步方式操作过程中的不同:

  • 使用同步方式,当用 WriteFile 和 ReadFile 进行读写操作时,主进程会被阻塞,主进程的其它操作都会被block,直到读写操作完成后,主进程才能进行其它操作。
  • 使用异步方式就不会出现同步的阻塞现象,当 HID 设备在执行读写操作时,主进程仍可以进行其它操作。

所以一般情况下都会使用异步方式访问 HID 设备。

异步操作的具体实现

异步方式有两种实现方式:

  • 启动读写线程
  • 使用 overlap

用线程的方式比较麻烦,如果是在 Windows 系统开发,可以使用 overlap,具体实现如下代码

void ChidTemplateDlg::WriteHIDOutputReport()
{
	DWORD	bytesWritten = 0;
	BOOL	result = false;
	DWORD	res_wait_object;

	Write_HID_Buf[0] = REPORTID_DATA;

	if (hidHandle != INVALID_HANDLE_VALUE)
	{
		result = WriteFile(hidHandle, Write_HID_Buf, HIDREPORTNUM, &bytesWritten, &hid_write_overlap);

		if (!result)	//因为是 overlap 异步操作,所以 WriteFile 后不会马上返回 true,这是正常的。
						//判断最终写操作是否成功,是在下面的 switch 中
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{//当错误是ERROR_IO_PENDING,那意味着写文件的操作还在进行中
			 //等候,直到文件读完

				switch ( WaitForSingleObject(hidHandle, HIDREADTIMEOUT) )
				{
				case WAIT_OBJECT_0:
//					MessageBox(_T("HID write successfully"));
					break;
				case WAIT_TIMEOUT:
					MessageBox(_T("HID write fail: timeout"));

					CloseHandle(hidHandle);		// close hid handle
					OpenHIDDevice(1);			// re-open hid
					break;
				default:
					MessageBox(_T("HID write fail: in overlap process"));
					break;
				}	
			}
			else
			{
				MessageBox(_T("HID write fail: not in overlap process"));
			}
		}		
	}
	else
		MessageBox(_T("write hid fail: hid handle is invaliable"));
}


void ChidTemplateDlg::ReadHIDInputReport()
{

	DWORD	bytesRead = 0;
	BOOL	result = false;
	DWORD	res_wait_object;

	if (hidHandle != INVALID_HANDLE_VALUE)
	{
		result = ReadFile(hidHandle, Read_HID_Buf, HIDREPORTNUM, &bytesRead, &hid_read_overlap);

		if (!result)	//因为是 overlap 异步操作,所以 ReadFile 后不会马上返回 true,这是正常的。
						//判断最终读操作是否成功,是在下面的 switch 中
		{
			if (GetLastError() == ERROR_IO_PENDING)
			{//当错误是ERROR_IO_PENDING,那意味着读文件的操作还在进行中
			 //等候,直到文件读完

				switch (WaitForSingleObject(hidHandle, HIDREADTIMEOUT))
				{
				case WAIT_OBJECT_0:
					//					MessageBox(_T("HID write successfully"));
					break;
				case WAIT_TIMEOUT:
					MessageBox(_T("HID read fail: timeout"));

					CloseHandle(hidHandle);		// close hid handle
					OpenHIDDevice(1);			// re-open hid
					break;
				default:
					MessageBox(_T("HID read fail: in overlap process"));
					break;
				}
			}
			else
			{
				MessageBox(_T("HID read fail: not in overlap process"));
			}
		}
	}
	else
		MessageBox(_T("read hid fail: hid handle is invaliable"));
}

关于 overlap 及其使用的具体讲解可参考下面文章:

https://blog.csdn.net/phenixyf/article/details/126854005

https://blog.csdn.net/phenixyf/article/details/126853088

(582条消息) Overlapped_Phenixyf的博客-CSDN博客

相关文章:

  • 吊打面试官系列之:我这样回答 “如何更高效的进行接口测试“,面试官果然跪了。
  • 云资源管理
  • 【机器学习】树模型预剪枝和后剪枝
  • 性能提升 25 倍:Rust 有望取代 C 和 C++,成为机器学习首选 Python 后端
  • python一些操作的笔记
  • 4、乐趣国学—“行有不得,反求诸己。”
  • Github每日精选(第42期):web前端自定义Alert窗口sweetalert
  • “大厂”角力移动办公系统市场,钉钉和企微向左、WorkPlus向右
  • 面向有监督学习与文本数据的通用分类器
  • 为了学明白中断机制,我努力了
  • Python中的super函数,你熟吗?
  • 护眼灯频闪是什么意思?无频闪护眼灯哪个好
  • 「设计模式」六大原则之里氏替换原则小结
  • springboot+篮球场馆预约系统 毕业设计-附源码211706
  • vue实现【接口数据渲染随机显示】和【仅显示前五条数据】
  • cookie和session
  • docker-consul
  • js
  • laravel with 查询列表限制条数
  • Laravel 实践之路: 数据库迁移与数据填充
  • Linux后台研发超实用命令总结
  • PAT A1017 优先队列
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 我感觉这是史上最牛的防sql注入方法类
  • 用简单代码看卷积组块发展
  • Android开发者必备:推荐一款助力开发的开源APP
  • MyCAT水平分库
  • RDS-Mysql 物理备份恢复到本地数据库上
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (十三)Maven插件解析运行机制
  • (十一)c52学习之旅-动态数码管
  • (五)关系数据库标准语言SQL
  • (循环依赖问题)学习spring的第九天
  • .java 9 找不到符号_java找不到符号
  • .mysql secret在哪_MySQL如何使用索引
  • .Net core 6.0 升8.0
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET gRPC 和RESTful简单对比
  • @cacheable 是否缓存成功_Spring Cache缓存注解
  • @property括号内属性讲解
  • [ 数据结构 - C++]红黑树RBTree
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [AIGC codze] Kafka 的 rebalance 机制
  • [ASP.NET MVC]如何定制Numeric属性/字段验证消息
  • [C#] 如何调用Python脚本程序
  • [C#]猫叫人醒老鼠跑 C#的委托及事件