在手动修改了无障碍文本缩放的注册表项后,如何让Windows重新生效?
我想写一个程序,可以通过我的MOBA鼠标上的按钮触发,在Windows 11的“文本大小”设置(设置应用 > 无障碍 > 文本大小 > 页面顶部的滑块)之间来回切换,切到100% 和我偏好的数值。我通过大量Google搜索,找到了需要修改的注册表项(HKEY_CURRENT_USER\SOFTWARE\Microsoft\Accessibility\TextScaleFactor),以及如何用C++修改它(据我所知,这似乎是唯一拥有所有必需API的语言),但实现起来仍然不太对劲。
具体来说,通过设置应用更改该设置时,Windows会显示一个“请稍等”屏幕几秒钟,然后所有打开的窗口都会重新绘制以适应更改后的文本大小;但如果用我目前写的程序手动编辑注册表项,以上都不会发生,大多数窗口也无法识别这个变化,只有Microsoft Edge会重新绘制,但只有在我切换回它(例如用Alt-Tab)时才会重新绘制。
我读到需要在 [这个Reddit评论] 上广播一个 WM_SETTINGCHANGE 消息,并在它链接的Stack Overflow帖子中也广播同样的消息,我也尝试过,但似乎没有起到任何作用。我还在运行程序后尝试重新启动Windows资源管理器,但也没什么帮助。我还看到 [这个论坛帖子] 提到可能还需要关注其他一些注册表项,我做了测试,发现只有那份清单中与字体相关的条目(当然还有 TextScaleFactor 那条)在通过设置应用修改后才真正改变,因此也可以尝试修改这些注册表键值,但我已经被这件事搞得筋疲力尽(对C++经验也不丰富),只想尽快把事情做完。
我是不是做错了什么?甚至有一个更好的办法来实现我想做的事吗?
这是我的代码(使用Visual Studio 2022创建并测试):
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <malloc.h>
#include <iostream>
// ToggleTextScale.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Constants
constexpr auto PREFERRED_TEXT_SCALE = 175; // Should be replaced with a command line arg.
constexpr auto DEFAULT_TEXT_SCALE = 100;
int main()
{
// Declaring a bunch of variables that I'm gonna need later.
LONG lResult;
DWORD dwRet;
DWORD cbData;
HKEY hKey;
DWORD_PTR broadcastResult;
LPBYTE textScaleFactor_ptr = (LPBYTE)malloc(sizeof REG_DWORD); // <- This is the important one!
// Check for if the ptr is null so Visual Studio doesn't yell at me about it.
if (textScaleFactor_ptr) {
// Open the Reg key that has the value I need.
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Accessibility"), 0, KEY_READ | KEY_SET_VALUE, &hKey);
// Get the value.
cbData = 4;
dwRet = RegQueryValueEx(hKey, TEXT("TextScaleFactor"), NULL, NULL, textScaleFactor_ptr, &cbData);
// If the text scaling is 100%, change to preferred value.
// Otherwise, change to 100%.
if ((int)*textScaleFactor_ptr == 100) {
DWORD preferredVal = PREFERRED_TEXT_SCALE;
lResult = RegSetValueEx(hKey, TEXT("TextScaleFactor"), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&preferredVal), sizeof(preferredVal));
}
else {
DWORD defaultVal = DEFAULT_TEXT_SCALE;
lResult = RegSetValueEx(hKey, TEXT("TextScaleFactor"), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&defaultVal), sizeof(defaultVal));
}
// Broadcast a message so Windows knows something changed and can do its thing.
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, (LPARAM)TEXT("TextScaleFactor"), 0, 1000, &broadcastResult);
// Close the registry key.
RegCloseKey(hKey);
// Free the important pointer to clean up.
free(textScaleFactor_ptr);
// Final return.
return ERROR_SUCCESS;
}
else {
// Clean up if the important pointer didn't work.
free(textScaleFactor_ptr);
return ERROR_NOT_ENOUGH_MEMORY;
}
}
解决方案
SetTextScaleFactor() 修改注册表项,然后调用一个未公开的函数来发送通知:
RtlPublishWnfStateData(WNF_EOA_UISETTINGS_CHANGED, 0, 0, 0, 0)
你也可以直接调用这个函数,但更简单的方式还是调用受支持的API。