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.mzph.cn/news/883125.shtml

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

相关文章

【SDL】微软SDL建设指南

【SDL】微软SDL建设指南 1.建立安全标准、指标和治理2.要求使用经过验证的安全功能、语言和框架3.执行安全设计审查和威胁建模4.定义并使用密码学标准5.确保软件供应链安全6.确保工程环境安全7.执行安全测试8.确保运营平台安全9.实施安全监控和响应&#xff08;态势管理或漏洞管…

二十、Innodb底层原理与Mysql日志机制深入剖析

文章目录 一、MySQL的内部组件结构1、Server层1.1、连接器1.2、查询缓存1.3、分析器1.4、优化器1.5、执行器 2、存储引擎层 二、Innodb底层原理与Mysql日志机制1、redo log重做日志关键参数2、binlog二进制归档日志2.1、binlog日志文件恢复数据 3、undo log回滚日志4、错误日志…

群晖通过 Docker 安装 Firefox

1. 获取 firefox 镜像 在注册表搜索 jlesage/firefox&#xff0c;并且下载 2. 创建容器 运行映像 jlesage/firefox&#xff0c;开始创建容器 3. 配置容器 启用自动重新启动&#xff0c;重点配置存储空间和环境变量&#xff0c;其他默认。 创建文件夹&#xff0c;及子文件夹…

高效设备管理:中小企业的Spring Boot解决方案

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理中小企业设备管理系统的相关信息成为必然。…

Lucas带你手撕机器学习——SVM支持向量机

#1024程序员节&#xff5c;征文# 支持向量机&#xff08;SVM&#xff09;的详细讲解 什么是SVM&#xff1f; 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种用于分类和回归的监督学习算法。它的主要任务是从给定的数据中找到一个最佳的决策…

原来“有符号数变成无符号数,并不是-1变成1,-15变成15”!!

不怕大家伙笑话&#xff0c;我以前一直以为在C语言中&#xff0c;有符号变无符号仅仅就是去掉数字前面的符号就行&#xff0c;如今做了一道题&#xff0c;细细研究&#xff0c;才发现&#xff0c;原来不是&#xff01; 如果你也感兴趣&#xff0c;那就学学今天这节吧~ 话不多说…

前端必知必会-JavaScript 简介

文章目录 JavaScript 简介JavaScript 可以更改 HTML 内容JavaScript 可以更改 HTML 属性值JavaScript 可以更改 HTML 样式 (CSS)JavaScript 可以隐藏 HTML 元素JavaScript 可以显示 HTML 元素 总结 JavaScript 简介 本页包含一些 JavaScript 功能的示例。 JavaScript 可以更改…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-20

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-20 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-20目录1. FLARE: Faithful Logic-Aided Reasoning and Exploration摘要研究背景问题与挑战如何解决创新点算法模型实验效果重要数…

多线程进阶——线程池的实现

什么是池化技术 池化技术是一种资源管理策略&#xff0c;它通过重复利用已存在的资源来减少资源的消耗&#xff0c;从而提高系统的性能和效率。在计算机编程中&#xff0c;池化技术通常用于管理线程、连接、数据库连接等资源。 我们会将可能使用的资源预先创建好&#xff0c;…

Ubuntu22.04虚拟机安装

一、安装介质下载&#xff1a; 在官网下载安装镜像&#xff0c;下载地址https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso 二、操作系统安装&#xff1a; step 1:进入ubuntu的安装界面&#xff0c;直接回车安装。 step 2:选择语言&#xff0c;直接回…

liunx线程互斥

临界资源和临界区 临界资源&#xff1a;多线程执行流共享的资源就叫临界资源。 临界区&#xff1a;每个线程中&#xff0c;访问临界区的代码&#xff0c;就叫临界区。 互斥&#xff1a;任何时候&#xff0c;互斥保证只有一个执行流进入临界区&#xff0c;访问临界资源&#…

NXP Smart Access Car-车用产品整合应用

在汽车技术不断进步的今天&#xff0c;智能化已成为汽车行业发展的主要趋势之一。本次研讨会将深入探讨NXP的Smart Access Car技术&#xff0c;说明如何通过NXP 产品设计提升汽车的安全性、便利性和使用者体验。研讨会将涵盖NXP MCU/NFC等方面的最新解决方案&#xff0c;并探讨…

Qt调用Yolov11导出的Onnx分类模型开发分类检测软件

软件视频地址:视频地址 代码开源地址 之前用Python配合YOLOV11开发一个了分类训练软件&#xff0c;软件只要准备好数据&#xff0c;然后导入就可以训练数据&#xff0c;训练完成后还可以验证&#xff0c;测试&#xff0c;但是要真正落地&#xff0c;还是有点欠缺。配合YOLOV1…

入门数据结构JAVADS——如何通过遍历顺序构建二叉树

目录 前言 构建二叉树的前提&#xff1a; 为什么需要两个不同类型的遍历&#xff1a; 前序遍历 中序遍历 我们的算法思路如下: 举例&#xff1a; 代码实现 后序遍历 中序遍历 结尾 前言 入门数据结构JAVA DS——二叉树的介绍 (构建,性质,基本操作等) (1)-CSDN博客 在上…

我毕业后的8年嵌入式工作

2015年毕业&#xff0c;2016年工作到现在已经过了8个年头&#xff0c;借着征文&#xff0c;做个简单的回顾与总结。 2015年从广州番禺职业技术学院毕业&#xff0c;学的是嵌入式技术与应用&#xff0c;我的下一届学弟学妹变物联网了&#xff0c;算是绝版专业了吧。出来后谨遵校…

07 设计模式-结构型模式-桥接模式

桥接&#xff08;Bridge&#xff09;是用于把抽象化与实现化解耦&#xff0c;使得二者可以独立变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦。 这种模式涉及到一个作为桥接的接口&#xff0c;使得…

JAVA单列集合

List系列集合:添加的元素是 有序、可重复、有索引 Set系列集合:添加的元素是 无序、不重复、无索引 Collection Collection是单列集合的接口&#xff0c;它的功能是全部单列集合都可以继承使用的 public boolean add(E e) 把给定的对象添加到当前集合中 public void …

Spring MVC(下)

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多JavaEE知识 目录 1.响应 1.1 返回静态页面 1.2 返回数据ResponseBody 1.3 返回HTML代码⽚段 1.4 返回JSON 1.5 设置状态码 1.6 设置Header 2 . …

【文献及模型、制图分享】基于国际湿地城市视角的常德市湿地保护修复成效与归因分析及其政策启示

文献介绍 《湿地公约》提出的“国际湿地城市”认证是促进湿地保护修复的新举措。以国际湿地城市常德市为例&#xff0c;基于2000—2022年15 m空间分辨率湿地分类数据&#xff0c;监测常德市湿地保护修复逐年动态变化&#xff0c;定量分析湿地保护修复驱动因素的重要性和贡献率…

K8s中TSL证书如何续期

TSL是什么 K8s中的作用是什么&#xff1f; 在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;TSL 指的是 Transport Layer Security&#xff0c;也就是传输层安全协议。它是用来保护在网络上传输的数据的安全性和隐私性。 TSL 在 Kubernetes 中的作用包括&#xff1a;…