Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,14 @@ extern "system" { /* ... */ }
- `AppsUseLightTheme` - 控制应用主题
- `SystemUsesLightTheme` - 控制系统主题

然后发送系统广播消息通知主题变更:
- `WM_SETTINGCHANGE`
- `WM_THEMECHANGED` (注:目前在代码中已临时注释)
- `WM_SYSCOLORCHANGE` (注:目前在代码中已临时注释)

**说明**:目前实测发现 `WM_THEMECHANGED` 与 `WM_SYSCOLORCHANGE` 的广播在本工具场景下非必须。为了便于排查并避免潜在副作用,这两处广播已在 standard 与 mini 两处分别临时注释(保留为注释以便将来恢复)。`WM_SETTINGCHANGE` 广播仍保留,用于通知主题字符串变化。若需要恢复,请在对应文件中移除注释(变更提交:暂时注释 WM_THEMECHANGED 与 WM_SYSCOLORCHANGE 广播,PR 已合并)。
修改注册表后,广播以下消息通知所有应用主题变更:
- `WM_SETTINGCHANGE`(lParam 为字符串 `"ImmersiveColorSet"`)
- `WM_THEMECHANGED`
- `WM_SYSCOLORCHANGE`

**说明**:`"ImmersiveColorSet"` 是 `WM_SETTINGCHANGE` 的 **lParam 通知标识字符串**(类似 `"Environment"` 表示环境变量变更),与注册表路径无关,`Personalize` 键下**默认不存在**同名注册表值。
该字符串是 Windows 系统本身在切换主题时广播的标准通知,WinUI 3 应用(如 Windows 11 任务管理器)通过监听此 `WM_SETTINGCHANGE` 消息来感知主题变化,并结合读取 `AppsUseLightTheme`/`SystemUsesLightTheme` 注册表值来确定新主题。
技术出处:[microsoft/terminal `WindowEmperor.cpp`](https://github.com/microsoft/terminal/blob/c334f91f80dfe4c882e60be466622a7a51ca5bb9/src/cascadia/WindowsTerminal/WindowEmperor.cpp#L1008)、[AutoDarkMode `DwmRefreshHandler.cs`](https://github.com/AutoDarkMode/Windows-Auto-Night-Mode/blob/59e24dc2fe65f220e112f862fd6efc6d02740555/AutoDarkModeSvc/Handlers/DwmRefreshHandler.cs)。

## 系统要求

Expand Down
38 changes: 18 additions & 20 deletions mini/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,26 +160,24 @@ pub extern "system" fn mainCRTStartup() -> ! {
200,
ptr::null_mut(),
);

// 目前实测发现 WM_THEMECHANGED 和 WM_SYSCOLORCHANGE 的广播非必须,暂时注释掉(调试用)
// winapi::SendMessageTimeoutW(
// winapi::HWND_BROADCAST,
// winapi::WM_THEMECHANGED,
// 0,
// 0,
// winapi::SMTO_ABORTIFHUNG,
// 200,
// ptr::null_mut(),
// );
// winapi::SendMessageTimeoutW(
// winapi::HWND_BROADCAST,
// winapi::WM_SYSCOLORCHANGE,
// 0,
// 0,
// winapi::SMTO_ABORTIFHUNG,
// 200,
// ptr::null_mut(),
// );
winapi::SendMessageTimeoutW(
winapi::HWND_BROADCAST,
winapi::WM_THEMECHANGED,
0,
0,
winapi::SMTO_ABORTIFHUNG,
200,
ptr::null_mut(),
);
winapi::SendMessageTimeoutW(
winapi::HWND_BROADCAST,
winapi::WM_SYSCOLORCHANGE,
0,
0,
winapi::SMTO_ABORTIFHUNG,
200,
ptr::null_mut(),
);

winapi::ExitProcess(0);
}
Expand Down
7 changes: 2 additions & 5 deletions standard/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,13 @@ unsafe fn broadcast(msg: u32, lparam: isize) {
unsafe fn refresh_theme() {
let theme_str = to_utf16("ImmersiveColorSet");
broadcast(WM_SETTINGCHANGE, theme_str.as_ptr() as isize);

// 目前实测发现 WM_THEMECHANGED 和 WM_SYSCOLORCHANGE 的广播非必须,暂时注释掉(调试用)
// broadcast(WM_THEMECHANGED, 0);
// broadcast(WM_SYSCOLORCHANGE, 0);
broadcast(WM_THEMECHANGED, 0);
broadcast(WM_SYSCOLORCHANGE, 0);
}

fn main() {
unsafe {
let current = read_reg_dword(HKEY_CURRENT_USER, PATH, "AppsUseLightTheme").unwrap_or(1);
// let new_value = if current == 0 { 1 } else { 0 };
let new_value = 1 - current; // 更简洁的切换逻辑

write_reg_dword(HKEY_CURRENT_USER, PATH, "AppsUseLightTheme", new_value);
Expand Down