You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windhawk修改窗口关闭按钮悬停颜色遇问题求助

问题分析与修复方案

你的代码导致窗口异常的核心原因是错误修改了不相关的DWM窗口属性:

  • 钩子中判断的DWMWA_CAPTION_BUTTON_BOUNDS是用于设置标题按钮矩形边界的属性,参数类型为RECT*,而非COLORREF*。强行将其转为颜色指针修改会破坏窗口布局数据,直接引发窗口显示异常、无法交互。
  • 要修改关闭按钮悬停颜色,需使用Windows 11新增的DWMWA_CAPTION_BUTTON_COLORS属性,其对应参数为DWM_CAPTION_BUTTON_COLORS结构体,专门用于自定义标题按钮的各状态颜色。

修复后的完整代码

// ==WindhawkMod==
// @id              close-button-hover-color-changer
// @name            Close Button Hover Color Changer
// @description     Changes the close button's hover color on Windows 11
// @version         3.0
// @author          AssistantModder
// @github          https://github.com/AssistantModder
// @include         *
// @compilerOptions -ldwmapi -luser32 -lgdi32
// ==/WindhawkMod==

// ==WindhawkModReadme==
/*
# Close Button Hover Color Changer

Customizes the hover color of the close button for Windows 11 applications using DWM API.

## Features
- Targets only the close button's hover state
- Preserves other title button states (normal, pressed)
- Avoids unintended window layout corruption
- Detailed logging for troubleshooting

Note: Works with most Win32 apps; UWP apps may not support this customization.
*/
// ==/WindhawkModReadme==

// ==WindhawkModSettings==
/*
- closeButtonHoverColor: "#FF6666"
  $name: Hover Color
  $description: Color when hovering over the close button (e.g., #FF0000 for red, #00FF00 for green).
- enableMod: true
  $name: Mod Enabled
  $description: Toggle the mod on or off.
- logLevel: 3
  $name: Logging Level
  $description: Set logging level - 0:None, 1:Error, 2:Warning, 3:Info, 4:Debug
*/
// ==/WindhawkModSettings==

#include <windows.h>
#include <dwmapi.h>
#include <stdio.h>

// Structure to hold the mod's settings
struct ModSettings {
    COLORREF hoverColor;
    BOOL enableMod;
    int logLevel;
} settings;

// DWM caption button colors structure (Windows 11+)
typedef struct _DWM_CAPTION_BUTTON_COLORS {
    COLORREF cbtNormal[3];      // Minimize, Maximize, Close (normal state)
    COLORREF cbtHover[3];       // Minimize, Maximize, Close (hover state)
    COLORREF cbtPressed[3];     // Minimize, Maximize, Close (pressed state)
} DWM_CAPTION_BUTTON_COLORS;

// Function prototype for the DWM API call
typedef HRESULT (WINAPI *DwmSetWindowAttributeFptr)(HWND, DWORD, LPCVOID, DWORD);

// Original function pointer
DwmSetWindowAttributeFptr DwmSetWindowAttribute_Original;

// Converts a hex string to COLORREF
COLORREF HexStringToCOLORREF(const wchar_t* hexColor) {
    unsigned int r, g, b;
    if (hexColor && wcslen(hexColor) == 7 && swscanf(hexColor, L"#%02x%02x%02x", &r, &g, &b) == 3) {
        return RGB(r, g, b);
    }
    Wh_Log(L"Error: Invalid hex color format '%s'. Using default red.", hexColor);
    return RGB(255, 0, 0); // Default to red on failure
}

// Custom logging function based on the log level
void CustomLog(int level, const wchar_t* format, ...) {
    if (level <= settings.logLevel) {
        va_list args;
        va_start(args, format);
        wchar_t buffer[256];
        vswprintf(buffer, sizeof(buffer) / sizeof(wchar_t), format, args);
        va_end(args);
        Wh_Log(L"%s", buffer);
    }
}

// Hook function for DwmSetWindowAttribute to change close button hover color
HRESULT WINAPI DwmSetWindowAttribute_Hook(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) {
    if (settings.enableMod && pvAttribute) {
        // Check if we're dealing with caption button colors attribute
        if (dwAttribute == 35) { // DWMWA_CAPTION_BUTTON_COLORS is 35 (not defined in older SDKs)
            if (cbAttribute == sizeof(DWM_CAPTION_BUTTON_COLORS)) {
                // Cast to the correct structure type
                DWM_CAPTION_BUTTON_COLORS* colors = (DWM_CAPTION_BUTTON_COLORS*)pvAttribute;
                COLORREF originalHoverColor = colors->cbtHover[2]; // Close button is index 2
                
                CustomLog(4, L"Close button original hover color: 0x%06X", originalHoverColor);
                colors->cbtHover[2] = settings.hoverColor;
                CustomLog(4, L"Close button hover color changed to: 0x%06X", settings.hoverColor);
            } else {
                CustomLog(2, L"Unexpected size for DWMWA_CAPTION_BUTTON_COLORS: %lu", cbAttribute);
            }
        }
    }
    return DwmSetWindowAttribute_Original(hwnd, dwAttribute, pvAttribute, cbAttribute);
}

// Load settings from the Windhawk mod settings
void LoadSettings() {
    settings.hoverColor = HexStringToCOLORREF(Wh_GetStringSetting(L"closeButtonHoverColor"));
    settings.enableMod = Wh_GetIntSetting(L"enableMod") != 0;
    settings.logLevel = Wh_GetIntSetting(L"logLevel");
    CustomLog(3, L"Settings loaded: HoverColor=0x%06X, EnableMod=%d, LogLevel=%d", 
              settings.hoverColor, settings.enableMod, settings.logLevel);
}

// Initialization function for the mod
BOOL Wh_ModInit() {
    LoadSettings();

    HMODULE dwmapiModule = GetModuleHandle(L"dwmapi.dll");
    if (!dwmapiModule) {
        dwmapiModule = LoadLibrary(L"dwmapi.dll");
        if (!dwmapiModule) {
            CustomLog(1, L"Failed to load dwmapi.dll module");
            return FALSE;
        }
    }

    DwmSetWindowAttribute_Original = (DwmSetWindowAttributeFptr)GetProcAddress(dwmapiModule, "DwmSetWindowAttribute");
    if (!DwmSetWindowAttribute_Original) {
        CustomLog(1, L"Failed to get DwmSetWindowAttribute function address");
        return FALSE;
    }

    if (!Wh_SetFunctionHook((void*)DwmSetWindowAttribute_Original, (void*)DwmSetWindowAttribute_Hook, (void**)&DwmSetWindowAttribute_Original)) {
        CustomLog(1, L"Failed to set hook for DwmSetWindowAttribute");
        return FALSE;
    }

    CustomLog(3, L"Mod initialized successfully");
    return TRUE;
}

// Function called when the mod settings are changed
void Wh_ModSettingsChanged() {
    LoadSettings();
    CustomLog(3, L"Settings reloaded");
}

// Uninitialization function for the mod
void Wh_ModUninit() {
    CustomLog(3, L"Mod uninitialized");
}

关键修改说明

  1. 替换目标属性:使用DWMWA_CAPTION_BUTTON_COLORS(数值为35,部分旧SDK未定义,直接用数值避免编译问题),这是Windows 11专门用于自定义标题按钮颜色的属性。
  2. 使用正确数据结构:改用DWM_CAPTION_BUTTON_COLORS结构体,其中cbtHover[2]对应关闭按钮的悬停颜色(索引0为最小化,1为最大化,2为关闭)。
  3. 增加类型检查:修改前验证参数大小是否匹配结构体尺寸,避免破坏其他数据。
  4. 缩小修改范围:仅修改关闭按钮的悬停颜色,保留其他按钮和状态的默认颜色,降低异常风险。

额外注意事项

  • 此修改仅适用于Windows 11,Windows 10不支持DWMWA_CAPTION_BUTTON_COLORS属性。
  • 部分UWP应用或使用自定义标题栏的应用可能不响应此修改。
  • 若仍有崩溃问题,可缩小@include范围,仅针对特定应用测试,避免全局挂钩引发冲突。

内容的提问来源于stack exchange,提问作者Kai Piper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:44:52