searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

在Windows平台上使用SetupDi API获取设备相关信息

2023-09-26 07:36:45
159
0

Windows操作系统提供了一组功能强大的API,用于管理和获取与设备相关的信息。其中之一是SetupDi(Setup Device Installation) API,它允许开发者在Windows平台上轻松地获取与设备安装和配置相关的信息。本文将介绍如何使用SetupDi API来获取设备的相关信息。

1. 引入SetupDi API

首先,要使用SetupDi API,需要包含头文件 setupapi.h 和链接库setupapi.lib,具体如下所示:

#include <Windows.h>
#include <SetupAPI.h>
#pragma comment(lib, "Setupapi.lib")   //让编译器在链接阶段将指定的库文件与生成的可执行文件进行关联

2. 初始化设备信息结构体

在使用SetupDi API之前,需要初始化一些数据结构,其中最重要的是SP_DEVINFO_DATA结构体,它将用于存储设备信息。

 
SP_DEVINFO_DATA deviceInfoData;
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

3. 获取设备信息

接下来,使用SetupDi API来获取设备信息。

3.1 获取设备信息集

设备信息集是一个包含了一个或多个设备信息元素的集合,每个元素代表了一个特定的设备或设备类。要获取设备信息集,可以使用SetupDiGetClassDevs函数,它的原型如下:

HDEVINFO SetupDiGetClassDevs(
  const GUID *ClassGuid,
  PCTSTR     Enumerator,
  HWND       hwndParent,
  DWORD      Flags
);
该函数的参数说明如下:
  • ClassGuid:指定要获取的设备类的GUID,如果为NULL,则获取所有设备类。
  • Enumerator:指定要获取的设备的枚举器名称,如果为NULL,则获取所有设备。
  • hwndParent:指定父窗口句柄,如果为NULL,则没有父窗口。
  • Flags:指定获取设备信息集的选项,可以是以下值的组合:
    • DIGCF_ALLCLASSES:获取所有设备类。
    • DIGCF_DEVICEINTERFACE:获取与指定类GUID关联的所有设备接口。
    • DIGCF_PRESENT:只获取当前存在的设备。
    • DIGCF_PROFILE:只获取当前配置文件中的设备。

该函数返回一个HDEVINFO类型的句柄,表示设备信息集。如果失败,则返回INVALID_HANDLE_VALUE,并通过GetLastError函数返回错误代码。

调用示例:

HDEVINFO deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);

3.2 遍历设备信息集

要遍历设备信息集中的每个设备信息元素,可以使用SetupDiEnumDeviceInfo函数,它的原型如下:

BOOL SetupDiEnumDeviceInfo(
  HDEVINFO         DeviceInfoSet,
  DWORD            MemberIndex,
  PSP_DEVINFO_DATA DeviceInfoData
);
该函数的参数说明如下:
  • DeviceInfoSet:指定要遍历的设备信息集句柄。
  • MemberIndex:指定要获取的设备信息元素的索引,从0开始递增。
  • DeviceInfoData:指向一个SP_DEVINFO_DATA结构的指针,用于接收设备信息元素的数据。

该函数返回一个布尔值,表示是否成功。如果成功,则DeviceInfoData指向的结构被填充。如果失败,则通过GetLastError函数返回错误代码。当遍历到最后一个元素时,GetLastError返回ERROR_NO_MORE_ITEMS。

调用示例:

SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData);

3.3 获取设备属性

要获取设备属性,可以使用SetupDiGetDeviceRegistryProperty函数,它的原型如下:

BOOL SetupDiGetDeviceRegistryProperty(
  HDEVINFO         DeviceInfoSet,
  PSP_DEVINFO_DATA DeviceInfoData,
  DWORD            Property,
  PDWORD           PropertyRegDataType,
  PBYTE            PropertyBuffer,
  DWORD            PropertyBufferSize,
  PDWORD           RequiredSize
);
该函数的参数说明如下:
  • DeviceInfoSet:指定要获取属性的设备所属的设备信息集句柄,由
     SetupDiGetClassDevs函数返回的句柄。 
  • DeviceInfoData:指向一个SP_DEVINFO_DATA结构的指针,表示要获取属性的设备。

  • Property:指定要获取的属性代码,常用的值包括:

    • SPDRP_CLASS:表示设备类名称。
    • SPDRP_CLASSGUID:表示设备类GUID。
    • SPDRP_DEVICEDESC:表示设备描述。
    • SPDRP_DRIVER:表示设备驱动程序键名称。
    • SPDRP_HARDWAREID:表示设备硬件ID列表。
    • SPDRP_INSTALL_STATE:表示设备安装状态。
    • SPDRP_MFG:表示设备制造商名称。
    • SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:表示物理设备对象名称。
    • 其他的属性可以参考微软官方文档

     

  • PropertyRegDataType:指向一个DWORD变量的指针,用于接收属性数据的注册表类型。

  • PropertyBuffer:指向一个缓冲区的指针,用于接收属性数据。如果为NULL,则只返回所需的缓冲区大小,不返回数据。

  • PropertyBufferSize:指定属性缓冲区的大小,以字节为单位。如果PropertyBuffer为NULL,则忽略此参数。

  • RequiredSize:指向一个DWORD变量的指针,用于接收属性数据所需的缓冲区大小,以字节为单位。如果为NULL,则忽略此参数。

该函数返回一个布尔值,表示是否成功。如果成功,则PropertyRegDataType、PropertyBuffer和RequiredSize指向的变量被填充。如果失败,则通过GetLastError函数返回错误代码。如果缓冲区太小,则GetLastError返回ERROR_INSUFFICIENT_BUFFER。

调用示例(获取设备硬件ID):

TCHAR hardwareID[MAX_DEVICE_ID];
if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID, NULL, (BYTE*)hardwareID, sizeof(hardwareID), NULL)) {
    // 硬件ID现在存储在hardwareID中
}

4. 清理资源

在使用完SetupDi API之后释放获取到的句柄资源。

SetupDiDestroyDeviceInfoList(deviceInfoSet);
 
 
完整示例代码:

以下是一个使用setupDi API获取系统中所有存在的USB设备友好名称的示例代码:

 
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>

#pragma comment(lib, "setupapi.lib")

int main()
{
    // 定义USB类GUID
    //GUID usbClassGuid = {0x36fc9e60,0xc465,0x11cf,{0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00}};
    GUID usbClassGuid = GUID_DEVCLASS_USB;   // #include <devguid.h>

    // 获取USB类的所有存在的设备信息集
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&usbClassGuid, NULL, NULL, DIGCF_PRESENT);

    // 检查是否成功
    if (hDevInfo == INVALID_HANDLE_VALUE)
    {
        printf("SetupDiGetClassDevs failed with error %d\n", GetLastError());
        return 1;
    }

    // 定义索引变量和结构体变量
    DWORD index = 0;
    SP_DEVINFO_DATA devInfoData;
    devInfoData.cbSize=sizeof(SP_DEVINFO_DATA);

   // 遍历设备信息集
    while (SetupDiEnumDeviceInfo(hDevInfo, index, &devInfoData))
    {
        // 定义缓冲区变量和大小变量
        TCHAR friendlyName[256];
        DWORD friendlyNameSize = sizeof(friendlyName);
  
        // 获取设备友好名称
        if (SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)friendlyName, friendlyNameSize, NULL))
        {
            // 打印设备友好名称
            printf("Device %d Friendly Name: %s\n", index, friendlyName);
        }
        else
        {
            // 打印错误信息
            printf("SetupDiGetDeviceRegistryProperty failed with error %d\n", GetLastError());
        }

        // 增加索引
        index++;
    }

    // 检查是否遍历完毕
    if (GetLastError() != ERROR_NO_MORE_ITEMS)
    {
        printf("SetupDiEnumDeviceInfo failed with error %d\n", GetLastError());
    }

    // 释放设备信息集
    SetupDiDestroyDeviceInfoList(hDevInfo);

    return 0;
}
 
0条评论
0 / 1000
w****n
3文章数
0粉丝数
w****n
3 文章 | 0 粉丝
原创

在Windows平台上使用SetupDi API获取设备相关信息

2023-09-26 07:36:45
159
0

Windows操作系统提供了一组功能强大的API,用于管理和获取与设备相关的信息。其中之一是SetupDi(Setup Device Installation) API,它允许开发者在Windows平台上轻松地获取与设备安装和配置相关的信息。本文将介绍如何使用SetupDi API来获取设备的相关信息。

1. 引入SetupDi API

首先,要使用SetupDi API,需要包含头文件 setupapi.h 和链接库setupapi.lib,具体如下所示:

#include <Windows.h>
#include <SetupAPI.h>
#pragma comment(lib, "Setupapi.lib")   //让编译器在链接阶段将指定的库文件与生成的可执行文件进行关联

2. 初始化设备信息结构体

在使用SetupDi API之前,需要初始化一些数据结构,其中最重要的是SP_DEVINFO_DATA结构体,它将用于存储设备信息。

 
SP_DEVINFO_DATA deviceInfoData;
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

3. 获取设备信息

接下来,使用SetupDi API来获取设备信息。

3.1 获取设备信息集

设备信息集是一个包含了一个或多个设备信息元素的集合,每个元素代表了一个特定的设备或设备类。要获取设备信息集,可以使用SetupDiGetClassDevs函数,它的原型如下:

HDEVINFO SetupDiGetClassDevs(
  const GUID *ClassGuid,
  PCTSTR     Enumerator,
  HWND       hwndParent,
  DWORD      Flags
);
该函数的参数说明如下:
  • ClassGuid:指定要获取的设备类的GUID,如果为NULL,则获取所有设备类。
  • Enumerator:指定要获取的设备的枚举器名称,如果为NULL,则获取所有设备。
  • hwndParent:指定父窗口句柄,如果为NULL,则没有父窗口。
  • Flags:指定获取设备信息集的选项,可以是以下值的组合:
    • DIGCF_ALLCLASSES:获取所有设备类。
    • DIGCF_DEVICEINTERFACE:获取与指定类GUID关联的所有设备接口。
    • DIGCF_PRESENT:只获取当前存在的设备。
    • DIGCF_PROFILE:只获取当前配置文件中的设备。

该函数返回一个HDEVINFO类型的句柄,表示设备信息集。如果失败,则返回INVALID_HANDLE_VALUE,并通过GetLastError函数返回错误代码。

调用示例:

HDEVINFO deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);

3.2 遍历设备信息集

要遍历设备信息集中的每个设备信息元素,可以使用SetupDiEnumDeviceInfo函数,它的原型如下:

BOOL SetupDiEnumDeviceInfo(
  HDEVINFO         DeviceInfoSet,
  DWORD            MemberIndex,
  PSP_DEVINFO_DATA DeviceInfoData
);
该函数的参数说明如下:
  • DeviceInfoSet:指定要遍历的设备信息集句柄。
  • MemberIndex:指定要获取的设备信息元素的索引,从0开始递增。
  • DeviceInfoData:指向一个SP_DEVINFO_DATA结构的指针,用于接收设备信息元素的数据。

该函数返回一个布尔值,表示是否成功。如果成功,则DeviceInfoData指向的结构被填充。如果失败,则通过GetLastError函数返回错误代码。当遍历到最后一个元素时,GetLastError返回ERROR_NO_MORE_ITEMS。

调用示例:

SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData);

3.3 获取设备属性

要获取设备属性,可以使用SetupDiGetDeviceRegistryProperty函数,它的原型如下:

BOOL SetupDiGetDeviceRegistryProperty(
  HDEVINFO         DeviceInfoSet,
  PSP_DEVINFO_DATA DeviceInfoData,
  DWORD            Property,
  PDWORD           PropertyRegDataType,
  PBYTE            PropertyBuffer,
  DWORD            PropertyBufferSize,
  PDWORD           RequiredSize
);
该函数的参数说明如下:
  • DeviceInfoSet:指定要获取属性的设备所属的设备信息集句柄,由
     SetupDiGetClassDevs函数返回的句柄。 
  • DeviceInfoData:指向一个SP_DEVINFO_DATA结构的指针,表示要获取属性的设备。

  • Property:指定要获取的属性代码,常用的值包括:

    • SPDRP_CLASS:表示设备类名称。
    • SPDRP_CLASSGUID:表示设备类GUID。
    • SPDRP_DEVICEDESC:表示设备描述。
    • SPDRP_DRIVER:表示设备驱动程序键名称。
    • SPDRP_HARDWAREID:表示设备硬件ID列表。
    • SPDRP_INSTALL_STATE:表示设备安装状态。
    • SPDRP_MFG:表示设备制造商名称。
    • SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:表示物理设备对象名称。
    • 其他的属性可以参考微软官方文档

     

  • PropertyRegDataType:指向一个DWORD变量的指针,用于接收属性数据的注册表类型。

  • PropertyBuffer:指向一个缓冲区的指针,用于接收属性数据。如果为NULL,则只返回所需的缓冲区大小,不返回数据。

  • PropertyBufferSize:指定属性缓冲区的大小,以字节为单位。如果PropertyBuffer为NULL,则忽略此参数。

  • RequiredSize:指向一个DWORD变量的指针,用于接收属性数据所需的缓冲区大小,以字节为单位。如果为NULL,则忽略此参数。

该函数返回一个布尔值,表示是否成功。如果成功,则PropertyRegDataType、PropertyBuffer和RequiredSize指向的变量被填充。如果失败,则通过GetLastError函数返回错误代码。如果缓冲区太小,则GetLastError返回ERROR_INSUFFICIENT_BUFFER。

调用示例(获取设备硬件ID):

TCHAR hardwareID[MAX_DEVICE_ID];
if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID, NULL, (BYTE*)hardwareID, sizeof(hardwareID), NULL)) {
    // 硬件ID现在存储在hardwareID中
}

4. 清理资源

在使用完SetupDi API之后释放获取到的句柄资源。

SetupDiDestroyDeviceInfoList(deviceInfoSet);
 
 
完整示例代码:

以下是一个使用setupDi API获取系统中所有存在的USB设备友好名称的示例代码:

 
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>

#pragma comment(lib, "setupapi.lib")

int main()
{
    // 定义USB类GUID
    //GUID usbClassGuid = {0x36fc9e60,0xc465,0x11cf,{0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00}};
    GUID usbClassGuid = GUID_DEVCLASS_USB;   // #include <devguid.h>

    // 获取USB类的所有存在的设备信息集
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&usbClassGuid, NULL, NULL, DIGCF_PRESENT);

    // 检查是否成功
    if (hDevInfo == INVALID_HANDLE_VALUE)
    {
        printf("SetupDiGetClassDevs failed with error %d\n", GetLastError());
        return 1;
    }

    // 定义索引变量和结构体变量
    DWORD index = 0;
    SP_DEVINFO_DATA devInfoData;
    devInfoData.cbSize=sizeof(SP_DEVINFO_DATA);

   // 遍历设备信息集
    while (SetupDiEnumDeviceInfo(hDevInfo, index, &devInfoData))
    {
        // 定义缓冲区变量和大小变量
        TCHAR friendlyName[256];
        DWORD friendlyNameSize = sizeof(friendlyName);
  
        // 获取设备友好名称
        if (SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)friendlyName, friendlyNameSize, NULL))
        {
            // 打印设备友好名称
            printf("Device %d Friendly Name: %s\n", index, friendlyName);
        }
        else
        {
            // 打印错误信息
            printf("SetupDiGetDeviceRegistryProperty failed with error %d\n", GetLastError());
        }

        // 增加索引
        index++;
    }

    // 检查是否遍历完毕
    if (GetLastError() != ERROR_NO_MORE_ITEMS)
    {
        printf("SetupDiEnumDeviceInfo failed with error %d\n", GetLastError());
    }

    // 释放设备信息集
    SetupDiDestroyDeviceInfoList(hDevInfo);

    return 0;
}
 
文章来自个人专栏
个人总结
3 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0