您的位置:首页 > 编程语言 > C语言/C++

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

2015-07-06 10:30 573 查看
前言:
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  加密 接口 检测