Re0: 从零实现一个置顶任意窗口的小工具

news2024/11/27 11:46:31

前言

话不多说,先上效果:

动画

这里展示的是通过下拉框选择窗口,让窗口显示并置顶,其实还可以直接通过快捷键(先鼠标点击要置顶的窗口,再使用CTRL+SHIFT+T),本文涉及到的完整代码已上传到GitHub,也可以选择直接下载exe(35k)体验。

实现

实现显示并置顶功能

其实置顶的核心功能就是通过SetWindowPos函数实现的:

// 置顶窗口
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

// 取消置顶
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 100, 100, SWP_NOMOVE | SWP_NOSIZE);

不过如果只使用该函数,无法满足窗口未处于前台(例如最小化状态)无法显示在前台的情况,需要手动让窗口处于前台才能满足最终效果,因此还需要结合SetForegroundWindow函数使用,但是由于官网中提到的如下限制:

image-20231129160938483

因此还需要使用AttachThreadInput函数进行处理,最终的函数如下:

// 展示并置顶窗口
void topwin(HWND hWnd)
{
    // 通过快捷键方式不需要传递窗口句柄
    if (hWnd == nullptr) {
        hWnd = GetForegroundWindow();
    }
    DWORD currentId = GetCurrentThreadId();
    DWORD topId = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
    AttachThreadInput(currentId, topId, TRUE);

    // 展示并置顶窗口
    ShowWindow(hWnd, SW_SHOWNORMAL);
    SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    SetForegroundWindow(hWnd);

    AttachThreadInput(currentId, topId, FALSE);
}

快捷键方式实现

讲完置顶功能后,再说一下如何将功能和快捷键进行关联。

首先,需要注册快捷键(CTRL+SHIFT+T用于置顶,CTRL+SHIFT+C用于取消置顶):

int topHotkeyId = 1;
int untopHotkeyId = 2;

// 注册全局快捷键
if (!RegisterHotKey(NULL, topHotkeyId, MOD_CONTROL | MOD_SHIFT, 'T')) {
	return 1;
}

if (!RegisterHotKey(NULL, untopHotkeyId, MOD_CONTROL | MOD_SHIFT, 'C')) {
	return 1;
}

然后就可以在消息循环中处理快捷键事件:

// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        if (msg.message == WM_HOTKEY) {
            HWND hWnd = GetForegroundWindow();
            if (msg.wParam == topHotkeyId) {
                topwin(nullptr);
            }
            if (msg.wParam == untopHotkeyId) {
                SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 100, 100, SWP_NOMOVE | SWP_NOSIZE);
            }
        }
    }
}

WM_HOTKEY 的处理需要放在 DispatchMessage(&msg); 之后,否则可能出现打包后的 exe 无法正常运行。在使用快捷键方式置顶窗口时,需要先选中指定窗口使其获取焦点。

下拉列表方式实现

最后再讲一下如何实现下拉列表选择窗口进行置顶。

这里先展示获取窗口列表的具体实现:

std::vector<HWND> windows;

// 判断窗口是否在桌面正常显示
bool IsWindowOnDesktop(HWND hwnd) {
    WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) };
    if (GetWindowPlacement(hwnd, &placement)) {
        return placement.showCmd == SW_SHOWNORMAL;
    }
    return false;
}

// 遍历窗口并获取窗口标题展示在下拉框中
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
    if (IsWindowVisible(hwnd) && !IsWindowOnDesktop(hwnd)) {
        int titleLength = GetWindowTextLength(hwnd);
        if (titleLength > 0) {
            std::wstring windowTitle(titleLength + 1, L'\0');
            GetWindowText(hwnd, &windowTitle[0], titleLength + 1);
            // 将窗口标题加入到下拉列表中
            SendMessageW(hComboBox, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(windowTitle.c_str()));
            windows.push_back(hwnd);
        }
    }
    return TRUE;
}

// 遍历窗口
EnumWindows(EnumWindowsProc, 0);

结合代码可以直观的知道就是先进行窗口遍历,获取符合条件的窗口(窗口可见且是在桌面正常显示的窗口)标题。此外通过windows.push_back(hwnd);保存窗口句柄,用于后续选中条件的处理。

实现了获取窗口标题列表的功能后,再来说明一下如何将数据填充到下拉列表中并处理选择事件:

#define MENU_ID 29

HWND hComboBox;
// 创建下拉框
hComboBox = CreateWindowW(L"ComboBox", L"", CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
	10, 10, 360, 200, hWnd, (HMENU)MENU_ID, nullptr, nullptr);

// 设置默认选中项
SendMessageW(hComboBox, CB_SETCURSEL, 0, 0);

case WM_COMMAND:
    {
        // 处理下拉列表选中事件
        if (HIWORD(wParam) == CBN_SELCHANGE) {
            LRESULT selectedIndex = SendMessageW(GetDlgItem(hWnd, MENU_ID), CB_GETCURSEL, 0, 0);
            topwin(windows.at(selectedIndex));
        }
    }
    break;

通过代码不难理解,就是创建一个下拉框组件,并设置唯一标识MENU_ID,之后处理相应的下拉选择事件即可,窗口句柄通过windows.at(selectedIndex)进行获取。

这里暂时未实现取消置顶的方式,可以使用CTRL+SHIFT+C快捷键进行取消置顶的操作。

总结

本文简单实现了一个置顶任意窗口的小工具,实现思路很简单,还只算是一个半成品,不过核心功能已经有了,只需要自己额外进行一些扩展就足够日常使用,欢迎一起交流讨论。

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

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

相关文章

【开源】基于Vue+SpringBoot的智能教学资源库系统

项目编号&#xff1a; S 050 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S050&#xff0c;文末获取源码。} 项目编号&#xff1a;S050&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课…

现代风客餐阳台开放式一体布局,设计亮点。福州中宅装饰,福州装修

在现代家居设计中&#xff0c;开放式布局越来越受到欢迎。它不仅可以提升家居的空间感&#xff0c;还可以促进家人之间的交流和互动。这个客厅、餐厅、阳台一体化的设计&#xff0c;更是充分利用了空间&#xff0c;具有多重亮点。 01.玄关到客厅嵌入式一体式收纳柜 玄关是进入…

全国高校走进深算院:共话国产数据库产教融合生态建设

近日&#xff0c;由教育部高等学校计算机类专业教学指导委员会、全国高等学校计算机教育研究会主办&#xff0c;清华大学出版社、深圳市信息技术应用创新联盟承办的“2023全国高校走进信创企业研学活动”顺利举办。来自全国各地30余家高校的近80位院校领导、教师代表走进了深圳…

windows启动后直接进入指定程序并且不显示欢迎界面和windows桌面

windows启动后直接进入指定程序并且不显示欢迎界面和windows桌面 前言开机进入指定程序方法问题 浅尝GINA和Credential Providers关闭欢迎屏幕 前言 由于系统需求需要做到电脑开机后显示完windows加载页面就直接进入自己系统的界面&#xff0c;并且不显示登录欢迎页面&#xf…

【收藏】SNMP介绍及使用

热门IT课程-视频教程&#xff1a;文章浏览阅读49次。认证课程介绍&#xff1a;华为HCIA试听课程 &#xff1a; 华为HCIA试听课程&#xff1a;华为HCIA试听课程&#xff1a;华为HCIP试听课程&#xff1a;思科CCNA试听课程&#xff1a;思科CCNA试听课程&#xff1a;思科CCNA试听课…

0x00000709一键修复的解决办法,0x00000709错误的原因

在使用打印机时&#xff0c;你可能会遇到一些错误代码&#xff0c;其中之一是0x00000709。这个错误代码表示无法设置默认打印机。如果你遇到这样的问题不用担心&#xff01;这篇文章将为你提供0x00000709一键修复的解决办法&#xff0c;帮助你解决0x00000709错误&#xff0c;并…

京东API接口的接入(京东工业)

在技术交流群&#xff0c;大家有探讨稳定获取京东商品主图、价格、标题&#xff0c;及sku的完整解决方案。这个引起了我技术挑战的兴趣。 目前&#xff0c;自己做了压测&#xff0c;QPS高、出滑块概率极低&#xff0c;API整体稳定&#xff0c;可满足业务场景的性能需求。 公共…

Electron+Ts+Vue+Vite桌面应用系列:sqlite增删改查操作篇

文章目录 1️⃣ sqlite应用1.1 sqlite数据结构1.2 初始化数据库1.3 初始化实体类1.4 操作数据类1.5 页面调用 优质资源分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418 ElectronTsVueVite桌面应用系列 &#xff1a;这个系列包括了从桌…

对一个预算有限的创业者来说,应该选择哪些形式的办公场地

对于一个预算有限的创业者来说&#xff0c;选择合适的办公场地是一个重要的决策。不同的办公场地形式有各自的优缺点&#xff0c;需要根据创业者的具体情况和需求来权衡。 一般来说&#xff0c;有以下几种常见的办公场地形式&#xff1a; - 家庭办公&#xff1a;这是最节省成本…

无需部署服务器,如何结合内网穿透实现公网访问导航页工具Dashy

文章目录 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 简介 Dashy 是一个开源的自托管的导航页配置服务&#xff0c;具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一些网站聚合起来放在一起&#xff0c;形成自己的导航…

迅为iTOP-3568核心板在精准气象行业应用方案

迅为iTOP-3568核心板在精准气象行业应用方案 各位小伙伴们&#xff0c;今天我要给大家介绍一个非常厉害的项目&#xff0c;那就是3568核心板在精准气象方面的方案&#xff01;这个方案真的是太牛了&#xff0c;让人不禁感叹科技的强大&#xff01; 首先&#xff0c;让我们来了解…

主播岗位面试

一、自我介绍 在面试的开始阶段&#xff0c;你需要准备一个简洁而有力的自我介绍。这个自我介绍应该包括你的姓名、教育背景、工作经验以及你为何对这个主播职位感兴趣。这个自我介绍应该控制在1-2分钟之内&#xff0c;避免冗长的表述。 二、主播经历和特点 在这个环节&…

PC模糊搜索

双向绑定input输入框&#xff0c;监听值改变事件 <el-inputinput"input"v-model"queryParams.keyword"style"margin-bottom: 10px"type"text"prefix-icon"el-icon-search"size"small"placeholder"输入员工…

leetCode 40.组合总和 II + 回溯算法 + 剪枝 + used数组 + 图解

给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用 一次 注意&#xff1a;解集不能包含重复的组合 示例 1: 输入: candidates [10,1,2,7,6,1,5], t…

数据库应用-H2database--未授权访问命令执行漏洞

数据库应用-H2database–未授权访问&命令执行漏洞 Java SQL 数据库 H2,H2的主要特点是&#xff1a;非常快&#xff0c;开源&#xff0c;JDBC API&#xff1b;嵌入式和服务器模式&#xff1b;内存数据库&#xff1b;基于浏览器的控制台应用程序。 H2 数据库控制台中的另一…

依靠堡塔面板,飞速部署Java项目

依靠堡塔面板&#xff0c;飞速部署Java项目 环境介绍 环境介绍&#xff1a; 面板版本&#xff1a;8.0.26 操作系统版本&#xff1a;CentOS7.9.2009 Nginx版本&#xff1a;1.22 Java环境&#xff1a;Tomcat8&#xff0c;JDK&#xff1a;OpenJDK-1.8.0-internal MySQL版本&#…

028 - STM32学习笔记 - ADC(二) 独立模式单通道中断采集

028 - STM32学习笔记 - 结构体学习&#xff08;二&#xff09; 上节对ADC基础知识进行了学习&#xff0c;这节在了解一下ADC相关的结构体。 一、ADC初始化结构体 在标准库函数中基本上对于外设都有一个初始化结构体xx_InitTypeDef&#xff08;其中xx为外设名&#xff0c;例如…

数字时代的表演艺术:TikTok如何重新定义舞台

在数字时代的潮流中&#xff0c;TikTok崭露头角&#xff0c;重新定义了表演艺术的舞台。这款短视频应用不仅改变了用户与内容的互动方式&#xff0c;也为艺术家和创作者提供了全新的表达平台。本文将深入探讨TikTok如何在数字时代重新定义舞台&#xff0c;以及它对表演艺术的深…

《围城》思维导图

《围城》是一幅栩栩如生的市井百态图&#xff0c;人生的酸甜苦辣千般滋味均在其中得到了淋漓尽致的体现。钱钟书先生将自己的语言天才并入极其渊博的知识&#xff0c;再添加上一些讽刺主义的幽默调料&#xff0c;以一书而定江山。《围城》显示给我们一个真正的聪明人是怎样看人…

Nginx热部署

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;小编会及时修改&#xff09; Nginx热部署 首先来讲一下为什么要进行热部署 nginx 支持热加载 热部署 &#xff0c;在不打断用户请求的情…