当前位置: 首页 > 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;包…...

ChatGPT01-preivew体验报告:内置思维链和多个llm组合出的COT有啥区别呢?丹田与练气+中学生物理奥赛题测试,名不虚传还是名副其实?

一个月前&#xff0c;o1发布的时候&#xff0c;我写了篇文章介绍 逻辑推理能力堪比博士生&#xff0c;OpenAI发布全新AI模型系列&#xff1a; o1 - 大模型或许进入新阶段&#xff0c;还翻译了官方的介绍 解密OpenAI o1是如何让LLMs获得逻辑推理能力的 - CoT * RL&#xff0c;也…...

《云计算网络技术与应用》实训6-1:配置KVM虚拟机使用NAT网络

任务1、计算节点基础环境准备 1. 使用VMware安装CentOS 7虚拟机&#xff0c;安装时记得开启CPU虚拟化&#xff0c;命名为“KVMC6”。 2. &#xff08;网卡配置和之前的一样&#xff0c;都用100网段&#xff09;网关设置为192.168.100.1&#xff0c;地址段为192.168.100.10-25…...

【Unity新闻】Unity 6 正式版发布

Unity CEO Matt Bromberg 在今天自豪地宣布&#xff0c;Unity 6 正式发布&#xff01;作为迄今为止最强大和稳定的版本&#xff0c;Unity 6 为游戏和应用开发者提供了大量的新功能和工具&#xff0c;帮助他们加速开发并提升性能。 本次正式版是6.0000.0.23f1&#xff08;LTS&a…...

基于语音识别的停车共享小程序(lw+演示+源码+运行)

目 录 1 绪论1 1.1 课题研究背景1 1.2 研究现状1 1.3 论文结构安排1 2 系统关键技术2 2.1 微信小程序2 2.2 微信Web开发者工具2 2.3 JavaScript简介2 2.4 微信小程序API接口2 2.5 MYSQL数据库2 3 系统分析1 3.1 可行性分析1 3.1.1 技术可行性1 3.1.2 经济可行性1…...

编程考古-计算机发展(上)

计算机/器现在是我们日常生活中的重要工具&#xff0c;它的发展历程见证了人类数学计算能力的不断提升。 什么是计算 计算的本质在于基于规则对符号串进行变换。简言之&#xff0c;从一个初始的符号串&#xff08;输入&#xff09;出发&#xff0c;依据既定的法则逐步改变这个…...

pc轨迹回放制作

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;pc轨迹回放制作 主要内容&#xff1a;制作车辆轨迹操作页&#xff0c;包括查询条件、动态轨迹回放、车辆轨迹详情表单等 应用场景&#xff1a;车辆…...

无向图中的一些问题与处理(上接无向图知识简记)

一、有向图中的排序与调度 1、深度优先搜索的排序 使用深度优先搜索对图中顶点进行排序&#xff0c;根据数据结构性质与递归保存顺序&#xff0c;有以下三种排列顺序 &#xff08;1&#xff09; 前序&#xff1a;在递归调用之前将顶点加入队列。 &#xff08;2&#xff09;后…...

AIGC助力小学生编程梦:C++入门不再难!

文章目录 一、AIGC时代下的编程教育新趋势二、小学生C入门趣味编程的意义三、小学生C入门趣味编程的实践策略四、面临的挑战与应对策略五、AIGC技术在小学生C编程中的应用与前景《小学生C趣味编程从入门到精通》编辑推荐内容简介作者简介目录 随着人工智能生成内容&#xff08;…...

AI开发-三方库-Hugging Face-Pipelines

1 需求 需求1&#xff1a;pipeline支持的任务类型 需求2&#xff1a;推理加速使用CPU还是GPU 需求3&#xff1a;基于pipeline的文本分类示例 需求4&#xff1a;pipeline实现原理 模型使用步骤&#xff08;Raw text -》Input IDs -》Logits -》Predictions&#xff09;&…...

【Python网络编程】学习Socket编程,打造网络应用!

【Python网络编程】学习Socket编程&#xff0c;打造网络应用&#xff01; 网络编程是现代计算机科学中的重要一环&#xff0c;几乎所有的应用都依赖网络传输数据。无论是创建简单的客户端-服务器模型&#xff0c;还是构建复杂的网络应用&#xff0c;Socket 编程都是关键的技术…...