运行时切换#32768(菜单)窗口类主题的问题
关于插件DLL中启用暗色模式后菜单弹窗未自动切换的问题
我通过插件DLL启用暗色模式时,主窗口已存在,导致菜单弹窗无法自动切换到暗色主题,缺少触发机制。
当我从全屏切换为普通窗口,或在Windows 11设置中修改主题时,菜单下拉框会自动启用暗色模式。目前找到的方法是调用SendMessage(hWnd, WM_DWMNCRENDERINGCHANGED, FALSE, 0);,但该操作会破坏主窗口的全屏布局。请问推荐的解决方式是什么?我可以自定义绘制弹窗,但既然某些事件能触发正常切换,能否明确这些事件并找到官方解决方案?
HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); ASSERT(hUxtheme); SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135)); ASSERT(SetPreferredAppMode); AllowDarkModeForWindow = (fnAllowDarkModeForWindow)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133)); ASSERT(AllowDarkModeForWindow); SetPreferredAppMode(PreferredAppMode::ForceDark); void enableImmersiveDarkMode(HWND hWnd) { BOOL USE_DARK_MODE = true; BOOL SET_IMMERSIVE_DARK_MODE_SUCCESS = SUCCEEDED(DwmSetWindowAttribute( hWnd, DWMWINDOWATTRIBUTE::DWMWA_USE_IMMERSIVE_DARK_MODE, &USE_DARK_MODE, sizeof(USE_DARK_MODE))); }
推荐解决方案
1. 触发菜单主题切换的系统事件
你观察到的全屏/窗口切换、系统主题修改时菜单自动切换,本质是系统向窗口发送了主题变更相关通知,核心消息包括:
WM_THEMECHANGED:系统主题(含明暗模式)变更时发送,所有窗口都会收到,触发控件重新加载主题资源WM_DWMCOLORIZATIONCOLORCHANGED:DWM着色颜色变更(通常关联明暗模式切换)时发送WM_SETTINGCHANGE:系统设置(如主题)变更时,可能附带主题相关参数
这些消息不会修改窗口布局,只会通知控件更新主题渲染。
2. 官方合规的触发方式
无需使用破坏布局的WM_DWMNCRENDERINGCHANGED,按以下步骤操作即可:
步骤1:确保菜单窗口允许暗色模式
在启用暗色模式后,对菜单窗口的HWND调用AllowDarkModeForWindow:
// 假设hMenuWnd是菜单弹窗的句柄 AllowDarkModeForWindow(hMenuWnd, TRUE);
步骤2:发送主题变更消息触发更新
在你的暗色模式启用代码执行完成后,向主窗口和已存在的菜单窗口发送WM_THEMECHANGED:
// 通知主窗口更新主题 SendMessage(hMainWnd, WM_THEMECHANGED, 0, 0); // 若能获取菜单窗口句柄,直接通知它 if (hMenuWnd != NULL) { SendMessage(hMenuWnd, WM_THEMECHANGED, 0, 0); }
步骤3:处理动态创建的菜单
如果是右键菜单这类动态创建的控件,需在创建后立即配置暗色模式并触发更新:
HMENU hMenu = CreatePopupMenu(); // 添加菜单项逻辑... HWND hMenuWnd = GetMenuOwnerWindow(hMenu); AllowDarkModeForWindow(hMenuWnd, TRUE); SendMessage(hMenuWnd, WM_THEMECHANGED, 0, 0); TrackPopupMenu(hMenu, TPM_LEFTALIGN, x, y, 0, hMainWnd, NULL);
3. 完善暗色模式启用流程
现有代码中SetPreferredAppMode(ForceDark)是全局设置,还需确保主窗口和所有子窗口都完成暗色模式配置:
// 启用主窗口沉浸式暗色模式 enableImmersiveDarkMode(hMainWnd); // 允许主窗口使用暗色模式 AllowDarkModeForWindow(hMainWnd, TRUE);
内容的提问来源于stack exchange,提问作者user1050755
相关产品推荐
相关产品推荐

