Ø Virtual Studio上建立“win32控制台”工程。
Ø 下载hid设备需要用到的头文件和lib文件到新建工程目录.
文件包括:Hid.h , hidsdi.h setupapi.h, hid.lib 。至于setupapi.lib好像不需要。
Ø 修改工程属性,添加lib:链接器->输入->附加依赖项中添加:hid.lib setupapi.lib
Ø 在新建工程xxx.cpp中添加头文件:
#include
#include
#include
extern "C"
{
#include "Hid.h"
#include "hidsdi.h"
#include "setupapi.h"
}
调用DDK提供的接口函数,获得设备设备信息,其中VID,PID, bcdDevice可以用来识别唯一的USB设备。使用此信息与要通信的设备的信息比对是否一致。
下面从原理的流程上讲述调用的API。
设备信息的API定义如下:
BOOLEAN __stdcall
HidD_GetAttributes (
IN HANDLE HidDeviceObject,
OUT PHIDD_ATTRIBUTES Attributes
);
第二个参数就是设备属性结构,由API输出,此结构定义如下:
typedef struct _HIDD_ATTRIBUTES {
ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
要使用此函数,还需要第一个入口参数:HidDeviceObject,这是一个指向设备的句柄,所以在调用HidD_GetAttributes前,先要调用CreateFile函数返回一个有效的设备操作句柄. 有了这个句柄才能与设备进行正常的通信。
此函数第一个参数需要完整的设备路径名,这个路径名是操作系统在识别到设备后分配给设备的, 可以通过DDK里的接口SetupDiGetDeviceInterfaceDetail来获取。
此函数定义如下:
BOOL SetupDiGetDeviceInterfaceDetail(
_In_ HDEVINFO DeviceInfoSet,
_In_ PSP_DEVICE_INTERFACE_DATADeviceInterfaceData,
_Out_opt_ PSP_DEVICE_INTERFACE_DETAIL_DATADeviceInterfaceDetailData,
_In_ DWORD DeviceInterfaceDetailDataSize,
_Out_opt_ PDWORD RequiredSize,
_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData
);
此函数可以获得接口设备详细信息,由第三个参数输出,第三个参数结构体定义如下:
typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
DWORD cbSize;
TCHARDevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;
在此结构体中我们看见了CreateFile所需要的一个参数设备路径。
那我们该如何调用SetupDiGetDeviceInterfaceDetail函数呢?下面直接给出调用方法,具体参数含义等参考msdn。此处调用2遍,第一遍调用的第五个输出参数RequiredSize作为第二遍调用时第四个输入参数使用。
HANDLE hDevInfo;
SP_DEVICE_INTERFACE_DATA devInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
SP_DEVINFO_DATA devInfoData;
//省略部分
ULONG ulLength;
SP_DEVINFO_DATA devInfoData;
BOOL bResult;
bResult = SetupDiGetDeviceInterfaceDetail (
hDevInfo,//--------------------------------------
&devInterfaceData,//--------------------------------------
NULL,
0,
&ulLength,
&devInfoData);
detailData = NULL;
//Allocate memory for the hDevInfo structure, using the returnedLength.
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) new unsignedchar[ulLength];
//Set cbSize in the detailData structure.
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Call the function again, this time passing it the returned buffersize.
ULONG ulRequired;
bResult = SetupDiGetDeviceInterfaceDetail(
hDevInfo,
&devInterfaceData,
detailData,
ulLength,
&ulRequired,
&devInfoData);
注:上面“省略部分”的程序完成功能是:准备SetupDiGetDeviceInterfaceDetail函数需要的2个输入参数。第一个输入参数DeviceInfoSet最后再说,先说第二个输入参数:DeviceInterfaceData,需要调用SetupDiEnumDeviceInterfaces函数获得(最后一个输出参数)。
函数定义如下:
BOOL SetupDiEnumDeviceInterfaces(
_In_ HDEVINFO DeviceInfoSet,
_In_opt_ PSP_DEVINFO_DATA DeviceInfoData,
_In_ const GUID *InterfaceClassGuid,
_In_ DWORD MemberIndex,
_Out_ PSP_DEVICE_INTERFACE_DATADeviceInterfaceData
);
此函数功能是枚举设备信息(DeviceInfoSet)中包含的某一个接口的信息(DeviceInterfaceData)。由于hid类下又可能有几个接口设备,比如鼠标,键盘,自己定义的HID设备等,MemberIndex就是索引依次获取设备信息。
第一个输入参数就是设备信息DeviceInfoSet(同SetupDiGetDeviceInterfaceDetail函数的第一个输入参数,最后讲述从何处获得),第二个参数可以为0,第三个参数是接口类型InterfaceClassGuid(下一步讲述),第四个参数就是索引,(所以此函数需要循环调用,index从0开始,直到获得PID,VID一致的设备,或者调用此函数返回FALSE),最有一个输出参数是设备接口数据DeviceInterfaceData,是调用此函数的目的,上面已讲述。
这部分较为简单,不再赘述。代码如下:
GUID m_Dev_Guid; //SetupDiEnumDeviceInterfaces函数第三个参数
HANDLE hDevInfo; // SetupDiEnumDeviceInterfaces函数第一个参数,SetupDiGetDeviceInterfaceDetailW
HidD_GetHidGuid(&m_Dev_Guid);
hDevInfo=SetupDiGetClassDevs
(&m_Dev_Guid,
NULL,
NULL,
DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
devInterfaceData.cbSize =sizeof(devInterfaceData);
char m_szDevicePath[MAX_PATH];
BOOL m_bDevFound = FALSE;
BOOL m_bDevOpened = FALSE;
void ScanDeviceByVidPid(unsigned short usVendorID,
unsigned short usProductID)
{
BOOL bResult;
ULONG ulLength;
ULONG ulRequired;
int iMemberIndex;
GUID m_Dev_Guid;
//Use a series of APIcalls to find a HID with a specified Vendor IF and Product ID.
HANDLE hDevInfo;
SP_DEVICE_INTERFACE_DATA devInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
SP_DEVINFO_DATA devInfoData;
m_bDevFound = FALSE;
HidD_GetHidGuid(&m_Dev_Guid);
hDevInfo=SetupDiGetClassDevs
(&m_Dev_Guid,
NULL,
NULL,
DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
devInterfaceData.cbSize =sizeof(devInterfaceData);
//Step through theavailable devices looking for the devices we want.
//All desired deviceswill be added to list.
for(iMemberIndex=0; ;iMemberIndex++)
{
if(SetupDiEnumDeviceInterfaces (
hDevInfo,
0,
&m_Dev_Guid,
iMemberIndex,
&devInterfaceData)== FALSE)
break;
//A device hasbeen detected, so get more information about it.
ZeroMemory(&devInfoData,sizeof(devInfoData));
devInfoData.cbSize= sizeof(devInfoData);
//Get theLength value.
//The call willreturn with a "buffer too small" error which can be ignored.
ulLength = 0;
bResult =SetupDiGetDeviceInterfaceDetail (
hDevInfo,
&devInterfaceData,
NULL,
0,
&ulLength,
&devInfoData);
detailData =NULL;
//Allocatememory for the hDevInfo structure, using the returned Length.
detailData =(PSP_DEVICE_INTERFACE_DETAIL_DATA) new unsigned char[ulLength];
//Set cbSize inthe detailData structure.
detailData->cbSize= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Call thefunction again, this time passing it the returned buffer size.
bResult =SetupDiGetDeviceInterfaceDetail
(hDevInfo,
&devInterfaceData,
detailData,
ulLength,
&ulRequired,
&devInfoData);
// here we can use HidD_GetAttributes to read vid and pid.
// but thisinterface need devhandle which comes from createfile.
// so to avoidto create file many times, we just search device path for vid and pid.
HANDLE hHandle=CreateFile(detailData->DevicePath,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
NULL,
NULL);
BOOLEAN Result;
HIDD_ATTRIBUTESAttributes;
// Set the Sizemember to the number of bytes
// in thestructure.
Attributes.Size= sizeof(Attributes);
Result =HidD_GetAttributes(hHandle, &Attributes);
::CloseHandle(hHandle);
strcpy(m_szDevicePath,detailData->DevicePath);
//Free thememory used by the detailData structure (no longer needed).
delete[]detailData;
if (Attributes.VendorID == usVendorID
&&Attributes.ProductID == usProductID )
{
m_bDevFound= TRUE;
break;
}
else
{
continue;
}
}
//Free the memoryreserved for hDevInfo by SetupDiClassDevs.
SetupDiDestroyDeviceInfoList(hDevInfo);
}
未完待续....