FFMPEG录屏(18)--- 枚举Windows下的窗口列表并获取进程图标、标题、缩略图等

在Windows中获取可进行屏幕共享捕获的窗口列表及其图标、缩略图

在Windows系统中,获取可进行屏幕共享捕获的窗口列表以及它们的图标和缩略图是一个复杂但有趣的过程。本文将详细介绍如何实现这一功能,涉及到的主要技术包括Windows API、C++编程和一些第三方库。

前置知识

在开始之前,您需要了解以下内容:

  1. Windows API:Windows API提供了大量的函数,用于与操作系统进行交互。
  2. C++编程:本文的示例代码使用C++编写。
  3. 第三方库:我们将使用libyuv库来处理图像缩放。

实现步骤

1. 包含必要的头文件

首先,我们需要包含一些必要的头文件,这些头文件提供了我们需要的函数和数据结构。

#include "base/devices/screen/desktop_geometry.h"
#include "base/devices/screen/enumerator.h"
#include "base/devices/screen/mouse_cursor.h"
#include "base/devices/screen/utils.h"
#include "base/devices/screen/win/capture_utils.h"
#include "base/devices/screen/win/cursor.h"
#include "base/devices/screen/win/scoped_object_gdi.h"
#include "base/log/logger.h"
#include "base/strings/string_trans.h"
#include "base/utils/win/version.h"#include <libyuv/scale_argb.h>#include <memory>
#include <string>#include <stdlib.h>#include <shellapi.h>
#include <windows.h>

2. 定义辅助函数

我们需要一些辅助函数来获取窗口属性、窗口文本、进程路径等。

获取窗口属性
typedef HRESULT(WINAPI *FuncDwmGetWindowAttribute)(HWND window, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);FuncDwmGetWindowAttribute helper_get_dwmapi_get_window_attribute() {HINSTANCE dwmapi = LoadLibraryW(L"Dwmapi.dll");if (dwmapi == nullptr) {return nullptr;}FuncDwmGetWindowAttribute dwmapi_get_window_attribute =(FuncDwmGetWindowAttribute)GetProcAddress(dwmapi, "DwmGetWindowAttribute");if (dwmapi_get_window_attribute == nullptr) {return nullptr;}return dwmapi_get_window_attribute;
}
获取窗口文本
int get_window_text_safe(HWND window, LPWSTR p_string, int cch_max_count) {return ::InternalGetWindowText(window, p_string, cch_max_count);
}
获取进程路径
int get_window_process_path(HWND window, wchar_t *path, int max_count) {DWORD process_id;::GetWindowThreadProcessId(window, &process_id);if (process_id == 0) {return 0;}HANDLE process = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);if (process == nullptr) {return 0;}DWORD buffer_size = static_cast<DWORD>(max_count);if (::QueryFullProcessImageNameW(process, 0, path, &buffer_size) == 0) {::CloseHandle(process);return 0;}::CloseHandle(process);return buffer_size;
}

3. 定义窗口枚举回调函数

我们需要一个回调函数来处理每个被枚举到的窗口。

BOOL WINAPI enum_screen_source_info_proc(HWND window, LPARAM lParam) {auto *param = reinterpret_cast<enumerator_param *>(lParam);if (!::IsWindowVisible(window) || ::IsIconic(window) || ::GetShellWindow() == window) {return TRUE;}if (::GetAncestor(window, GA_ROOT) != window) {return TRUE;}desktop_rect window_rect = desktop_rect::make_ltrb(0, 0, 0, 0);if (!get_window_rect(window, &window_rect) || window_rect.is_empty()) {return TRUE;}if (is_window_invisible_win10_background_app(window)) {return TRUE;}HWND owner = ::GetWindow(window, GW_OWNER);LONG exstyle = ::GetWindowLongW(window, GWL_EXSTYLE);if (owner && !(exstyle & WS_EX_APPWINDOW)) {return TRUE;}if ((exstyle & WS_EX_TOOLWINDOW) &&!(param->external_flags & TRAA_SCREEN_SOURCE_FLAG_NOT_IGNORE_TOOLWINDOW)) {return TRUE;}if (!capture_utils::is_window_response(window) &&!(param->external_flags & TRAA_SCREEN_SOURCE_FLAG_NOT_IGNORE_UNRESPONSIVE)) {return TRUE;}bool owned_by_current_process = capture_utils::is_window_owned_by_current_process(window);if ((param->external_flags & TRAA_SCREEN_SOURCE_FLAG_IGNORE_CURRENT_PROCESS) &&owned_by_current_process) {return TRUE;}bool has_title = false;WCHAR window_title[TRAA_MAX_DEVICE_NAME_LENGTH] = L"";if (get_window_text_safe(window, window_title, TRAA_MAX_DEVICE_NAME_LENGTH - 1) > 0) {has_title = true;} else {LOG_ERROR("get window title failed: {}", ::GetLastError());}if (!has_title && !(param->external_flags & TRAA_SCREEN_SOURCE_FLAG_NOT_IGNORE_UNTITLED)) {return TRUE;}bool has_process_path = false;WCHAR process_path[TRAA_MAX_DEVICE_NAME_LENGTH] = L"";if (get_window_process_path(window, process_path, TRAA_MAX_DEVICE_NAME_LENGTH - 1) > 0) {has_process_path = true;} else {LOG_ERROR("get window process path failed: {}", ::GetLastError());}if ((param->external_flags & TRAA_SCREEN_SOURCE_FLAG_IGNORE_NOPROCESS_PATH) &&!has_process_path) {return TRUE;}WCHAR class_name[TRAA_MAX_DEVICE_NAME_LENGTH] = L"";const int class_name_length = ::GetClassNameW(window, class_name, TRAA_MAX_DEVICE_NAME_LENGTH);if (class_name_length < 1)return TRUE;if (!(param->external_flags & TRAA_SCREEN_SOURCE_FLAG_NOT_SKIP_SYSTEM_WINDOWS)) {if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Program Manager") == 0)return TRUE;if (wcscmp(class_name, L"TaskManagerWindow") == 0)return TRUE;if (wcscmp(class_name, L"Button") == 0)return TRUE;if (wcscmp(class_name, L"Windows.Internal.Shell.TabProxyWindow") == 0)return TRUE;}traa_screen_source_info window_info;window_info.id = reinterpret_cast<int64_t>(window);window_info.screen_id = get_window_owned_screen_id(window);window_info.is_window = true;window_info.is_minimized = ::IsIconic(window);if (is_window_maximized(window, &window_info.is_maximized) && window_info.is_maximized) {get_window_maximized_rect(window, &window_rect);}window_info.rect = window_rect.to_traa_rect();window_info.icon_size = param->icon_size;window_info.thumbnail_size = param->thumbnail_size;if (has_title) {auto utf8_title = string_trans::unicode_to_utf8(window_title);strncpy_s(const_cast<char *>(window_info.title), sizeof(window_info.title) - 1,utf8_title.c_str(), utf8_title.length());}if (has_process_path) {auto utf8_process_path = string_trans::unicode_to_utf8(process_path);strncpy_s(const_cast<char *>(window_info.process_path), sizeof(window_info.process_path) - 1,utf8_process_path.c_str(), utf8_process_path.length());}if (has_process_path && param->icon_size.width > 0 && param->icon_size.height > 0) {if (get_process_icon_data(process_path, desktop_size(param->icon_size.width, param->icon_size.height),const_cast<uint8_t **>(&window_info.icon_data), window_info.icon_size)) {} else {LOG_ERROR("get icon data failed");}}if (param->thumbnail_size.width > 0 && param->thumbnail_size.height > 0 &&param->thumbnail_instance) {if (!param->thumbnail_instance->get_thumbnail_data(window, param->thumbnail_size, const_cast<uint8_t **>(&window_info.thumbnail_data),window_info.thumbnail_size)) {LOG_ERROR("get thumbnail data failed");}}param->infos.push_back(window_info);return TRUE;
}

4. 枚举窗口信息

最后,我们需要一个函数来枚举所有窗口的信息。

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()};BOOL ret = ::EnumWindows(enum_screen_source_info_proc, reinterpret_cast<LPARAM>(&param));if (!ret) {LOG_ERROR("call ::EnumWindows failed: {}", ::GetLastError());return traa_error::TRAA_ERROR_ENUM_SCREEN_SOURCE_INFO_FAILED;}*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));strncpy_s(const_cast<char *>(dest_info.title), sizeof(dest_info.title) - 1, source_info.title,std::strlen(source_info.title));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;
}

总结

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

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

源码传送

traa

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

未来人工智能的发展对就业市场的影响 人工智能在生活中的相关

人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI.是新一轮科技革命和产业变革的重要驱动力量&#xff0c; 是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学. 人工智能的发展对就业市场的影响主要…

论文笔记:RelationPrompt :Zero-Shot Relation Triplet Extraction

论文来源: ACL Findings 2022 论文链接:https://arxiv.org/pdf/2203.09101.pdf 论文代码:http://github.com/declare-lab/RelationPrompt 本篇论文是由阿里达摩院自然语言智能实验室于2022年发表的关于零样本关系抽取的顶会论文,本篇博客将记录我在阅读过程中的一些笔记…

修改pq_default.ini禁用降噪,解决S905X3电视盒硬解视频画质模糊、严重涂抹得像油画、水彩画的问题

笔者使用一台处理器芯片为 S905X3 的电视盒将近一年&#xff0c;性能比之前的 RK3328 的盒子有所提升&#xff0c;但我对它视频解码方面感到越来越不爽&#xff0c;该盒子的硬解视频总是开启美颜降噪和锐化&#xff0c;导致硬解视频的画质模糊&#xff0c;细节都被磨平&#xf…

使用Jenkins部署项目

部署中的痛点 为什么要用Jenkins&#xff1f;我说下我以前开发的痛点&#xff0c;在一些中小型企业&#xff0c;每次开发一个项目完成后&#xff0c;需要打包部署&#xff0c;可能没有专门的运维人员&#xff0c;只能开发人员去把项目打成一个exe包&#xff0c;可能这个项目已…

OPENSSL-2023/11/10学习记录-C/C++对称分组加密DES

对称分组加密常用算法&#xff1a; DES 3DES AES 国密SM4 对称分组加密应用场景&#xff1a; 文件或者视频加密 加密比特币私钥 消息或者配置项加密 SSL通信加密 对称分组加密 使用异或实现一个简易的对称加密算法 A明文 B秘钥 AB密文AB (AB)B A 密码补全和初始化 数…

第六节——从深层剖析qsort的使用(让你不再害怕指针)

文章目录 1.什么是回调函数2.qsort的使用qsort排序整形数据qsort排序结构体数据qsort排序字符串数据 3.qsort的模拟实现 1.什么是回调函数 回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另⼀个函数&#xff0c;当…

Python画笔案例-087 绘制 旋转的文字

1、绘制 旋转的文字 通过 python 的turtle 库绘制 旋转的文字,如下图: 2、实现代码 绘制 旋转的文字,以下为实现代码: """旋转的文字.py """ import time from turtle import * from write_patch import *screen = Screen

【JPCS独立出版 | 福州大学主办 | 有确定的ISSN号】第三届可再生能源与电气科技国际学术会议(ICREET 2024)

第三届可再生能源与电气科技国际学术会议&#xff08;ICREET 2024&#xff09; 2024 3rd International Conference on Renewable Energy and Electrical Technology ICREET 2024已成功申请JPCS - Journal of Physics: Conference Series (ISSN:1742-6596) 独立出版&#xf…

架构设计笔记-16-嵌入式系统架构设计理论与实践

目录 知识要点 嵌入式微处理器 存储器&#xff08;memory&#xff09; 内&#xff08;外&#xff09;总线逻辑 嵌入式操作系统&#xff08;Embedded Operating System&#xff0c;EOS&#xff09; 通用中间件 嵌入式中间件的一般架构 典型嵌入式中间件系统 案例分析 1…

搭建mongodb单机部署-认证使用

搭建mongodb单机部署-认证使用 实现思路 先将配置文件配置好&#xff0c;使用不用认证的启动命令启动docker&#xff0c;然后创建账号并制定角色。在使用开启认证的命令重新启动容器就好。 这里我并没有说先停止容器&#xff0c;删掉容器重新创建容器。是因为我的启动命令中…

机器学习—Motivations

学习了线性回归&#xff0c;它预测了一个数字&#xff0c;接下来学习分类&#xff0c;输入变量y只能接收少数几个可能的值中的一个&#xff0c;而不是无限范围内的任何数字。事实证明&#xff0c;线性回归不是分类问题的好算法。这将引入一种不同的算法&#xff0c;叫做Logisti…

立仪科技:光谱共焦传感器精准测量玻璃

光谱共焦测量技术作为一种创新的光学检测方法&#xff0c;近年来在工业领域引起了广泛关注。 它以其高精度、非接触式的特点&#xff0c;特别适用于透明或半透明材料如玻璃的厚度和表面形貌测量。 接下来&#xff0c;立仪科技小编将深入探讨光谱共焦技术在玻璃测量上的应用及其…

【MySQL】增删改查-进阶(一)

目录 &#x1f334;数据库约束 &#x1f6a9;约束类型 &#x1f6a9;NOT NULL &#x1f6a9;UNIQUE &#x1f6a9;DEFAULT &#x1f6a9;PRIMARY KEY &#x1f6a9;FOREIGN KEY &#x1f6a9;CHECK &#x1f384;表的设计 &#x1f6a9;一对一 &#x1f6a9;一对多 …

Spring Boot知识管理:智能搜索与分析

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

如何做好SQL 数据库安全

随着信息技术的迅猛发展&#xff0c;数据库在现代信息系统中的重要性日益凸显。无论是电子商务平台、金融系统还是社交媒体应用&#xff0c;数据库都是其核心组件之一。其中&#xff0c;SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;数据库…

微信小程序使用MQTT连接阿里云

目录 一、新建项目和项目整体配置​ 二、MQTT 下载引入和配置连接​ 三、阿里云配置 1、创建产品及设备 2、数据进行云流转 四、创建 MQTT 连接​ 五、微信小程序配置 六、效果展示 1、微信小程序发送控制命令 2、LED台灯反馈LED状态 七、微信小程序项目完整代码 一…

论文笔记:PTR: Prompt Tuning with Rules for Text Classification

Abstract 手动设计大量语言提示麻烦且易出错&#xff0c;而自动生成的提示&#xff0c;在非小样本场景下验证其有效性昂贵且耗时。因此&#xff0c;提示调优以处理多类别分类任务仍然具有挑战。为此&#xff0c;本文提出使用规则进行多类别文本分类提示调优&#xff08;PTR&…

Linux发展与基础

Linux基础知识 Shell 命令执行环境&#xff1a; 命令提示符的组成&#xff1a;(用户名主机名)-[当前路径]权限提示符,例&#xff1a;&#xff08;kali㉿kali)-[~]$ ~ 表示所在目录为家目录:其中root用户的家目录是/root&#xff0c;普通用户的家目录在/home下 # 表示用户的权…

C#学习笔记(二)

C#学习笔记&#xff08;二&#xff09; 第 二 章 命名空间和类、数据类型、变量和代码规范一、命名空间-namespace1. 作用与具体表达形式-using2. 命名空间如何分类&#xff1f;3. 命名空间的命名规范 第 二 章 命名空间和类、数据类型、变量和代码规范 深水区 一、命名空间-…

掌握高效工作汇报技巧:如何利用即时白板打造完美日报,提升职场影响力

在快节奏的工作环境中&#xff0c;撰写工作日报、周报和月报已成为职场人士的日常任务。一份精心准备的工作汇报不仅能够体现我们的敬业精神&#xff0c;还能吸引上级的注意&#xff0c;提升我们在团队中的能见度。使用即时白板作为辅助工具&#xff0c;可以让我们更高效地梳理…