当前位置: 首页 > news >正文

FFMPEG录屏(19)--- 枚举Windows下的屏幕列表,并获取名称、缩略图

在Windows下枚举显示器列表并获取名称、缩略图

在Windows系统中,枚举显示器列表并获取它们的名称和缩略图是一个常见的需求。本文将详细介绍如何实现这一功能,涉及到的主要技术包括Windows API和C++编程。

获取显示器信息

首先,我们需要一个函数来枚举所有的显示器,并获取它们的名称和缩略图。

int enum_screens(enumerator_param &param) {BOOL enum_result = TRUE;for (int device_index = 0;; ++device_index) {DISPLAY_DEVICEW device;device.cb = sizeof(device);enum_result = EnumDisplayDevicesW(NULL, device_index, &device, 0);if (!enum_result) {break;}if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) {continue;}bool is_primary = false;if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {is_primary = true;}DEVMODEW device_mode;device_mode.dmSize = sizeof(device_mode);device_mode.dmDriverExtra = 0;BOOL result = EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0);if (!result) {break;}traa_screen_source_info screen_info;screen_info.is_window = false;screen_info.id = device_index;screen_info.rect = traa_rect(device_mode.dmPosition.x, device_mode.dmPosition.y,device_mode.dmPelsWidth, device_mode.dmPelsHeight);auto utf8_name = string_trans::unicode_to_utf8(device.DeviceName);strncpy_s(const_cast<char *>(screen_info.title), sizeof(screen_info.title) - 1,utf8_name.c_str(), utf8_name.length());if (param.thumbnail_size.width > 0 && param.thumbnail_size.height > 0 &&param.thumbnail_instance) {capture_utils::get_screen_image_by_gdi(screen_info.rect, param.thumbnail_size,const_cast<uint8_t **>(&screen_info.thumbnail_data),screen_info.thumbnail_size);}param.infos.push_back(screen_info);}return traa_error::TRAA_ERROR_NONE;
}

这个函数使用EnumDisplayDevicesW来枚举所有的显示器,并使用EnumDisplaySettingsExW来获取每个显示器的设置。然后,我们将显示器的信息存储在traa_screen_source_info结构体中,并将其添加到参数的infos向量中。

获取缩略图

获取显示器的缩略图是一个关键步骤。我们需要使用GDI(图形设备接口)来捕获屏幕图像,并将其缩放到我们需要的大小。

bool capture_utils::get_screen_image_by_gdi(const traa_rect &rect, const traa_size &target_size,uint8_t **data, traa_size &scaled_size) {const desktop_size scaled_desktop_size =calc_scaled_size(desktop_size(rect.right - rect.left, rect.bottom - rect.top),desktop_size(target_size.width, target_size.height));if (scaled_desktop_size.is_empty()) {LOG_ERROR("calc scaled scaled_size failed, get empty scaled_size");return false;}HDC screen_dc = ::GetDC(nullptr);if (!screen_dc) {LOG_ERROR("get screen dc failed: {}", ::GetLastError());return false;}bool result = false;HANDLE section = nullptr;uint8_t *bitmap_data = nullptr;HBITMAP bitmap = nullptr;HDC compatible_dc = nullptr;HGDIOBJ old_obj = nullptr;do {constexpr int bytes_per_pixel = desktop_frame::kBytesPerPixel;BITMAPINFO bmi = {};bmi.bmiHeader.biWidth = scaled_desktop_size.width();bmi.bmiHeader.biHeight = -scaled_desktop_size.height();bmi.bmiHeader.biPlanes = 1;bmi.bmiHeader.biBitCount = 32;bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);bmi.bmiHeader.biSizeImage =scaled_desktop_size.width() * scaled_desktop_size.height() * bytes_per_pixel;bitmap = ::CreateDIBSection(screen_dc, &bmi, DIB_RGB_COLORS, (void **)&bitmap_data, section, 0);if (!bitmap) {LOG_ERROR("create dib section failed: {}", ::GetLastError());break;}compatible_dc = ::CreateCompatibleDC(screen_dc);old_obj = ::SelectObject(compatible_dc, bitmap);if (!old_obj || old_obj == HGDI_ERROR) {LOG_ERROR("select object failed: {}", ::GetLastError());break;}SetStretchBltMode(compatible_dc, COLORONCOLOR);result = ::StretchBlt(compatible_dc, 0, 0, scaled_desktop_size.width(),scaled_desktop_size.height(), screen_dc, rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top, SRCCOPY | CAPTUREBLT);if (!result) {LOG_ERROR("stretch blt failed: {}", ::GetLastError());break;}*data = new uint8_t[bmi.bmiHeader.biSizeImage];if (!*data) {LOG_ERROR("alloc memory for thumbnail data failed: {}", ::GetLastError());break;}memcpy_s(*data, bmi.bmiHeader.biSizeImage, bitmap_data, bmi.bmiHeader.biSizeImage);scaled_size = scaled_desktop_size.to_traa_size();} while (0);if (bitmap) {::DeleteObject(bitmap);}if (compatible_dc) {if (old_obj) {::SelectObject(compatible_dc, old_obj);}::DeleteDC(compatible_dc);}::ReleaseDC(nullptr, screen_dc);if (!result && *data) {delete[] * data;*data = nullptr;}return result;
}

这个函数使用CreateDIBSection创建一个设备独立位图(DIB),然后使用StretchBlt将屏幕图像复制到位图中。最后,我们将位图数据复制到一个新的缓冲区中,并返回缩放后的大小。

整合一切

最后,我们需要一个函数来整合所有的步骤,枚举显示器并获取它们的名称和缩略图。

int screen_source_info_enumerator::enum_screen_source_info(const traa_size icon_size,const traa_size thumbnail_size,const unsigned int external_flags,traa_screen_source_info **infos,int *count) {std::unique_ptr<thumbnail> thumbnail_instance;if (thumbnail_size.width > 0 && thumbnail_size.height > 0) {thumbnail_instance.reset(new thumbnail());}enumerator_param param = {icon_size, thumbnail_size, external_flags, {}, thumbnail_instance.get()};enum_windows(param);enum_screens(param);*count = static_cast<int>(param.infos.size());*infos =reinterpret_cast<traa_screen_source_info *>(new traa_screen_source_info[param.infos.size()]);if (*infos == nullptr) {LOG_ERROR("alloca memroy for infos failed: {}", ::GetLastError());return traa_error::TRAA_ERROR_OUT_OF_MEMORY;}for (size_t i = 0; i < param.infos.size(); ++i) {auto &source_info = param.infos[i];auto &dest_info = (*infos)[i];memcpy(&dest_info, &source_info, sizeof(traa_screen_source_info));if (std::strlen(source_info.title) > 0) {strncpy_s(const_cast<char *>(dest_info.title), sizeof(dest_info.title) - 1, source_info.title,std::strlen(source_info.title));}if (std::strlen(source_info.process_path) > 0) {strncpy_s(const_cast<char *>(dest_info.process_path), sizeof(dest_info.process_path) - 1,source_info.process_path, std::strlen(source_info.process_path));}}return traa_error::TRAA_ERROR_NONE;
}

这个函数创建一个thumbnail实例,并调用enum_windowsenum_screens来枚举窗口和显示器。然后,它将枚举到的信息复制到一个新的缓冲区中,并返回信息的数量。

通过上述步骤,我们可以在Windows系统中枚举显示器列表,并获取它们的名称和缩略图。这一过程涉及到Windows API的使用、窗口属性的获取、图标和缩略图的处理等多个方面。希望本文能对您有所帮助。

最近有点懒了,这还是copilot生成的。。。

源码传送

traa

相关文章:

FFMPEG录屏(19)--- 枚举Windows下的屏幕列表,并获取名称、缩略图

在Windows下枚举显示器列表并获取名称、缩略图 在Windows系统中&#xff0c;枚举显示器列表并获取它们的名称和缩略图是一个常见的需求。本文将详细介绍如何实现这一功能&#xff0c;涉及到的主要技术包括Windows API和C编程。 获取显示器信息 首先&#xff0c;我们需要一个…...

【python】NumPy(三):文件读写

目录 ​前言 NumPy 常见IO函数 save()和load() savez() loadtxt()和savetxt() 练习 前言 在数据分析中&#xff0c;我们经常需要从文件中读取数据或者将数据写入文件&#xff0c;常见的文件格式有&#xff1a;文本文件txt、CSV格式文件&#xff08;用逗号分隔&#xff…...

硬件产品经理的开店冒险之旅(下篇)

缘起&#xff1a;自己为何想要去寻找职业第二曲线 承接上篇的内容&#xff0c;一名工作13年的普通硬件产品经理将尝试探索第二职业曲线。根本原因不是出于什么高大上的人生追求或者什么职业理想主义&#xff0c;就是限于目前的整体就业形式到了40岁的IT从业人员基本不可能在岗…...

基于GeoScene Pro的开源数据治理与二维制图规范化处理智能工具箱

内容导读 本文描述的是一个基于GeoScene Pro4.0/ArcGIS3.1 Pro平台的开源数据治理与二维制图规范化处理智能工具箱(免费试用&#xff0c;文末有获取方式)&#xff0c;旨在解决GIS应用中数据转换、检查、治理和制图数据规范化处理方面的问题。 工具箱结合了Geoscene/ArcGIS Pr…...

CSS 设置网页的背景图片

背景 最近正好在写一个个人博客网站“小石潭记”&#xff0c;需要一张有水&#xff0c;有鱼的图片。正好玩原神遇到了类似场景&#xff0c;于是截图保存&#xff0c;添加到网站里面。以下是效果图&#xff1a; css 写个class&#xff0c;加到整个网页的body上 .bodyBg {ba…...

如何使用DockerSpy检测你的Docker镜像是否安全

关于DockerSpy DockerSpy是一款针对Docker镜像的敏感信息检测与安全审计工具&#xff0c;该工具可以帮助广大研究人员在Docker Hub上检测和搜索自己镜像的安全问题&#xff0c;并识别潜在的泄漏内容&#xff0c;例如身份验证密钥等敏感信息。 功能介绍 1、安全审计&#xff1a…...

数据结构练习题4(链表)

1两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4]…...

【前端】如何制作自己的网站(7)

以下内容接上文。 结合图片的超链接 将img元素作为内容&#xff0c;放在a元素中。即可为图片添加一个超链接。 例如右边的代码&#xff0c;点击头像就会打开“aboutme.html“。 点击右边的图片试试&#xff5e; 两个非文本元素——图片与超链接。 从现在开始&#xff0…...

《数字图像处理基础》学习02-BMP位图文件

目录 一&#xff0c;BMP文件组成 二&#xff0c;使用ultra edit软件查看图像结构 1&#xff0c;ultra edit软件的下载和安装 2&#xff0c;ultra edit打开图像 三&#xff0c;使用matlab显示RGB图像 在之前的文章学习到&#xff0c;计算机只能处理数字图像&#xff0c;因…...

车辆管理系统设计与SpringBoot技术融合

3系统分析 3.1可行性分析 通过对本车辆管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本车辆管理系统采用Spring Boot框架&#xff0c;JAVA作为开发语…...

常见TCP/IP协议基础——计算机网络

目录 前言常见协议基础常见协议-基于TCP的应用层协议常见协议-基于UDP的应用层协议常见协议-网络层协议习题自测1.邮件发送协议2.接收邮件协议端口3.建立连接4.层次对应关系5.FTP服务器端口 前言 本笔记为备考软件设计师时的重点知识点笔记&#xff0c;关于常见TCP/IP协议基础…...

SVM支持向量机python实现

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种强大的监督学习算法&#xff0c;主要用于分类和回归任务。SVM的核心思想是找到一个最优的超平面&#xff0c;使得不同类别的数据点能够被尽可能清晰地分开&#xff0c;并且这个超平面与最近的数据点之间有…...

linux查看系统类型

要确定系统是 Ubuntu 还是 CentOS&#xff0c;可以通过查看系统的发行版信息来判断。以下是几种常见的方法&#xff1a; 方法一&#xff1a;使用 cat 命令查看 /etc/os-release 文件 这个文件包含了系统的详细信息&#xff0c;包括发行版名称和版本号。 cat /etc/os-release…...

SpringSecurity 捕获自定义JWT过滤器抛出的异常

自定义过滤器如下&#xff1a; /*** jwt过滤器&#xff0c;验证令牌是否合法** author 朱铭健*/ Slf4j public class JwtAuthenticationFilter extends OncePerRequestFilter {Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse resp…...

中小型企业网络的设计与实现

资料下载中小型企业网络的设计与实现论文资源-CSDN文库 摘 要 本文规划的是一个公司的网络搭建&#xff0c;网络设计包括了多个部门的网络架构&#xff0c;每个部门通过VLAN进行隔离&#xff0c;确保了网络的安全性和高效。 华为企业网络模拟平台&#xff08;ENSP&#xff09…...

小马识途海外媒体推广有何优势?

互联网让地球变得像一个村子一样&#xff0c;信息可以瞬间变得人尽皆知&#xff0c;商品和服务也同样习惯了跨国合作。中国不少物美价廉的产品在世界各地都很受欢迎&#xff0c;国内小资群体对国外的服饰和美妆更是偏爱有加。小马识途营销顾问认为&#xff0c;中国品牌不出走国…...

Spring Boot知识管理:跨平台集成方案

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…...

逆向工程基本流程

1 逆向的基本流程 1获取目标app (官网,豌豆荚),尽量不要去华为应用市场,小米应用市场下载–多渠道打包,安装到手机上 2使用抓包工具 抓包分析(charles,fiddler…) 3使用反编译工具 (JADX,JD-GUI。。),把apk反编译成java代码,分析java代码,定位代码位置 4 使用动态分…...

target_include_directories是如何组织头文件的?

target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 这条 CMake 命令用于指定编译目标&#xff08;在此例中为 mylib 静态库&#xff09;的头文件搜索路径。具体来说&#xff0c;这条命令的作用包括以下几个方面&#xff1a; 1. 添加包含目录 mylib&…...

【Flutter】Dart:运算符

在 Dart 中&#xff0c;运算符是非常重要的组成部分&#xff0c;它们可以对变量和常量进行多种运算操作。理解和掌握 Dart 中的各种运算符不仅可以帮助你编写更加高效、简洁的代码&#xff0c;还能更好地理解其背后的逻辑和设计。本文将深入探讨 Dart 中的运算符&#xff0c;包…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...