Qt篇——Qt使用C++获取Windows电脑上所有外接设备的名称、物理端口位置等信息

news2024/12/28 21:40:08

        我之前有发过一篇文章《Qt篇——获取Windows系统上插入的串口设备的物理序号》,文章中主要获取的是插入的USB串口设备的物理序号;而本篇文章则进行拓展,可以获取所有外接设备的相关信息(比如USB摄像头、USB蓝牙、USB网卡、其它一些可拔插的设备等等),并且代码进行了优化、精简。代码如下,可直接cv享用。(代码中有一段筛选相机设备的代码被注释掉了,如果你仅仅只需要获取到相机的设置信息,可以取消注释。)

#include <QDebug>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>

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

void DevicesTool::listCameras() {
    // 获取所有图像设备, GUID_DEVCLASS_USB、GUID_DEVCLASS_SYSTEM等等都可以,根据实际需求选择
    HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_USB, nullptr, nullptr, DIGCF_PRESENT | DIGCF_ALLCLASSES);
    if (deviceInfoSet == INVALID_HANDLE_VALUE) {
        qDebug() << "Failed to get device info set";
        return;
    }

    SP_DEVINFO_DATA deviceInfoData;
    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    // 遍历设备列表
    for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoSet, i, &deviceInfoData); i++) {
        TCHAR deviceName[256];
        QString deviceDescStr = "", deviceNameStr = "", deviceLocationInfoStr = "", deviceLocationPathStr;
        if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC, nullptr,
                                             (PBYTE)deviceName, sizeof(deviceName), nullptr)) {
            deviceDescStr= QString::fromWCharArray(deviceName);
        }
        if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_FRIENDLYNAME, nullptr,
                                             (PBYTE)deviceName, sizeof(deviceName), nullptr)) {
            deviceNameStr = QString::fromWCharArray(deviceName);
        }
        if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_LOCATION_INFORMATION, nullptr,
                                             (PBYTE)deviceName, sizeof(deviceName), nullptr)) {
            deviceLocationInfoStr = QString::fromWCharArray(deviceName);
        }
        if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_LOCATION_PATHS, nullptr,
                                             (PBYTE)deviceName, sizeof(deviceName), nullptr)) {
            deviceLocationPathStr = QString::fromWCharArray(deviceName);
        }
        if (deviceLocationInfoStr != "" && deviceDescStr != "" && deviceNameStr != "" && deviceLocationPathStr != "") {
            qDebug() << "Device: " << deviceDescStr << deviceNameStr << deviceLocationInfoStr << deviceLocationPathStr;
        }
        //如果只需要USB相机设备的信息,可以再筛选一条属性
        //index值越小代表着用opencv的VideoCapture.open()里面的相机序号越靠前
/**
        int index = -1;
        if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DRIVER, nullptr,
                                             (PBYTE)deviceName, sizeof(deviceName), nullptr)) {
            index = QString::fromWCharArray(deviceName).split("\\")[1].toInt();
        }
        if (deviceLocationInfoStr != "" && deviceDescStr != ""
            && deviceNameStr != "" && deviceLocationPathStr != "" && index != -1) {
            qDebug() << "Device: " << deviceDescStr << deviceNameStr << deviceLocationInfoStr << deviceLocationPathStr << index;
            cameraList.append(new DeviceInfo(deviceNameStr, deviceDescStr, deviceLocationInfoStr, deviceLocationPathStr, index));
        }
*/
    }

    SetupDiDestroyDeviceInfoList(deviceInfoSet);
}

打印结果如下:

 比如我获取到的4个USB 视频设备就是我插入的3个USB相机、系统自带的相机,这里就可以知道哪个相机插在哪个USB口上面了(右键此电脑-管理-设备管理器-照相机,双击我要查看的相机,里面的“位置”就是上面代码中获取到的deviceLocationInfoStr)。

        ps:其实还有更多设备信息可以查看,只是我打印的地方进行了筛选,只有4项信息(物理端口信息、物理端口路径、设备信息、设备名称)都能够获取的才进行打印,可以根据你实际需求降低筛选。 

需要了解代码原理的看这里,这里简单地介绍各个函数的用途:

1.SetupDiGetClassDevs函数返回一个包含本机上所有被请求的设备信息的设备信息集合句柄。

HDEVINFO SetupDiGetClassDevs(
  _In_opt_ const GUID   *ClassGuid, // 一个指向GUID的指针,此GUID可标识一个设备安装类或一个设备接口类, 可以为NULL
  _In_opt_       PCTSTR Enumerator, // 一个指向以空字符结束的字符串的指针
  _In_opt_       HWND   hwndParent, // 用于与在设备信息集中安装设备实例相关联的用户界面的顶级窗口句柄
  _In_           DWORD  Flags       // 通过此参数来过滤指定的设备信息集中的设备, DIGCF_PRESENT表示只返回当前系统中存在的(已连接)设备。
);

        该函数的第一个入口参数GUID指定了我们想要检索什么类型的设备,一些常用的GUID如下:

GUID_DEVCLASS_SYSTEM    // 系统设备GUID
GUID_DEVCLASS_USB       // USB设备GUID
GUID_DEVCLASS_MOUSE     // 鼠标设备GUID
GUID_DEVCLASS_NET       // 网络设备GUID
GUID_DEVCLASS_KEYBOARD  // 键盘设备GUID

        当调用完此函数并处理完相应数据后,必须调用SetupDiDestroyDeviceInfoList函数,否则内存溢出。

2.SetupDiEnumDeviceInfo函数返回一个SP_DEVINFO_DATA结构,它指定该设备的信息集的设备的信息元素。

BOOL SetupDiEnumDeviceInfo(
    _In_ HDEVINFO DeviceInfoSet,          // 设备信息集的句柄,即SetupDiGetClassDevs返回的句柄
    _In_ DWORD MemberIndex,               // 要检索的设备信息元素的从零开始的索引
    _Out_ PSP_DEVINFO_DATA DeviceInfoData // 指向SP_DEVINFO_DATA结构的指针,以接收有关枚举设备信息元素的信息
    );

3.SetupDiGetDeviceRegistryProperty检索指定的即插即用设备属性.

BOOL SetupDiGetDeviceRegistryPropertyW(
    _In_ HDEVINFO DeviceInfoSet,          // 设备信息集的句柄,即SetupDiGetClassDevs返回的句柄
    _In_ PSP_DEVINFO_DATA DeviceInfoData, // 指向SP_DEVINFO_DATA结构的指针,该结构指定DeviceInfoSet中的设备信息元素
    _In_ DWORD Property,                  // 指定要检索的属性
    _Out_opt_ PDWORD PropertyRegDataType, // 指向一个变量的指针,该变量接收要检索的属性的数据类型。
    _Out_writes_bytes_to_opt_(PropertyBufferSize, *RequiredSize) PBYTE PropertyBuffer, // 指向缓冲区的指针,该缓冲区接收正在检索的属性
    _In_ DWORD PropertyBufferSize,        // PropertyBuffer缓冲区的大小(单位:字节)
    _Out_opt_ PDWORD RequiredSize         // 指向DWORD类型的变量的指针,该变量接收所需的PropertyBuffer缓冲区的大小(单位:字节)
    );

        该函数的第三个入口参数Property决定了我们想要检索设备的什么属性,它的取值可以在SetupAPI.h文件里查找,一些常用的属性的含义如下:

#常用
#define SPDRP_DEVICEDESC                  (0x00000000)  // DeviceDesc (R/W)
#define SPDRP_FRIENDLYNAME                (0x0000000C)  // FriendlyName (R/W)
#define SPDRP_LOCATION_INFORMATION        (0x0000000D)  // LocationInformation (R/W)

#其他
#define SPDRP_HARDWAREID                  (0x00000001)  // HardwareID (R/W)
#define SPDRP_COMPATIBLEIDS               (0x00000002)  // CompatibleIDs (R/W)
#define SPDRP_CLASS                       (0x00000007)  // Class (R--tied to ClassGUID)
#define SPDRP_CLASSGUID                   (0x00000008)  // ClassGUID (R/W)
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2124045.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端转鸿蒙好做吗

在科技不断发展的当下&#xff0c;许多前端开发者可能会思考一个问题&#xff1a;前端转鸿蒙好做吗? 一、前端与鸿蒙开发的差异 1. 技术栈的变化 前端开发主要涉及 HTML、CSS、JavaScript 等技术&#xff0c;而鸿蒙开发则需要掌握 Java、Kotlin、JavaScript 等语言&#xff0c…

远程存储 RDMA

什么是 RDMA RDMA&#xff08;Remote Direct Memory Access&#xff09;指的是远程直接内存访问&#xff0c;这是一种通过网络在两个应用程序之间搬运缓冲区里的数据的方法。 Remote&#xff1a;数据通过网络与远程机器间进行数据传输。 Direct&#xff1a;没有内核的参与&am…

计算机毕业设计 | 基于SpringBoot的健身房管理系统(附源码)

1&#xff0c;项目背景 随着人们生活水平的提高和健康意识的增强&#xff0c;越来越多的人开始关注自己的身体健康并加入到健身行列中。然而&#xff0c;传统的健身房管理方式往往存在诸多问题&#xff0c;如会员信息管理混乱、课程安排不合理、教练资源分配不均等&#xff0c…

MaxCompute基础概论

1. 简介与背景 随着大数据技术的发展&#xff0c;企业和组织面临着处理海量数据的挑战。传统的数据存储和处理工具难以应对高并发、复杂计算以及海量数据的快速增长需求。为了解决这些问题&#xff0c;阿里云推出了 MaxCompute&#xff08;原名 ODPS&#xff09;&#xff0c;这…

超声波雪深监测站

超声波雪深监测站是一种用于测量和监测雪深的设备。它的功能和作用主要包括以下几个方面&#xff1a; 雪深测量&#xff1a;超声波雪深监测站能够通过发射超声波并接收回波的方式&#xff0c;测量雪地表面到地面之间的距离&#xff0c;从而得到雪深的数据。通过分析和处理这些数…

图像去噪的艺术:自适应中值滤波器的应用与实践

在数字图像处理的众多挑战中&#xff0c;噪声的去除是一个永恒的话题。特别是椒盐噪声&#xff0c;因其随机将像素点变为极黑或极白&#xff0c;对图像的视觉质量破坏极大。本文将通过MATLAB实现的自适应中值滤波器&#xff08;AMF&#xff09;&#xff0c;探讨其在图像去噪中的…

--- 数据结构 二叉树 --- java

树形结构 数使一个非线性结构&#xff0c;他是由n个结点组成的具有一定层次关系的集合&#xff0c;叫做树是因为他像是一颗倒挂的树&#xff0c;根在上&#xff0c;叶子在下&#xff0c;具有一些性质 1&#xff0c;有一个特殊节点叫做根节点&#xff0c;他没有钱去节点&#x…

017_Python爬虫系列_防盗链代理

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数…

限流,流量整形算法

写在前面 本文看下流量整形相关算法。 目前流量整形算法主要有三种&#xff0c;计数器&#xff0c;漏桶&#xff0c;令牌桶。分别看下咯&#xff01; 1&#xff1a;计数器 1.1&#xff1a;描述 单位时间内只允许指定数量的请求&#xff0c;如果是时间区间内超过指定数量&a…

用Python实现时间序列模型实战——Day 17: 时间序列模型的评估方法

一、学习内容 1. 预测误差的评估指标 在时间序列预测中&#xff0c;常用的评估指标包括 MAE (Mean Absolute Error), MSE (Mean Squared Error) 和 RMSE (Root Mean Squared Error)。这些指标用于衡量模型的预测误差。 MAE (Mean Absolute Error)&#xff1a; MAE 衡量预测值…

mysql学习教程,从入门到精通,MySQL WHERE 子句(10)

1、SQL WHERE 子句 在本教程中&#xff0c;您将学习如何使用SQL从表中选择特定记录。 根据条件选择记录 在上一章中&#xff0c;我们学习了如何从表或表列中获取所有记录。但是&#xff0c;在现实世界中&#xff0c;我们通常只需要选择&#xff0c;更新或删除满足某些条件的那…

HarmonyOS---应用测试概述

一、应用质量要求 应用质量要求分为应用体验质量建议和应用内容合规要求两大部分。 1、应用体验质量建议 功能数据完备、基础体验要求、HarmonyOS特征增强体验要求。 &#xff08;1&#xff09;功能数据完备 &#xff08;2&#xff09;基础体验要求 &#xff08;3&#xff09;增…

盘古信息IMS 驱动智能工厂建设,助力制造企业降本增效

随着全球化的加剧和市场竞争的日益激烈&#xff0c;制造业面临着提高生产效率、降低成本、提升产品质量以及实现绿色可持续发展等多重压力。智能工厂是利用人工智能、大数据、物联网、云计算等新技术&#xff0c;实现工厂的智能化、自动化、可持续化发展的新型制造业模式&#…

《深度学习》OpenCV 高阶 图像直方图、掩码图像 参数解析及案例实现

目录 一、图像直方图 1、什么是图像直方图 2、作用 1&#xff09;分析图像的亮度分布 2&#xff09;判断图像的对比度 3&#xff09;检测图像的亮度和色彩偏移 4&#xff09;图像增强和调整 5&#xff09;阈值分割 3、举例 二、直方图用法 1、函数用法 2、参数解析…

芋道快速开发平台的使用心得

1.前端版本 项目的管理后台有 4 个版本&#xff1a; yudao-ui-admin-vue3 (opens new window)&#xff1a;基于 Vue3 element-plus yudao-ui-admin-vben (opens new window)&#xff1a;基于 Vue3 vben(ant-design-vue) yudao-ui-admin-vue2 (opens new window)&#xff…

LaTeX中制作表格【表格数据自动换行】(附latex源码)

一、latex软件推荐 在使用LaTeX进行文档编写时&#xff0c;有几款非常受欢迎且功能强大的软件和在线编辑器可供选择。以下是一些推荐的LaTeX软件&#xff1a; 1. Overleaf(强烈推荐) Your Projects - Overleaf, Online LaTeX Editorhttps://www.overleaf.com/project 2.Tex…

图新说【消防】(一步步的做好态势标绘)

0.序 越来越多的消防战士使用图新说来做消防预案&#xff0c;态势标绘比武等。 图新说即可应用于具体的消防救援任务&#xff0c;制作具体的作战方案&#xff0c;让战士的配合更加紧密。 也可以做大型的消防预案&#xff0c;针对辖区内的重点建筑、危化存储区提前做应急救援方…

最新版MYMPay码支付开源版系统源码_个人免签支付_聚合支付系统

最新版MYMPay码支付开源版系统源码_个人免签支付_聚合支付系统 安装环境&#xff1a; PHP&#xff1a;7.0-8.2 (推荐使用7.4) 需要安装Xload 扩展 MySQL&#xff1a;5.6版本 访问 http://你的域名/install 进行安装 后台地址&#xff1a;http://你的域名/Admin/ 账号&am…

C++笔记之map的实用操作

C++笔记之map的实用操作 文章目录 C++笔记之map的实用操作1.初始化1.1.使用列表初始化1.2.使用 `insert` 方法1.3.使用 `emplace` 方法1.4.复制构造1.5.移动构造2.赋值2.1.列表赋值2.2.插入元素2.3.批量插入3.取值3.1.使用 `[]` 操作符3.2.使用 `at()` 方法3.3.检查键是否存在3…

C++设计模式——State状态模式

一&#xff0c;状态模式的定义 状态模式是一种行为型设计模式&#xff0c;状态模式允许对象在内部状态发生切换时改变它自身的行为。 状态模式的主要目的是将复杂的状态切换逻辑抽象化为一组离散的状态类&#xff0c;使代码结构更加清晰和易于维护。 状态模式将对象的行为封…