在vs2015中如何获取U盘的pid或vid

风尘星沙 2017-06-28 04:10:08
我想通过pid和vid等来获得指定U盘的设备路径,然后通过createfile来打开设备进行通讯,但是在获取设备属性的时候HidD_GetAttributes一直获取不到U盘的vid和pid,请大神指点下,下面是代码:



//保存HID设备的接口类GUID
GUID HidGuid;
//保存获取到的设备信息集合句柄
HDEVINFO hDevInfoSet;
//表示当前搜索到第几个设备,0表示第一个设备
DWORD MemberIndex;
//用来保存设备的驱动接口信息
SP_DEVICE_INTERFACE_DATA DevInterfaceData;
//保存函数调用是否返回成功
BOOL result;
//用来接收需要保存详细信息的缓冲长度
DWORD requiredSize;
//指向设备详细信息的结构体指针
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevDetailData;
//保存打开设备的句柄
HANDLE hDevHandle;
//保存设备属性
HIDD_ATTRIBUTES devAttributes;


myDevFound = FALSE;

//获取文本框中设置的Pid,Vid,Pvn
GetMyIDs();

//初始化读写句柄为无效句柄
hReadHandle = INVALID_HANDLE_VALUE;
hWritedHandle = INVALID_HANDLE_VALUE;

DevInterfaceData.cbSize = sizeof(DevInterfaceData);
devAttributes.Size = sizeof(devAttributes);

//获取HID设备的GUID,保存在HidGuid中
HidD_GetHidGuid(&HidGuid);

//根据HidGuid来获取设备信息集合,其中flags参数设置为DIGCF_DEVICEINTERFACE|DIGCF_PRESENT
//前者表示使用的GUID为接口类的GUID,后者表示只列举正在使用的设备,因为我们这里只查找连接上的设备
//返回 的句柄保存在hDevInfo,注意设备信息集合在使用了之后,要使用setupDIDestroyDeviveInfoList销毁,
//不然可能造成内存泄漏
hDevInfoSet = SetupDiGetClassDevs(&HidGuid,
NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

AddToInfOut("开始查找设备",TRUE,TRUE);
//然后对设备集合中的每个设备进行枚举,检查是否是我们要查找的设备
//当找到我们指定的设备,或者设备已经查找完毕时,就退出查找
//首先指向第一个设备,即将memberIndex置为零
MemberIndex = 0;
while (1)
{
//调用SetupDiEnumInterfaces函数在设备信息集合中获取参数为memberIndex的设备信息
result = SetupDiEnumDeviceInterfaces(
hDevInfoSet,
NULL,
&HidGuid,
MemberIndex,
&DevInterfaceData
);

if (result == FALSE)
break;
MemberIndex++;

//如果获取信息成功,则继续获取该设备的详细信息,在获取设备详细信息时,
//需要先知道保存详细信息需要多大的缓冲区,这通过第一次调用函数SetupDiGetDeviceInterfacesDetail
//来获取,这时 提供缓冲区和长度都为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(*pDevDetailData);

SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

//然后再次调用SetupDiGetDeviceInterfaceDetail函数来获取设备的详细信息,
//这次调用设置使用的缓冲区以及缓冲区的大小
result = SetupDiGetDeviceInterfaceDetail(
hDevInfoSet,
&DevInterfaceData,
pDevDetailData,
requiredSize,
NULL,
NULL
);
/* INT a= GetLastError();*/
//将设备路径取出来,然后销毁刚刚申请的内存
myDevPathName = pDevDetailData->DevicePath;
free(pDevDetailData);

//如果查找设备失败,则继续查找下一个设备
if (result == FALSE)
continue;

//如果调用成功,则使用不带读写访问的createfile函数来获取设备的属性,
//包括vid,pid,pvn,等,对于一些独占设备(例如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;

//如果获取成功,则将属性中的pid,vid,pvn与我们输入的比较
//如果一致则说明找到了我们要的设备
if (devAttributes.VendorID == myVid)
if (devAttributes.ProductID == myPid)
/*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("读访问打开设备成功",TRUE,TRUE);
else AddToInfOut("读访问打开设备失败",TRUE,TRUE);
//写访问的方式打开设备
hWritedHandle = CreateFile(myDevPathName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);

if (hWritedHandle != INVALID_HANDLE_VALUE)AddToInfOut("写访问打开设备成功",TRUE,TRUE);
else("写访问打开设备失败",TRUE,TRUE);

//可以发送数据
DataInsending = FALSE;
//手动触发事件,让读报告线程恢复运行,因为在这之前并没有调用读数据的函数,
//也就不会引起读事件的产生,所以需要先手动触发一次事件,让读报告线程恢复运行
SetEvent(readOverLapped.hEvent);

//显示设备的状态
SetDlgItemText(IDC_EDIT4, "设备已打开");

//找到设备,退出循环,本程序只检测一个目标设备,找到后就退出查找
//如果你需要把所以的目标设备的都列出来的话,可以设置一个数组,
//找到后就设置在数组中,直达所有设备都查找完毕才退出查找
break;
}
}
else
continue;


}
//调用setupDiDestroyDeviceInfoList销毁设备信息集合
SetupDiDestroyDeviceInfoList(hDevInfoSet);
//如果设备已经找到,应该使能各个功能按钮,同时使打开设备按钮失效
if (myDevFound)
{
GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON4)->EnableWindow(TRUE);

}
else
{
AddToInfOut("设备未找到",TRUE,TRUE);
}


...全文
71 点赞 收藏 1
写回复
1 条回复
赵4老师 2017年06月29日
搜“devcon”?
回复 点赞
发动态
发帖子
VC/MFC
创建于2007-09-28

7900

社区成员

42.1w+

社区内容

VC/MFC相关问题讨论
社区公告
暂无公告