想做一个C++实现通过USB读取键盘发送的数据,即通过Readfile的同步通信模式,在执行到Readfile语句前程序阻塞,此时键盘再通过敲击给程序发送数据,程序读取键盘发送的数据存在buffer中。但是代码执行SetupDiGetClassDevs,SetupDiEnumDeviceInterfaces,两次SetupDiGetDeviceInterfaceDetail,createfile都正常,但执行到Readfile时却出现问题,始终没有想要的效果,大家觉得有什么问题啊。源代码如下:
int main()
{
ULONG Required;
//定义strUsbPath 设备路径
CString strUsbPath;
//定义一个GUID的结构体HidGuid来保存HID设备的接口类GUID。
GUID GUID_DEVINTERFACE_USB_DEVICE = {0xA5DCBF10,0x6530,0x11D2,0x90,0x1F,0x00,0xC0,0x4F,0xB9,0x51,0xED};
GUID HidGuid;
//定义一个DEVINFO的句柄hDevInfoSet来保存获取到的设备信息集合句柄。
HDEVINFO hDevInfoSet;
//DevInfoData,用来保存设备的驱动接口信息
SP_DEVICE_INTERFACE_DATA DevInfoData;
//定义一个BOOL变量,保存函数调用是否返回成功
BOOL Result;
//定义一个RequiredSize的变量,用来接收需要保存详细信息的缓冲长度。
DWORD RequiredSize;
//定义一个指向设备详细信息的结构体指针。
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevDetailData;
//定义一个用来保存打开设备的句柄。
HANDLE DevHandle;
//定义一个HIDD_ATTRIBUTES的结构体变量,保存设备的属性。
HIDD_ATTRIBUTES DevAttributes;
//对DevInfoData结构体的cbSize初始化为结构体大小
DevInfoData.cbSize=sizeof(DevInfoData);
//调用HidD_GetHidGuid函数获取HID设备的GUID,并保存在HidGuid中。
HidD_GetHidGuid(&HidGuid);
hDevInfoSet=SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,NULL,NULL,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if (hDevInfoSet == INVALID_HANDLE_VALUE)
{
cout<<"没有找到正在使用的设备"<<endl;
SetupDiDestroyDeviceInfoList(hDevInfoSet);
}
int MemberIndex=0;
while(1)
{
cout<<"开始枚举第"<<MemberIndex+1<<"个设备"<<endl;
//调用SetupDiEnumDeviceInterfaces在设备信息集合中获取编号为MemberIndex的设备信息。
Result=SetupDiEnumDeviceInterfaces(hDevInfoSet,NULL,&GUID_DEVINTERFACE_USB_DEVICE,MemberIndex,&DevInfoData);
MemberIndex++;
if(Result==FALSE){cout<<"获取设备信息失败"<<endl;break;}
Result=SetupDiGetDeviceInterfaceDetail(hDevInfoSet,&DevInfoData,NULL,0,&RequiredSize,NULL);
if (Result==FALSE)
{
cout<<"第一次获取设备细节失败,错误代码为"<<GetLastError()<<endl;
}
//然后,分配一个大小为RequiredSize缓冲区,用来保存设备详细信息。
pDevDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(RequiredSize);
if(pDevDetailData==NULL) //如果内存不足,则直接返回。
{
//TRACE("内存不足!");
cout<<"内存不足"<<endl;
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return FALSE;
}
//并设置pDevDetailData的cbSize为结构体的大小(注意只是结构体大小,不包括后面缓冲区)
pDevDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//然后再次调用SetupDiGetDeviceInterfaceDetail函数来获取设备的详细信息。这次调用设置使用的缓冲区以及缓冲区大小。
Result=SetupDiGetDeviceInterfaceDetail(hDevInfoSet,&DevInfoData,pDevDetailData,RequiredSize,&Required,NULL);
//如果调用失败,则查找下一个设备。
if(Result==FALSE) {cout<<"第二次获取设备细节失败"<<endl;continue;}
//将设备路径复制出来,然后销毁刚刚申请的内存。
CString m_strDevicePath;//=pDevDetailData->DevicePath;
cout<<"格式化前设备路径"<<m_strDevicePath<<endl;
m_strDevicePath.Format(_T("%s"),pDevDetailData->DevicePath);
cout<<"设备路径为"<<m_strDevicePath<<endl;
free(pDevDetailData);
DevHandle=CreateFile(m_strDevicePath,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,(LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,0,NULL);
if(DevHandle == INVALID_HANDLE_VALUE)
{
cout<<"创建设备句柄失败,失败代码为 "<< GetLastError()<<endl;
}
//如果打开成功,则获取设备属性。
if(DevHandle!=INVALID_HANDLE_VALUE)
{
cout<<"创建设备句柄成功"<<endl;
//获取设备的属性并保存在DevAttributes结构体中
Result=HidD_GetAttributes(DevHandle,&DevAttributes);
//获取失败,查找下一个
if(Result==FALSE)
{
//关闭刚刚打开的设备
cout<<"获取设备HID属性失败,关闭该句柄,继续枚举下一设备,错误代码为 "<<GetLastError()<<endl;
CloseHandle(DevHandle);
DevHandle=NULL;
}
else cout<<DevAttributes.ProductID<<"||"<<DevAttributes.Size<<"||"<<DevAttributes.VendorID<<"||"<<DevAttributes.VersionNumber<<endl;
}
char buf[1024];DWORD len = 0;
bool res = ReadFile(DevHandle,buf,1024,&len,NULL);
if(!res)
{
cout<<"读取设备失败,关闭该句柄,失败代码为 "<<GetLastError()<<endl;
CloseHandle(DevHandle);
}
cout<<endl;
}
return 0;
}
------解决方案--------------------
你说的很对。理论上来说Readfile应该可以。
Readfile不能正确返回的原因可能是键盘的驱动队列里面,没有驱动来响应你的这个ReadFile对应的IRP_MJ_READ请求。
如果你调试对应的HID MiniDriver你可能就会知道,该MiniDriver可能只支持Read Report/Read Feature之类的IRP/IOCTL请求。