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.zip
源代码:
WDK_VidPidQuery.h
/* ---------------------------------------------------------- 文件名称:WDK_VidPidQuery.h 作者:秦建辉 MSN:[email protected] 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; }