在Windows11中常见的有:Acrylic(亚克力)、Mica(云母)、MicaAlt(特殊云母)

使用DWMAPI:dwmapi库来应用,理论支持任意Windows窗口,不仅限于C/C++

使用WindowsAPI(C++)为任意Windows窗口应用特殊背景样式

使用dwmapi

在C++中,使用Windows中头文件<dwmapi.h>

在Windows GUI程序开发中都可以间接、直接的使用C++接口

理论上,任意Windows窗口都可以实现效果,不限语言

基本:两个函数、两个枚举

先直接上代码,非常简单,后面是细讲

//HWND hwnd :变量 已获取的目标窗口句柄
constexpr auto type = DWM_SYSTEMBACKDROP_TYPE::DWMSBT_MAINWINDOW;
constexpr auto margins = MARGINS{-1, -1, -1, -1};
DwmExtendFrameIntoClientArea(hwnd, &margins);
DwmSetWindowAttribute(
    hwnd,
    DWMWINDOWATTRIBUTE::DWMWA_SYSTEMBACKDROP_TYPE,
    &type,
    sizeof(type));

hwnd Windows窗口句柄,在原生WindowsGUI开发中,可以直接使用,若使用框架

Qt中:使用WId QWidget::winId() const获取,转换 HWND hwnd = reinterpret_cast<HWND>(widget->winId())

wxWidgets中:使用virtual WXWidget wxWindow::GetHandle () const 获取,转换 HWND hwnd = static_cast<HWND>(window->GetHandle())

其他框架应该都有类似的接口

Bilibili视频 讲解|演示:https://www.bilibili.com/video/BV185FLeUESf

应用/实战

使用函数前,Windows可能并不会自动加载DWM库,需要手动加载

  • 使用MSVC编译器时 可以设置以下的预处理指令
    #pragma comment(lib, "dwmapi.lib")

  • 使用MinGW(gcc/g++)MSVC编译器时 可以动态加载库(通用)
    HMODULE dwmapi = LoadLibrary(L"dwmapi.dll");
    定义函数指针类型
    typedef HRESULT (WINAPI *pFN)(HWND, const MARGINS*);
    获取函数指针
    const auto DwmExtendFrameIntoClientArea = (pFN)(pfn_ExtendFrameIntoClientArea);

//在头文件中 xxx.h
#include <windows.h>
#ifdef _MSC_VER
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#else
constexpr auto DWMWA_SYSTEMBACKDROP_TYPE = 38;
typedef enum DWM_SYSTEMBACKDROP_TYPE {
  DWMSBT_AUTO,
  DWMSBT_NONE,
  DWMSBT_MAINWINDOW,
  DWMSBT_TRANSIENTWINDOW,
  DWMSBT_TABBEDWINDOW
};
typedef HRESULT (WINAPI *pExtendFrameIntoClientArea)(HWND, const MARGINS*);
typedef HRESULT (WINAPI *pSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
const extern pExtendFrameIntoClientArea DwmExtendFrameIntoClientArea;
const extern pSetWindowAttribute        DwmSetWindowAttribute;
#endif


//在源文件中 xxx.cpp
#ifndef _MSC_VER
HMODULE dwmapi = LoadLibrary(L"dwmapi.dll");
const auto pfn_ExtendFrameIntoClientArea = GetProcAddress(dwmapi, "DwmExtendFrameIntoClientArea")
const auto pfn_SetWindowAttribute = GetProcAddress(dwmapi, "DwmSetWindowAttribute");
const auto DwmExtendFrameIntoClientArea = reinterpret_cast<pExtendFrameIntoClientArea>(pfn_ExtendFrameIntoClientArea);
const auto DwmSetWindowAttribute = reinterpret_cast<pSetWindowAttribute>(pfn_SetWindowAttribute);
#endif
/* 最后可封装为以下函数 */

/// @brief 设置窗口样式
/// @param hwnd Windows窗口句柄
/// @param type 样式 从枚举DWM_SYSTEMBACKDROP_TYPE中选择
void SetWindowStyle(HWND hwnd, DWM_SYSTEMBACKDROP_TYPE type)
{
    constexpr auto margins = MARGINS{-1, -1, -1, -1}; //若值其中某一值为负数,则会扩展到整个窗口,正好满足需求
    auto style = GetWindowLong(hwnd, GWL_STYLE);
    style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CAPTION; //此处样式可以根据具体需求变换

    SetWindowLong(hwnd, GWL_STYLE, style);
    DwmExtendFrameIntoClientArea(hwnd, &margins);
    DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &type, sizeof(type));
}

对于样式样式枚举 DWM_SYSTEMBACKDROP_TYPE (仅为Windows11对应样式)

  1. DWMSBT_AUTO = 0 自动:由系统决定背景样式,默认不设置即为该值

  2. DWMSBT_NONE = 1 无:无背景样式,通常为白色背景或是对应主题色

  3. DWMSBT_MAINWINDOW = 2 主窗口 云母(mica):云母样式

  4. DWMSBT_TRANSIENTWINDOW = 3 暂时窗口(如对话框) 亚克力(Acrylic):亚克力,Windows10中主要样式

  5. DWMSBT_TABBEDWINDOW = 4 选项卡窗口 特殊云母(MicaAlt):特殊云母样式可能会随着Windwos版本更新而改变

注意事项:
  1. 若使用GUI框架需要进行对应操作,诸如Qt,窗口有默认颜色,需要将窗口背景色设为透明

  2. 使用非C/C++时,可以将上述函数封装为库,如Java:JNI,即可实现Java窗口背景样式设置

  3. 有时候加载可能失效建议加上获取值检查,如函数指针是否为空,获取到的module是否是

  4. 以上样式通常为Windows11,windows10并不能很好的支持,Windows10中只对亚克力(Acrylic)有完整支持

  5. 调用函数时,可以取两个函数的返回值类型:HRESULT确认是否成功

总结

  • 内容还是非常简单的,基本就两个函数,其他的就是版本还有编译器之类的问题了,最后注意参数等等即可。

参考文档
  1. (微软官方文档) 函数 其一 边框扩展 DwmExtendFrameIntoClientArea 函数

  2. (微软官方文档) 函数 其二 属性设置 DwmSetWindowAttribute 函数

  3. (微软官方文档) 枚举 其一 窗口属性 DWMWINDOWATTRIBUTE

  4. (微软官方文档) 枚举 其二 背景类型 DWM_SYSTEMBACKDROP_TYPE

  5. (哔哩哔哩视频) 我的视频:https://www.bilibili.com/video/BV185FLeUESf


Powered by Halo:Stellar