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这个参数了