You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Windhawk模组编译报错:Expected unqualified-id及括号匹配问题

编译错误日志

JSON格式诊断信息

[{
    "resource": "/c:/ProgramData/Windhawk/EditorWorkspace/mod.wh.cpp",
    "owner": "_generated_diagnostic_collection_name_#0",
    "code": "expected_unqualified_id",
    "severity": 8,
    "message": "Expected unqualified-id",
    "source": "clang",
    "startLineNumber": 23,
    "startColumn": 1,
    "endLineNumber": 23,
    "endColumn": 2
}]

详细编译错误输出

c:\ProgramData\Windhawk\EditorWorkspace\mod.wh.cpp:24:3: error: expected unqualified-id
   24 |   "closeButtonHoverColor": {
      |   ^
c:\ProgramData\Windhawk\EditorWorkspace\mod.wh.cpp:81:16: error: expected ')'
   81 |         Wh_Log(buffer);  // 确保宏展开正确
      |                ^
c:\ProgramData\Windhawk\EditorWorkspace\mod.wh.cpp:81:9: note: 匹配此处的'('
   81 |         Wh_Log(buffer);  // 确保宏展开正确
      |         ^
c:/Program Files/Windhawk/Compiler/include/windhawk_api.h:71:35: note: 从宏'Wh_Log'展开
   71 |             InternalWh_Log_Wrapper(L"[%d:%S]: " message, __LINE__, \
      |                                   ^
生成2个错误。
完整模组代码
// ==WindhawkMod==
// @id              close-button-hover-color-changer
// @name            关闭按钮悬停颜色修改器
// @description     修改所有应用程序中关闭按钮的悬停颜色
// @version         1.0
// @author          AssistantModder
// @github          https://github.com/AssistantModder
// @include         *
// @compilerOptions -ldwmapi -luser32 -lgdi32
// ==/WindhawkMod==

// ==WindhawkModReadme==
/*
此模组可自定义所有使用Windows DWM API的应用程序的关闭按钮悬停颜色。
特性:
- 修改关闭按钮的悬停颜色。
- 基础错误处理与日志记录,便于排查问题。
*/
// ==/WindhawkModReadme==

// 定义Windhawk模组设置
// ==WindhawkModSettings==
{
  "closeButtonHoverColor": {
    "type": "string",
    "default": "#FF6666",
    "title": "悬停颜色",
    "description": "鼠标悬停在关闭按钮上时的颜色。"
  },
  "enableMod": {
    "type": "boolean",
    "default": true,
    "title": "启用模组",
    "description": "开启或关闭此模组。"
  },
  "logLevel": {
    "type": "integer",
    "default": 1,
    "minimum": 0,
    "maximum": 4,
    "title": "日志级别",
    "description": "设置日志级别:0-无,1-错误,2-警告,3-信息,4-调试"
  }
}
// ==/WindhawkModSettings==

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

// 存储模组设置的结构体
struct ModSettings {
    COLORREF hoverColor;
    BOOL enableMod;
    int logLevel;
} settings;

// DWM API调用的函数原型
typedef HRESULT (WINAPI *DwmSetWindowAttributeFptr)(HWND, DWORD, LPCVOID, DWORD);

// 原始函数指针
DwmSetWindowAttributeFptr OriginalDwmSetWindowAttribute = nullptr;

// 将十六进制字符串转换为COLORREF
COLORREF HexStringToCOLORREF(const wchar_t* hexColor) {
    unsigned int r, g, b;
    if (wcslen(hexColor) == 7 && swscanf_s(hexColor, L"#%02x%02x%02x", &r, &g, &b) == 3) {
        return RGB(r, g, b);
    }
    Wh_Log(L"错误:无效的十六进制颜色格式'%s',使用默认红色。", hexColor);
    return RGB(255, 0, 0); // 转换失败时默认使用红色
}

// 基于日志级别的自定义日志函数
void CustomLog(int level, const wchar_t* format, ...) {
    if (level <= settings.logLevel) {
        va_list args;
        va_start(args, format);
        wchar_t buffer[256];
        vswprintf_s(buffer, sizeof(buffer) / sizeof(buffer[0]), format, args);
        Wh_Log(buffer);  // 确保宏展开正确
        va_end(args);
    }
}

// 用于修改关闭按钮悬停颜色的DwmSetWindowAttribute钩子函数
HRESULT WINAPI HookDwmSetWindowAttribute(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) {
    if (settings.enableMod && dwAttribute == 35) { // 35是未公开的DWMWA_CAPTION_COLOR_HOVER
        *(COLORREF*)pvAttribute = settings.hoverColor;
        CustomLog(4, L"将标题悬停颜色设置为0x%06X", settings.hoverColor);
    }
    return OriginalDwmSetWindowAttribute(hwnd, dwAttribute, pvAttribute, cbAttribute);
}

// 从Windhawk模组设置加载配置
void LoadSettings() {
    settings.hoverColor = HexStringToCOLORREF(Wh_GetStringSetting(L"closeButtonHoverColor"));
    settings.enableMod = Wh_GetIntSetting(L"enableMod") != 0;  // 转换为布尔值
    settings.logLevel = Wh_GetIntSetting(L"logLevel");
}

// 模组初始化函数
BOOL Wh_ModInit() {
    LoadSettings();

    HMODULE dwmapiModule = GetModuleHandle(L"dwmapi.dll");
    if (!dwmapiModule) {
        CustomLog(1, L"获取dwmapi.dll模块句柄失败");
        return FALSE;
    }

    OriginalDwmSetWindowAttribute = (DwmSetWindowAttributeFptr)GetProcAddress(dwmapiModule, "DwmSetWindowAttribute");
    if (!OriginalDwmSetWindowAttribute) {
        CustomLog(1, L"获取DwmSetWindowAttribute函数地址失败");
        return FALSE;
    }

    // 挂钩DwmSetWindowAttribute函数
    Wh_SetFunctionHook((void*)OriginalDwmSetWindowAttribute, (void*)HookDwmSetWindowAttribute, (void**)&OriginalDwmSetWindowAttribute);
    CustomLog(3, L"模组初始化成功");
    return TRUE;
}

// 模组设置更改时调用的函数
void Wh_ModSettingsChanged() {
    LoadSettings();
    CustomLog(3, L"配置已重新加载");
}

// 模组卸载函数
void Wh_ModUninit() {
    CustomLog(3, L"模组已卸载");
}
已尝试的修复措施
  • 修正注释位置:将Windhawk模组设置移到注释块外,修复模组设置未在注释块外正确定义的错误。
  • 调整日志宏:确保Wh_Log宏的正确使用,验证日志函数通过vswprintf_s正确处理格式化字符串。
  • 修复保留关键字使用:避免使用char等保留关键字作为变量名。
  • 修正函数指针处理:确保DwmSetWindowAttribute的函数指针定义和使用正确。
  • HexStringToCOLORREF中的错误处理:添加无效十六进制颜色格式的错误处理。
  • 布尔设置获取:使用Wh_GetBoolSetting获取布尔类型设置。
错误修复方案

第一个错误:expected unqualified-id(第24行)

该错误是因为Windhawk模组设置块的JSON内容未被正确注释,编译器将其当作C++代码解析。Windhawk要求设置块的JSON必须被多行注释包裹,修改后的设置块如下:

// ==WindhawkModSettings==
/*
{
  "closeButtonHoverColor": {
    "type": "string",
    "default": "#FF6666",
    "title": "悬停颜色",
    "description": "鼠标悬停在关闭按钮上时的颜色。"
  },
  "enableMod": {
    "type": "boolean",
    "default": true,
    "title": "启用模组",
    "description": "开启或关闭此模组。"
  },
  "logLevel": {
    "type": "integer",
    "default": 1,
    "minimum": 0,
    "maximum": 4,
    "title": "日志级别",
    "description": "设置日志级别:0-无,1-错误,2-警告,3-信息,4-调试"
  }
}
*/
// ==/WindhawkModSettings==

第二个错误:expected ')'(第81行)

该错误是因为Wh_Log是预处理宏,要求传入的格式化字符串必须是字面量,无法直接传入变量。修改自定义日志函数的调用方式即可解决:

void CustomLog(int level, const wchar_t* format, ...) {
    if (level <= settings.logLevel) {
        va_list args;
        va_start(args, format);
        wchar_t buffer[256];
        vswprintf_s(buffer, sizeof(buffer) / sizeof(buffer[0]), format, args);
        Wh_Log(L"%s", buffer);  // 将buffer作为格式化参数传入
        va_end(args);
    }
}

额外优化:布尔设置获取

LoadSettings中的布尔值获取改为Wh_GetBoolSetting,更符合API设计:

void LoadSettings() {
    settings.hoverColor = HexStringToCOLORREF(Wh_GetStringSetting(L"closeButtonHoverColor"));
    settings.enableMod = Wh_GetBoolSetting(L"enableMod");
    settings.logLevel = Wh_GetIntSetting(L"logLevel");
}

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

火山引擎 最新活动