VC++:结合设备安装类GUID和设备接口类GUID获取设备VIDPID

前言:

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: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;
}



  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值