|
5精币
本帖最后由 大司命 于 2019-10-16 17:35 编辑
我附加下源码
#include "stdafx.h"
#include <hidusage.h>
#include <shidfact.h>
#include <hidpi.h>
#include <SetupAPI.h>
#include <hidsdi.h>
#include "HIDControl.h"
#pragma comment(lib,"hid.lib")
#pragma comment(lib,"setupapi.lib")
int CHIDControl::FindHIDDevice()
{
//定义一个GUID的结构体HidGuid来保存HID设备的接口类GUID。
GUID HidGuid;
//定义一个DEVINFO的句柄hDevInfoSet来保存获取到的设备信息集合句柄。
HDEVINFO hDevInfoSet;
//定义MemberIndex,表示当前搜索到第几个设备,0表示第一个设备。
DWORD MemberIndex;
//DevInterfaceData,用来保存设备的驱动接口信息
SP_DEVICE_INTERFACE_DATA DevInterfaceData;
//定义一个BOOL变量,保存函数调用是否返回成功
BOOL Result;
//定义一个RequiredSize的变量,用来接收需要保存详细信息的缓冲长度。
DWORD RequiredSize;
//定义一个指向设备详细信息的结构体指针。
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevDetailData;
//定义一个用来保存打开设备的句柄。
HANDLE hDevHandle;
//定义一个HIDD_ATTRIBUTES的结构体变量,保存设备的属性。
HIDD_ATTRIBUTES DevAttributes;
//初始化设备未找到
MyDevFound = FALSE;
//获取在文本框中设置的VID、PID、PVN。
//GetMyIDs();
MyVid = 0x0965;
MyPid = 0x6915;
MyPvn = 0;
//初始化读、写句柄为无效句柄。
hReadHandle = INVALID_HANDLE_VALUE;
hWriteHandle = INVALID_HANDLE_VALUE;
//对DevInterfaceData结构体的cbSize初始化为结构体大小
DevInterfaceData.cbSize = sizeof(DevInterfaceData);
//对DevAttributes结构体的Size初始化为结构体大小
DevAttributes.Size = sizeof(DevAttributes);
//调用HidD_GetHidGuid函数获取HID设备的GUID,并保存在HidGuid中。
HidD_GetHidGuid(&HidGuid);
//根据HidGuid来获取设备信息集合。其中Flags参数设置为
//DIG*FDEVICEINTERFACE|DIG*FPRESENT,前者表示使用的GUID为
//接口类GUID,后者表示只列举正在使用的设备,因为我们这里只
//查找已经连接上的设备。返回的句柄保存在hDevinfo中。注意设备
//信息集合在使用完毕后,要使用函数SetupDiDestroyDeviceInfoList
//销毁,不然会造成内存泄漏。
hDevInfoSet = SetupDiGetClassDevs(&HidGuid,
NULL,
NULL,
DIG*FDEVICEINTERFACE | DIG*FPRESENT);
//然后对设备集合中每个设备进行列举,检查是否是我们要找的设备
//当找到我们指定的设备,或者设备已经查找完毕时,就退出查找。
//首先指向第一个设备,即将MemberIndex置为0。
MemberIndex = 0;
while (1)
{
//调用SetupDiEnumDeviceInterfaces在设备信息集合中获取编号为
//MemberIndex的设备信息。
Result = SetupDiEnumDeviceInterfaces(hDevInfoSet,
NULL,
&HidGuid,
MemberIndex,
&DevInterfaceData);
//如果获取信息失败,则说明设备已经查找完毕,退出循环。
if (Result == FALSE) break;
//将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) //如果内存不足,则直接返回。
{
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return -1;
}
//并设置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.c_str(),
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; //设置设备已经找到
//那么就是我们要找的设备,分别使用读写方式打开之,并保存其句柄
//并且选择为异步访问方式。
//读方式打开设备
hReadHandle = CreateFile(MyDevPathName.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (hReadHandle != INVALID_HANDLE_VALUE);//cout << "读访问打开设备成功" << endl;
else return -2;// cout << "读访问打开设备失败" << endl;
//写方式打开设备
hWriteHandle = CreateFile(MyDevPathName.c_str(),
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (hWriteHandle != INVALID_HANDLE_VALUE);//cout << "写访问打开设备成功" << endl;
else return -3;//cout << "写访问打开设备失败" << endl;
DataInSending = FALSE; //可以发送数据
//手动触发事件,让读报告线程恢复运行。因为在这之前并没有调用
//读数据的函数,也就不会引起事件的产生,所以需要先手动触发一
//次事件,让读报告线程恢复运行。
SetEvent(ReadOverlapped.hEvent);
//显示设备的状态。
//SetDlgItemText(IDC_DS, "设备已打开");
//找到设备,退出循环。本程序只检测一个目标设备,查找到后就退出
//查找了。如果你需要将所有的目标设备都列出来的话,可以设置一个
//数组,找到后就保存在数组中,直到所有设备都查找完毕才退出查找
break;
}
}
}
//如果打开失败,则查找下一个设备
else continue;
}
//调用SetupDiDestroyDeviceInfoList函数销毁设备信息集合
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return 1;
}
|
|