前言:
VID和PID常被用于厂家的软件加密,只有在系统中检测到某VID和PID的设备时,软件才能运行。因此获取某一类型设备或者全部设备的VID和PID集合至关重要。获取设备VID和PID的一般流程是通过设备接口类GUID创建设备信息集,然后从设备接口详细信息中获取设备路径,再调用HidD_GetAttributes从属性中读取VID和PID。该方法的缺点是需要事先知道设备接口类GUID,且每次只能获取一个设备接口类的VID和PID集合。本方法既可以指定设备安装类GUID和/或设备接口类GUID,也可以两者都不指定而直接创建设备信息集,然后通过设备信息数据获取设备实例ID,并直接从设备实例ID中提取出VID和PID,巧妙地避开了对设备IO的读写。
源代码:
WDK_VidPidQuery.h
/* ----------------------------------------------------------
文件名称:WDK_VidPidQuery.h
作者:秦建辉
QQ:36748897
开发环境:
Visual Studio V2010
WinDDK 7600.16385.1
版本历史:
V1.0 2011年09月10日
结合设备安装类GUID和设备接口类GUID获取设备VIDPID
接口函数:
WDK_WhoAllVidPid
WDK_isExistVidPid
------------------------------------------------------------ */
#pragma once
#include <windows.h>
#ifndef MACRO_HIDD_VIDPID
#define MACRO_HIDD_VIDPID
typedef struct _HIDD_VIDPID
{
USHORT VendorID;
USHORT ProductID;
} HIDD_VIDPID;
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/*
功能:获取系统所有设备的VIDPID
入口参数:
[out] pVidPid:存储返回的VIDPID,会自动过滤掉重复的VIDPID
[in] iCapacity:存储单元的容量,建议为32
[in] SetupClassGuid:设备安装类GUID,默认为NULL
[in] InterfaceClassGuid:设备接口类GUID,默认为NULL
返回值:
获取到的VID和PID数目
优点:
直接通过设备实例ID提取VIDPID,从而无需获取设备路径来读写IO。
*/
INT WINAPI WDK_WhoAllVidPid( HIDD_VIDPID* pVidPid, INT iCapacity, const GUID* SetupClassGuid = NULL, const GUID* InterfaceClassGuid = NULL );
/*
功能:判断指定的VIDPID是否存在于列表中
入口参数:
[in] VendorID:要查找的VID
[in] ProductID:要查找的PID
[in] pVidPid:用来检索的VIDPID库
[in] iSize:VIDPID库大小
返回值:
TRUE:存在
FALSE:不存在
*/
BOOL WINAPI WDK_isExistVidPid( USHORT VendorID, USHORT ProductID, const HIDD_VIDPID* pVidPid, INT iSize );
#ifdef __cplusplus
}
#endif
WDK_VidPidQuery.cpp
#include "WDK_VidPidQuery.h"
#include <tchar.h>
#include <setupapi.h>
#pragma comment (lib, "Setupapi.lib")
#define DeviceInstanceIdSize 256 // 设备实例ID最大长度
// 获取系统的VID和PID集合
INT WINAPI WDK_WhoAllVidPid( HIDD_VIDPID* pVidPid, INT iCapacity, const GUID* SetupClassGuid, const GUID* InterfaceClassGuid )
{
// 检测入口参数
if (pVidPid == NULL || iCapacity <= 0) return 0;
// 根据设备安装类GUID创建空的设备信息集合
HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList( SetupClassGuid, NULL );
if (DeviceInfoSet == INVALID_HANDLE_VALUE) return -1;
// 根据设备安装类GUID获取设备信息集合
HDEVINFO hDevInfo;
if(InterfaceClassGuid == NULL)
hDevInfo = SetupDiGetClassDevsEx( NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE | DIGCF_PRESENT, DeviceInfoSet, NULL, NULL );
else
hDevInfo = SetupDiGetClassDevsEx( InterfaceClassGuid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT, DeviceInfoSet, NULL, NULL );
if (hDevInfo == INVALID_HANDLE_VALUE) return -1;
// 存储得到的VID和PID数目
INT iTotal = 0;
// 存储设备实例ID
TCHAR DeviceInstanceId[DeviceInstanceIdSize];
// 存储设备信息数据
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// 获取设备信息数据
DWORD DeviceIndex = 0;
while (SetupDiEnumDeviceInfo( hDevInfo, DeviceIndex++, &DeviceInfoData))
{
// 获取设备实例ID
if (SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, DeviceInstanceId, DeviceInstanceIdSize, NULL))
{
// 从设备实例ID中提取VID和PID
TCHAR* pVidIndex = _tcsstr(DeviceInstanceId, TEXT("VID_"));
if (pVidIndex == NULL) continue;
TCHAR* pPidIndex = _tcsstr(pVidIndex + 4, TEXT("PID_"));
if (pPidIndex == NULL) continue;
USHORT VendorID = _tcstoul(pVidIndex + 4, NULL, 16);
USHORT ProductID = _tcstoul(pPidIndex + 4, NULL, 16);
// 剔除重复的VID和PID
if (!WDK_isExistVidPid( VendorID, ProductID, pVidPid, iTotal ))
{
pVidPid[iTotal].VendorID = VendorID;
pVidPid[iTotal].ProductID = ProductID;
if (++iTotal >= iCapacity) break;
}
}
}
return iTotal;
}
// 判断VID和PID是否已经存在
BOOL WINAPI WDK_isExistVidPid( USHORT VendorID, USHORT ProductID, const HIDD_VIDPID* pVidPid, INT iSize )
{
if (pVidPid != NULL)
{
for (INT i = 0; i < iSize; i++)
{
if (pVidPid[i].VendorID == VendorID && pVidPid[i].ProductID == ProductID)
return TRUE;
}
}
return FALSE;
}