前言:

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


作者:秦建辉


MSN:splashcn@msn.com

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;

}