DWM 相关实现代码 [自用]

news2024/9/20 20:50:05

· 1. DWM 缩略图和模糊隐藏实现半透明

#include <windows.h>
#include <dwmapi.h>
#include <string>
#pragma comment(lib, "dwmapi.lib")

// 检查 UWP 窗口是否可见
bool IsUWPWindowVisible(HWND hwnd) {
    DWORD cloaked = 0;
    DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked));
    return (cloaked == 0);
}

bool IsBadWindow(HWND hwnd) {
    wchar_t title[256];
    wchar_t className[256];
    GetWindowTextW(hwnd, title, 256);
    GetClassNameW(hwnd, className, 256);

    LPCWSTR badTitleList[] = { L"NVIDIA", L"Xaml" };

    for (LPCWSTR badTitle : badTitleList) {
        if (wcsstr(title, badTitle) != nullptr) {
            return true;
        }
    }

    return false;
}

void UpdateInfoWindow(HWND infoHwnd, HWND mainHwnd) {
    if (infoHwnd) {
        RECT mdrc;
        GetWindowRect(mainHwnd, &mdrc);

        // 获取屏幕工作区和任务栏的位置信息
        RECT rcWorkArea = { 0 };
        SystemParametersInfoW(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
        HWND hTrayWnd = FindWindowW(L"Shell_TrayWnd", nullptr);

        // 计算任务栏是否遮挡信息窗口
        bool taskbarVisible = false;
        if (IsWindow(hTrayWnd)
            && IsWindowVisible(hTrayWnd)) {
            RECT tbrc;
            GetWindowRect(hTrayWnd, &tbrc);

            if (tbrc.top >= rcWorkArea.bottom && mdrc.bottom + 50 > tbrc.top) {
                // 任务栏在底部且信息窗口底部超出工作区域底部
                taskbarVisible = true;
            }
        }

        if (taskbarVisible) {
            // 将信息窗口移动到窗口上方
            SetWindowPos(infoHwnd, nullptr, mdrc.left + 10, mdrc.top - 110,
                mdrc.right - mdrc.left - 25,
                100, SWP_NOZORDER | SWP_SHOWWINDOW);
        }
        else {
            // 将信息窗口移动到窗口底部
            SetWindowPos(infoHwnd, nullptr, mdrc.left + 10, mdrc.bottom,
                mdrc.right - mdrc.left - 25,
                100, SWP_NOZORDER | SWP_SHOWWINDOW);
        }
    }
}

LRESULT CALLBACK InfoWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rc;
        GetClientRect(hwnd, &rc);

        // 获取目标窗口信息
        HWND targetHwnd = (HWND)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
        if (targetHwnd) {
            wchar_t title[256];
            wchar_t className[256];
            GetWindowTextW(targetHwnd, title, 256);
            GetClassNameW(targetHwnd, className, 256);
            wchar_t info[512];
            swprintf(info, 512, L"Title: %s\nClass: %s\nHandle: 0x%llX",
                title, className, (UINT_PTR)targetHwnd);

            // 绘制信息文本
            SetBkMode(hdc, TRANSPARENT);
            SetTextColor(hdc, RGB(0, 0, 0));
            DrawTextW(hdc, info, -1, &rc, DT_LEFT | DT_TOP | DT_NOPREFIX);
        }

        EndPaint(hwnd, &ps);
        return 0;
    }
    default:
        break;
    }
    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    static HTHUMBNAIL thumbnail = NULL;
    static HWND infoHwnd = NULL;
    static HWND oldBehindWnd = NULL;

    // 最小窗口尺寸
    const int MIN_WIDTH = 100;
    const int MIN_HEIGHT = 100;

    switch (uMsg) {
    case WM_CREATE: {
        // 创建子窗口用于显示信息
        HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE);
        const wchar_t INFO_CLASS_NAME[] = L"InfoWindowClass";

        WNDCLASS wc = {};
        wc.lpfnWndProc = InfoWindowProc;
        wc.hInstance = hInstance;
        wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  // 白色背景
        wc.lpszClassName = INFO_CLASS_NAME;

        RegisterClassW(&wc);

        infoHwnd = CreateWindowExW(
            WS_EX_TRANSPARENT | WS_EX_NOACTIVATE,  // 扩展窗口样式
            INFO_CLASS_NAME,                 // 窗口类名
            nullptr,                         // 窗口标题
            WS_POPUP,                        // 窗口样式
            0, 0, 800, 100,                  // 窗口尺寸
            hwnd, nullptr, hInstance, nullptr
        );

        if (infoHwnd == nullptr) {
            return 0;
        }

        SetLayeredWindowAttributes(infoHwnd, RGB(0,0,0), 0, LWA_COLORKEY);

        // 初始化信息窗口的位置
        RECT rc;
        GetWindowRect(hwnd, &rc);
        SetWindowPos(infoHwnd, nullptr, rc.left + 10, rc.bottom, 0, 0,
            SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
    }
    case WM_ACTIVATE: {
        // 查找第一个可见且尺寸不小于最小尺寸的后台窗口
        HWND hwndBehind = GetWindow(hwnd, GW_HWNDNEXT);
        while (hwndBehind) {
            if (IsWindowVisible(hwndBehind)
                && IsUWPWindowVisible(hwndBehind)
                 && !IsBadWindow(hwndBehind)) {
                RECT rcBehind;
                GetWindowRect(hwndBehind, &rcBehind);
                int width = rcBehind.right - rcBehind.left;
                int height = rcBehind.bottom - rcBehind.top;
                
                if (width >= MIN_WIDTH && height >= MIN_HEIGHT) {
                    break;
                }
            }
            hwndBehind = GetWindow(hwndBehind, GW_HWNDNEXT);
        }


        if (oldBehindWnd != hwndBehind) {

            // 注销当前缩略图
            if (thumbnail) {
                DwmUnregisterThumbnail(thumbnail);
                thumbnail = NULL;
            }

            if (hwndBehind) {
                oldBehindWnd = hwndBehind;

                // 注册后台窗口的缩略图
                DwmRegisterThumbnail(hwnd, hwndBehind, &thumbnail);

                RECT rcBehindWnd;
                GetWindowRect(hwndBehind, &rcBehindWnd);
                SetWindowPos(hwnd, nullptr,
                    0, 0,
                    rcBehindWnd.right - rcBehindWnd.left,
                    rcBehindWnd.bottom - rcBehindWnd.top + 50,
                    SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW);

                // 更新缩略图属性
                RECT rcClient;
                GetClientRect(hwnd, &rcClient);
                DWM_THUMBNAIL_PROPERTIES dpt;
                dpt.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_OPACITY;
                dpt.rcDestination = rcClient;
                dpt.opacity = (BYTE)(255 * 0.7);  // 设置透明度为70%
                DwmUpdateThumbnailProperties(thumbnail, &dpt);

                // 设置子窗口的用户数据为目标窗口句柄
                SetWindowLongPtrW(infoHwnd, GWLP_USERDATA, (LONG_PTR)hwndBehind);

                InvalidateRect(infoHwnd, NULL, TRUE);  // 重新绘制子窗口
            }
            else {
                // 设置子窗口的用户数据为目标窗口句柄
                SetWindowLongPtrW(infoHwnd, GWLP_USERDATA, (LONG_PTR)NULL);

                MessageBoxW(NULL,
                    L"没有找到合适窗口", L"提示",
                    MB_OK | MB_ICONINFORMATION |
                    MB_APPLMODAL | MB_TOPMOST);
            }
        }
        return 0;
    }
    case WM_DESTROY:
        if (thumbnail) {
            DwmUnregisterThumbnail(thumbnail);
        }
        PostQuitMessage(0);
        return 0;
    case WM_SIZE: {
        if (thumbnail) {
            RECT rcClient;
            GetClientRect(hwnd, &rcClient);

            // 窗口大小改变时重新扩展DWM框架到客户区
            MARGINS margins = { 0, 0, 0, rcClient.bottom - rcClient.top };
            DwmExtendFrameIntoClientArea(hwnd, &margins);

            // 更新缩略图属性
            DWM_THUMBNAIL_PROPERTIES dpt;
            dpt.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_OPACITY;
            dpt.rcDestination = rcClient;
            dpt.opacity = (BYTE)(255 * 0.7);  // 设置透明度为70%
            DwmUpdateThumbnailProperties(thumbnail, &dpt);
        }

        // 更新信息窗口的位置
        UpdateInfoWindow(infoHwnd, hwnd);
        return 0;
    }
    case WM_MOVE: {
        // 更新信息窗口的位置
        UpdateInfoWindow(infoHwnd, hwnd);
        return 0;
    }
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rc;
        GetClientRect(hwnd, &rc);

        // 绘制半透明背景
        HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
        SetBkMode(hdc, TRANSPARENT);
        FillRect(hdc, &rc, hBrush);
        DeleteObject(hBrush);

        EndPaint(hwnd, &ps);
        return 0;
    }
    default:
        return DefWindowProcW(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
    // 注册窗口类
    const wchar_t CLASS_NAME[] = L"TransparentWindowClass";
    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);  // 防止背景重绘
    wc.lpszClassName = CLASS_NAME;

    RegisterClassW(&wc);

    // 创建窗口
    HWND hwnd = CreateWindowExW(
        WS_EX_NOREDIRECTIONBITMAP,  // 扩展窗口样式
        CLASS_NAME,                 // 窗口类名
        L"Transparent Window",      // 窗口标题
        WS_OVERLAPPEDWINDOW,        // 窗口样式
        CW_USEDEFAULT, CW_USEDEFAULT, 1000, 600,
        nullptr, nullptr, hInstance, nullptr
    );

    if (hwnd == nullptr) {
        return 0;
    }

    // 使用 DWM API 设置毛玻璃效果
    DWM_BLURBEHIND bb = { 0 };
    bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
    bb.fEnable = TRUE;
    bb.hRgnBlur = NULL;
    DwmEnableBlurBehindWindow(hwnd, &bb);

    // 设置标题栏颜色为深色(示例为灰色)
    COLORREF grey = RGB(30, 30, 30);
    DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &grey, sizeof(grey));

    // 显示窗口
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // 消息循环
    MSG msg = {};
    while (GetMessageW(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return 0;
}

效果图:

窗口缩略图实现背景墙(自动识别窗口切换)

窗口切换和大小跟随: 

演示截图 2

· 2. 更多代码......

(...)


本文发布于:2024.07.08

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

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

相关文章

基于jeecgboot-vue3的Flowable流程-集成仿钉钉流程(六)仿钉钉流程的转bpmn流程图

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、转bpmn流程图接口 /*** 转为bpmn xml格式* param processModel* throws IOException*/PostMapping("/ddtobpmnxml")public Result<?> ddToBpmnXml(RequestBody Proce…

Linux 初识

目录 ​编辑 1.Linux发展史 1.1UNIX发展历史 1.2Linux发展历史 2.Linux的开源属性 2.1 开源软件的定义 2.2 Linux的开源许可证 2.3 开源社区与协作 3.Linux的企业应用现状 3.1 服务器 3.1.1 Web服务器 3.1.2 数据库服务器 3.1.3 文件服务器 3.1.4 电子邮件服务器 …

天润融通引领客服革新,AI大模型助力品牌服务升级

AI时代&#xff0c;消费零售品牌的客户服务应该怎么做&#xff1f; 如今消费者的关注点已经越来越复杂&#xff0c;一条毛巾&#xff0c;关注点就可以包括&#xff1a; 是否婴幼儿可用&#xff0c;是否儿童成人可用&#xff1b;是否可以直接接触皮肤&#xff1b;是否无甲醛、…

算法日常练习

对于这个题&#xff0c;如何处理同一个方向的问题&#xff0c;且对于同一组的如果间隔太大如何实现离散化 #include<bits/stdc.h> using namespace std;#define int long long typedef long long ll; map<pair<int,int>,vector<pair<ll,ll>>> mp…

张量笔记(4):张量网络

张量分解通常是将高维张量分解成一系列较低维的张量&#xff0c;表示能力相对较低。而张量网络可以表示复杂的高维数据结构&#xff0c;通过连接多个张量形成网络结构&#xff0c;可以更灵活地表示和处理复杂的数据关系。本节主要介绍HT和TT网络。 2.5.1 HT分解——首先我们引入…

Neo4j安装

下载地址&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 1.安装jdk&#xff0c;Neo4j 3.0需要jdk8&#xff0c;2.3.0之前的版本建议jdk7。Neo4j最新版本5.21.2&#xff0c;对应jdk版本17 2.将下载的zip文件解压到合适路径。 3.设置环境变量NEO4J_H…

LinkedList----源码分析

源码介绍 public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable{} 添加过程中的操作&#xff1a; 当创建LinkedList类时&#xff0c;会调用其空参构造方法&#xff0c;将其参…

STM32中断(NVIC和EXIT)

CM3 内核支持 256 个中断&#xff0c;其中包含了 16 个内核中断和 240个外部中断&#xff0c;并且具有 256 级的可编程中断设置。但STM32 并没有使用CM3内核的全部东西&#xff0c;而是只用了它的一部分。STM32有 76 个中断&#xff0c;包括16 个内核中断和 60 个可屏蔽中断&am…

MySQL字符串相关数据处理函数

目录 1. 转大小写 2. 截取字符串 sunstr 3. 获取字符长度 4. 字符串拼接 concat 5. 去掉空白 trim 1. 转大小写 转大写&#xff1a;upper() 转小写&#xff1a;lower() 虽然MySQL不严格区分大小写&#xff0c;但是我们还是需要掌握这种大小写的操作以方便学习其他…

Dify中的RAG和知识库

一.RAG 基本架构 当用户提问 “美国总统是谁&#xff1f;” 时&#xff0c;系统并不是将问题直接交给大模型来回答&#xff0c;而是先将用户问题在知识库中进行向量搜索&#xff0c;通过语义相似度匹配的方式查询到相关的内容&#xff08;拜登是美国现任第46届总统…&#xff0…

Adobe Illustrator 2021 for mac/Win:专业矢量图形设计的巅峰之作

Adobe Illustrator 2021作为Adobe公司旗下的旗舰矢量图形设计软件&#xff0c;无论是对于Mac还是Windows用户&#xff0c;都提供了强大而灵活的设计工具&#xff0c;让设计师们能够轻松应对各种复杂的图形设计挑战。这款软件以其卓越的性能、丰富的功能和友好的用户界面&#x…

Spring MVC入门2

Postman的使用 接上期我们抛出了一个问题&#xff0c;Postman的使用 可以点击链接下载 https://www.postman.com/downloads/ 安装之后会提示版本升级&#xff0c;直接点击dissmiss即可。 要想发送数据&#xff0c;具体歩奏如下简图&#xff1a; 还有一个更具体的图&#xff…

Fastgpt本地使用Docker Compose 快速部署

使用 Docker Compose 快速部署 FastGPT 部署架构图 MongoDB:用于存储除了向量外的各类数据 PostgreSQL/Milvus:存储向量数据 OneAPI: 聚合各类 AI API,支持多模型调用 (任何模型问题,先自行通过 OneAPI 测试校验) 推荐配置 PgVector版本 体验测试首选 环境最低配置(单…

解决浏览器 CORS跨域问题

跨域问题其实就是不同源请求导致 解决跨域问题时&#xff0c;Chrome 插件 requestly 解决 1、Chrome 应用商店 &#xff1a;chrome://extensions/ 搜索 requestly 插件。并添加到扩展程序 2、打开扩展程序&#xff0c;为当前接口设置请求头 在response Header 中设置 Acce…

使用getopt处理参数

文章目录 使用getopt处理参数1. shift 命令1.1 删除一个参数1.2 删除多个参数1.3 多次执行 shift 参数1.4 参数解析示例1.5 优化处理1.6 问题处理 2. getopt 命令2.1 常用参数及示例2.2 脚本参数优化示例2.3 参数校验 3. 示例展示4. eval 命令4.1 示例示例 1示例 2示例 3示例 4…

2022 RoboCom省赛题目解析

题目解析&#xff1a;这就是一题很简单的模拟&#xff0c;直接上代码&#xff1b; #include<iostream> using namespace std; const int N 10010; int arr[N]; int main() {int n , m;cin >> n >> m;int sum 0;int res 0;for(int i 0; i < n;i ) cin…

大学生暑假“三下乡”社会实践工作新闻投稿指南请查收!

近年来&#xff0c;大学生暑期“三下乡”社会实践工作方兴未艾&#xff0c;越来越多的大学生通过参与“三下乡”实践工作&#xff0c;走出校园&#xff0c;深入基层&#xff0c;体验农村生活&#xff0c;服务农民&#xff0c;促进农村经济社会发展&#xff0c;实现了理论与实践…

Java链表LinkedList经典题目

一.LinkedList的方法 首先先看一下链表的方法&#xff1a; 方法解释boolean add(E e)尾插void add(int index, E element)将 e 插入到 index 位置boolean addAll(Collection c)尾插 c 中的元素E remove(int index)删除 index 位置元素boolean remove(Object o)删除遇到的第一…

CSS技巧专栏:一日一例 4.纯CSS实现两款流光溢彩的酷炫按钮特效

大家好&#xff0c;今天是 CSS技巧专栏&#xff1a;一日一例 第三篇《纯CSS实现两款流光溢彩的酷炫按钮特效》 先看图&#xff1a; 特此说明&#xff1a; 本专题专注于讲解如何使用CSS制作按钮特效。前置的准备工作和按钮的基本样式&#xff0c;都在本专栏第一篇文章中又详细…

k8s集群部署mysql8主备

一、搜索mysql8版本 # helm search repo mysql# helm pull bitnami/mysql --version:11.1.2# tar -zxf mysql-11.1.2.tgz# cd mysql 二、修改value.ysqml文件 动态存储类自己提前搭建。 # helm install mysql8 -n mysql-cluster ./ -f values.yaml NAME: mysql8 LAST DEPLOYED…