⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myusbhidtestappdlg.cpp

📁 对HID类设备进行读写
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  //将MemberIndex指向下一个设备
		MemberIndex++;

		//如果获取信息成功,则继续获取该设备的详细信息。在获取设备
		//详细信息时,需要先知道保存详细信息需要多大的缓冲区,这通过
		//第一次调用函数SetupDiGetDeviceInterfaceDetail来获取。这时
		//提供缓冲区和长度都为NULL的参数,并提供一个用来保存需要多大
		//缓冲区的变量RequiredSize。
		Result=SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
			                                      &DevInterfaceData,
																																									NULL,
																																									NULL,
																																									&RequiredSize,
																																									NULL);

		//然后,分配一个大小为RequiredSize缓冲区,用来保存设备详细信息。
		pDevDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(RequiredSize);
		if(pDevDetailData==NULL) //如果内存不足,则直接返回。
		{
			MessageBox("内存不足!");
			SetupDiDestroyDeviceInfoList(hDevInfoSet);
			return;
		}

		//并设置pDevDetailData的cbSize为结构体的大小(注意只是结构体大小,
		//不包括后面缓冲区)。
		pDevDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

		//然后再次调用SetupDiGetDeviceInterfaceDetail函数来获取设备的
		//详细信息。这次调用设置使用的缓冲区以及缓冲区大小。
		Result=SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
			                                      &DevInterfaceData,
																																									pDevDetailData,
																																									RequiredSize,
																																									NULL,
																																									NULL);

		//将设备路径复制出来,然后销毁刚刚申请的内存。
		MyDevPathName=pDevDetailData->DevicePath;
		free(pDevDetailData);

		//如果调用失败,则查找下一个设备。
		if(Result==FALSE) continue;

		//如果调用成功,则使用不带读写访问的CreateFile函数
		//来获取设备的属性,包括VID、PID、版本号等。
		//对于一些独占设备(例如USB键盘),使用读访问方式是无法打开的,
		//而使用不带读写访问的格式才可以打开这些设备,从而获取设备的属性。
  hDevHandle=CreateFile(MyDevPathName, 
			                     NULL,
                        FILE_SHARE_READ|FILE_SHARE_WRITE, 
                        NULL,
																								OPEN_EXISTING,
																								FILE_ATTRIBUTE_NORMAL,
																								NULL);

		//如果打开成功,则获取设备属性。
		if(hDevHandle!=INVALID_HANDLE_VALUE)
		{
			//获取设备的属性并保存在DevAttributes结构体中
			Result=HidD_GetAttributes(hDevHandle,
				                         &DevAttributes);

			//关闭刚刚打开的设备
			CloseHandle(hDevHandle);

   //获取失败,查找下一个
   if(Result==FALSE) continue;

			//如果获取成功,则将属性中的VID、PID以及设备版本号与我们需要的
			//进行比较,如果都一致的话,则说明它就是我们要找的设备。
			if(DevAttributes.VendorID==MyVid) //如果VID相等
				if(DevAttributes.ProductID==MyPid) //并且PID相等
			//		if(DevAttributes.VersionNumber==MyPvn) //并且设备版本号相等
					{
						MyDevFound=TRUE; //设置设备已经找到
						AddToInfOut("设备已经找到");

						//那么就是我们要找的设备,分别使用读写方式打开之,并保存其句柄
						//并且选择为异步访问方式。
      //读方式打开设备
      hReadHandle=CreateFile(MyDevPathName, 
			                          GENERIC_READ,
                             FILE_SHARE_READ|FILE_SHARE_WRITE, 
                             NULL,
																								     OPEN_EXISTING,
																								     FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
																								     NULL);
						if(hReadHandle!=INVALID_HANDLE_VALUE)AddToInfOut("读访问打开设备成功");
						else AddToInfOut("读访问打开设备失败");

						//写方式打开设备
      hWriteHandle=CreateFile(MyDevPathName, 
			                          GENERIC_WRITE,
                             FILE_SHARE_READ|FILE_SHARE_WRITE, 
                             NULL,
																								     OPEN_EXISTING,
																								     FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
																								     NULL);
						if(hWriteHandle!=INVALID_HANDLE_VALUE)AddToInfOut("写访问打开设备成功");
						else AddToInfOut("写访问打开设备失败");

						DataInSending=FALSE; //可以发送数据

      //手动触发事件,让读报告线程恢复运行。因为在这之前并没有调用
      //读数据的函数,也就不会引起事件的产生,所以需要先手动触发一
      //次事件,让读报告线程恢复运行。
						SetEvent(ReadOverlapped.hEvent);
      
						//显示设备的状态。
						SetDlgItemText(IDC_DS,"设备已打开");

						//找到设备,退出循环。本程序只检测一个目标设备,查找到后就退出
						//查找了。如果你需要将所有的目标设备都列出来的话,可以设置一个
						//数组,找到后就保存在数组中,直到所有设备都查找完毕才退出查找
						break;
					}
		}
		//如果打开失败,则查找下一个设备
		else continue;
	}

	//调用SetupDiDestroyDeviceInfoList函数销毁设备信息集合
	SetupDiDestroyDeviceInfoList(hDevInfoSet);

 //如果设备已经找到,那么应该使能各操作按钮,并同时禁止打开设备按钮
	if(MyDevFound)
	{
		//禁止打开设备按键,使能关闭设备、清计数器按键
		GetDlgItem(IDC_OPEN_DEVICE)->EnableWindow(FALSE);
		GetDlgItem(IDC_CLOSE_DEVICE)->EnableWindow(TRUE);
		GetDlgItem(IDC_CLEAR_COUNTER)->EnableWindow(TRUE);

  //使能LED控制按键。
		GetDlgItem(IDC_LED1)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED2)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED3)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED4)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED5)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED6)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED7)->EnableWindow(TRUE);
		GetDlgItem(IDC_LED8)->EnableWindow(TRUE);
	}
	else
	{
		AddToInfOut("设备未找到");
	}
}
//////////////////////////////End of function//////////////////////

//将整型转化为CString
CString CMyUsbHidTestAppDlg::itos(INT value, INT radix)
{
	static CString Str;
	UCHAR strBuffer[20];

	Str=itoa(value,(char *)strBuffer,radix);
	if(radix==16)
	{
		if(Str.GetLength()==1)	//如果只有1位数据,则在前面加3个0
		{
			Str="000"+Str;
		}
		if(Str.GetLength()==2)	//如果只有2位数据,则在前面加2个0
		{
			Str="00"+Str;
		}
			if(Str.GetLength()==3)	//如果只有3位数据,则在前面加1个0
		{
			Str="0"+Str;
		}
	}
	Str.MakeUpper();
	return Str;
}
//////////////////////////////End of function//////////////////////

//获取文本框中的内容并转换为数值
BOOL CMyUsbHidTestAppDlg::GetInputData(INT nID, CString ErrorMsg, DWORD &Value)
{
	CString InText;

	GetDlgItemText(nID,InText);	//获取输入的文本

	if((InText.GetLength()<=4)&&(sscanf(InText,"%x",&Value)))	//判断是否输入正确
	{
		SetDlgItemText(nID,itos(Value,16));	//设置文本
		return TRUE;
	}
	else	//输入错误,提示重新输入,并聚焦到错误的输入框
	{
		MessageBox(ErrorMsg,NULL,MB_OK | MB_ICONEXCLAMATION);
		GetDlgItem(nID)->SetFocus();
		((CEdit*)GetDlgItem(nID))->SetSel(0,-1);
		return FALSE;
	}
}
//////////////////////////////End of function//////////////////////

//从文本框中获取输入的VID、PID、PVN
void CMyUsbHidTestAppDlg::GetMyIDs()
{
 //从文本框中获取VID号,保存在MyVid中。
	GetInputData(IDC_VID_EDIT,"厂商ID(VID)输入格式错误。请重新输入。",MyVid);
 //从文本框中获取PID号,保存在MyPid中。
 GetInputData(IDC_PID_EDIT,"产品ID(PID)输入格式错误。请重新输入。",MyPid);
	//从文本框中获取PVN号,保存在MyPvn中。
	GetInputData(IDC_PVN_EDIT,"产品版本号(PVN)输入格式错误。请重新输入。",MyPvn);
}
//////////////////////////////End of function//////////////////////

//单击关闭设备按钮的响应函数
void CMyUsbHidTestAppDlg::OnCloseDevice() 
{
	// TODO: Add your control notification handler code here
	HICON hIcon;

	LedStatus=0;  //所有LED关闭
 KeyStatus=0;  //所有按键抬起

	//如果读数据的句柄不是无效句柄,则关闭之
	if(hReadHandle!=INVALID_HANDLE_VALUE)
	{
		CloseHandle(hReadHandle);
		hReadHandle=INVALID_HANDLE_VALUE;
	}
	//如果写数据的句柄不是无效句柄,先设置所有LED为关闭状态,
	//然后关闭句柄。
	if(hWriteHandle!=INVALID_HANDLE_VALUE)
	{
		SendLedStatus();
		CloseHandle(hWriteHandle);
		hWriteHandle=INVALID_HANDLE_VALUE;
	}

	//设置设备状态为未找到
	MyDevFound=FALSE;

	//修改按键使能情况
	GetDlgItem(IDC_OPEN_DEVICE)->EnableWindow(TRUE);
	GetDlgItem(IDC_CLOSE_DEVICE)->EnableWindow(FALSE);
	GetDlgItem(IDC_CLEAR_COUNTER)->EnableWindow(FALSE);
	//设置LED为关闭状态
	hIcon=AfxGetApp()->LoadIcon(IDI_LED_OFF);
	GetDlgItem(IDC_LED1)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED2)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED3)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED4)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED5)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED6)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED7)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	GetDlgItem(IDC_LED8)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
	//禁止LED
	GetDlgItem(IDC_LED1)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED2)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED3)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED4)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED5)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED6)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED7)->EnableWindow(FALSE);
	GetDlgItem(IDC_LED8)->EnableWindow(FALSE);

 //设置按键及显示的状态
	KeyStatus=0x00;
	SetKeyStatus();

	//显示关闭信息
	AddToInfOut("关闭设备");
 //显示设备的状态
	SetDlgItemText(IDC_DS,"设备已关闭");
}
//////////////////////////////End of function//////////////////////

//单击退出程序的按钮响应
void CMyUsbHidTestAppDlg::OnQuit() 
{
	// TODO: Add your control notification handler code here
	OnCloseDevice(); //退出程序前先关闭设备
 DestroyWindow(); //销毁窗口
}
//////////////////////////////End of function//////////////////////

//窗口关闭时的处理
void CMyUsbHidTestAppDlg::OnClose() 
{
	// TODO: Add your message handler code here and/or call default
	OnCloseDevice();  //关闭窗口前先关闭设备
	CDialog::OnClose();
}
//////////////////////////////End of function//////////////////////

//显示计数器的值
void CMyUsbHidTestAppDlg::SetCounterNumber(DWORD Counter)
{
	SetDlgItemText(IDC_COUNTER, "计数器值:" + itos(Counter));
}
//////////////////////////////End of function//////////////////////

//点击清除计数器按钮时的响应函数
void CMyUsbHidTestAppDlg::OnClearCounter() 
{
 //当输出报告的第二字节为非0值时,清除计数器值。
	WriteReportBuffer[2]=0xFF;
	if(SendLedStatus()==TRUE)
	{
		SetCounterNumber(0);
	}
}
//////////////////////////////End of function//////////////////////

//定时器事件处理
void CMyUsbHidTestAppDlg::OnTimer(UINT nIDEvent) 
{
	if(nIDEvent==1)	//刷新图标时间到,用来产生动作的小图标
	{
		HICON hIcon;
		static UINT i=0;
		switch(i)
		{
		case 0:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON7);
			i++;
			break;
		case 1:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON1);
			SetIcon(hIcon,TRUE);
			i++;
			break;
		case 2:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON2);
			SetIcon(hIcon,TRUE);
			i++;
			break;
		case 3:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON3);
			SetIcon(hIcon,TRUE);
			i++;
			break;
		case 4:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON4);
			SetIcon(hIcon,TRUE);
			i++;
			break;
		case 5:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON5);
			SetIcon(hIcon,TRUE);
			i++;
			break;
		case 6:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON6);
			SetIcon(hIcon,TRUE);
			i++;
			break;
		case 7:
			hIcon=AfxGetApp()->LoadIcon(IDI_ICON7);
			SetIcon(hIcon,TRUE);
			i=0;
			break;
		default:
			i=0;
			break;
		}
	}
	CDialog::OnTimer(nIDEvent);
}
//////////////////////////////End of function//////////////////////

//设备状态改变时的处理函数
BOOL CMyUsbHidTestAppDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
 PDEV_BROADCAST_DEVICEINTERFACE pdbi;
	CString DevPathName;

	//dwData是一个指向DEV_BROADCAST_DEVICEINTERFACE结构体的指针,
	//在该结构体中保存了设备的类型、路径名等参数。通过跟我们指定设备
	//的路径名比较,即可以判断是否是我们指定的设备拔下或者插入了。
	pdbi=(PDEV_BROADCAST_DEVICEINTERFACE)dwData;

	switch(nEventType) //参数nEventType中保存着事件的类型
	{
  //设备连接事件
		case DBT_DEVICEARRIVAL:
			if(pdbi->dbcc_devicetype==DBT_DEVTYP_DEVICEINTERFACE)
   {
				DevPathName=pdbi->dbcc_name; //保存发生状态改变的设备的路径名
				//比较是否是我们指定的设备
			 if(MyDevPathName.CompareNoCase(DevPathName)==0)
			 {
			 	AddToInfOut("设备已连接");
			 }
			}
			return TRUE;

  //设备拔出事件
		case DBT_DEVICEREMOVECOMPLETE: 
			if(pdbi->dbcc_devicetype==DBT_DEVTYP_DEVICEINTERFACE)
   {
				DevPathName=pdbi->dbcc_name; //保存发生状态改变的设备的路径名
				//比较是否是我们指定的设备
			 if(MyDevPathName.CompareNoCase(DevPathName)==0)
			 {
				 AddToInfOut("设备被拔出");
					//设备被拔出,应该关闭设备(如果处于打开状态的话),停止操作
					if(MyDevFound==TRUE)
					{
					 MyDevFound=FALSE;
			 	 OnCloseDevice();
					}
				}
			}
			return TRUE;

		default:
			return TRUE;
	} 
}
//////////////////////////////End of function//////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -