Chrome从版本41开始强制启用directwrite ui,ui界面包括主菜单、地址栏、书签栏等不再使用点阵宋体渲染,如果系统是windows classical主题,这些地方的字体会严重发虚。
通过在chrome的快捷方式中指定–disable-directwrite-for-ui启动参数可以解决这个问题。但如果是其他程序打开浏览器的第一个实例,就没法应用这个参数。同理,基于chrome的atom、visual studio code等electron应用,通常都是通过关联文件而不是快捷方式启动,所以依然会悲剧,观感非常难受,如下图。

今天决定彻底干掉这个问题。方法很容易想到,通过劫持一个dll进行注入,然后改掉GetCommandLine返回的结果。研究chrome的依赖dll后决定选择DWrite.dll进行劫持,就像游戏外挂都喜欢用d3d9.dll注入一样,优点是它们都是只需要转发一个函数即可。d3d9是Direct3DCreate9,DWrite是DWriteCreateFactory。
代码:
#include <Windows.h>
static void* pDWriteCreateFactory;
extern "C" __declspec(dllexport) __declspec(naked) void DWriteCreateFactory()
{
__asm jmp dword ptr [pDWriteCreateFactory];
}
BOOL WINAPI DllMain(HMODULE, UINT uReason, LPVOID)
{
if (uReason == DLL_PROCESS_ATTACH)
{
WCHAR path[MAX_PATH];
GetSystemDirectoryW(path, sizeof(path));
lstrcatW(path, L"\\DWrite.dll");
HMODULE hModule = LoadLibraryW(path);
pDWriteCreateFactory = GetProcAddress(hModule, "DWriteCreateFactory");
static WCHAR commandLine[4096];
lstrcpyW(commandLine, GetCommandLineW());
lstrcatW(commandLine, L" --disable-directwrite-for-ui");
BYTE* code = (BYTE*)&GetCommandLineW;
DWORD protect = PAGE_EXECUTE_READWRITE;
VirtualProtect(code, 6, protect, &protect);
code[0] = 0xB8;
*(WCHAR**)&code[1] = commandLine;
code[5] = 0xC3;
VirtualProtect(code, 6, protect, &protect);
}
return TRUE;
}
下载:
用法:
放置到chrome内核所在的目录即可。Chrome浏览器放到chrome.dll的目录(目录名是版本号的,非chrome.exe目录),vscode等electron应用放置到exe所在目录。
效果:

现在不能这样玩了,内核直接不支持-disable-directwrite-for-ui这个参数了