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"); }
关键修改说明
- 替换目标属性:使用
DWMWA_CAPTION_BUTTON_COLORS(数值为35,部分旧SDK未定义,直接用数值避免编译问题),这是Windows 11专门用于自定义标题按钮颜色的属性。 - 使用正确数据结构:改用
DWM_CAPTION_BUTTON_COLORS结构体,其中cbtHover[2]对应关闭按钮的悬停颜色(索引0为最小化,1为最大化,2为关闭)。 - 增加类型检查:修改前验证参数大小是否匹配结构体尺寸,避免破坏其他数据。
- 缩小修改范围:仅修改关闭按钮的悬停颜色,保留其他按钮和状态的默认颜色,降低异常风险。
额外注意事项
- 此修改仅适用于Windows 11,Windows 10不支持
DWMWA_CAPTION_BUTTON_COLORS属性。 - 部分UWP应用或使用自定义标题栏的应用可能不响应此修改。
- 若仍有崩溃问题,可缩小
@include范围,仅针对特定应用测试,避免全局挂钩引发冲突。
内容的提问来源于stack exchange,提问作者Kai Piper
相关产品推荐
相关产品推荐

