Windows下USB HID设备通信
1. HID API
前面有写过一文来介绍 STM32F072 HID 自定义设备,这里记录windows下如何与之进行通信,也就是上位机的编写。windows作为主机端与HID设备通信流程大致如下:
- 通过VID/PID等信息查找到对应的设备路径
- 通过CreateFile获取设备的操作句柄
- 使用WriteFile/ReadFile、HidD_SetFeature/HidD_GetFeature 发送接收数据
- 关闭对应句柄,释放资源
windows 相关API
-
HANDLE CreateFile(
LPCWSTR lpFileName, // 指向路径的指针
DWORD dwDesiredAccess, // 访问模式(读/写)
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性的指针
DWORD dwCreationDisposition, // 如何创建
DWORD dwFlagsAndAttributes, // 文件属性(同步或异步)
HANDLE hTemplateFile // 用于复制文件句柄
); -
WriteFile(
HANDLE hFile, // 设备句柄,可通过CreateFile得到
LPCVOID lpBuffer, // 要发送的buffer(指针)
DWORD nNumberOfBytesToWrite, // 要发送数据的长度
LPDWORD lpNumberOfBytesWritten, // 实际发送数据的长度
LPOVERLAPPED lpOverlapped // OVERLAPPED结构体指针,如果设备是以FILE_FLAG_OVERLAPPED方式打开的话,那么这个指针就不能为NULL
); -
ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
); -
HidD_SetFeature (
HANDLE HidDeviceObject, // 设备句柄,通过CreateFile得到
PVOID ReportBuffer, // 待发送的数据
ULONG ReportBufferLength // 待发送数据的长度
); -
HidD_GetFeature (
HANDLE HidDeviceObject,
PVOID ReportBuffer,
ReportBufferLength
); -
HidD_SetOutputReport (
HANDLE HidDeviceObject,
PVOID ReportBuffer,
ULONG ReportBufferLength
); -
HidD_GetInputReport (
HANDLE HidDeviceObject,
PVOID ReportBuffer,
ULONG ReportBufferLength
); -
CloseHandle(
HANDLE hObject
);
所需开发库及头文件
-
添加库文件(附加依赖项)
setupapi.lib
hid.lib -
包含头文件
extern “C” {
#include “hidsdi.h”
#include “setupapi.h”
}
2. 查找设备
直接上代码
/*
HANDLE hWriteHandle = INVALID_HANDLE_VALUE;
HANDLE hReadHandle = INVALID_HANDLE_VALUE;
CString DevicePathName = "";
BOOL DeviceFound = FALSE;
UINT FoundDevice_Num;
HIDP_CAPS Capabilities;
PHIDP_PREPARSED_DATA HidParsedData;
*/
BOOL CUSB_HID_APPDlg::FindHidDevice(DWORD vid, DWORD pid)
{
GUID HidGuid; //定义一个GUID的结构体HidGuid来保存HID设备的接口类GUID
HDEVINFO hDevInfoSet; //定义一个DEVINFO的句柄hDevInfoSet来保存获取到的设备信息集合句柄
SP_DEVICE_INTERFACE_DATA DevInterfaceData; //DevInterfaceData,用来保存设备的驱动接口信息
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevDetailData; //定义一个指向设备详细信息的结构体指针
HIDD_ATTRIBUTES DevAttributes; //定义一个HIDD_ATTRIBUTES的结构体变量,保存设备的属性
DWORD RequiredSize; //定义一个RequiredSize的变量,用来接收需要保存详细信息的缓冲长度
HANDLE hDevHandle;
BOOL Result;
DWORD MemberIndex = 0; //定义MemberIndex,表示当前搜索到第几个设备,0表示第一个设备
FoundDevice_Num = 0;
DeviceFound = FALSE;
hWriteHandle = INVALID_HANDLE_VALUE;
hReadHandle = INVALID_HANDLE_VALUE;
hDevHandle = INVALID_HANDLE_VALUE;
DevInterfaceData.cbSize = sizeof(DevInterfaceData);
DevAttributes.Size = sizeof(DevAttributes);
HidD_GetHidGuid(&HidGuid);
hDevInfoSet = SetupDiGetClassDevs(&HidGuid,
NULL,
NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
while (1)
{
// 1
Result = SetupDiEnumDeviceInterfaces(hDevInfoSet,//设备信息集合句柄
NULL,
&HidGuid,
MemberIndex,
&DevInterfaceData);
if (Result == FALSE) break;
MemberIndex++; // search next
Result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
&DevInterfaceData,
NULL,
NULL,
&RequiredSize,
NULL);
pDevDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(RequiredSize);
if (pDevDetailData == NULL)
{
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return FALSE;
}
pDevDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// 2
Result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
&DevInterfaceData,
pDevDetailData,
RequiredSize,
NULL,
NULL);
DevicePathName = pDevDetailData->DevicePath;
free(pDevDetailData);
if (Result == FALSE)