duangsuse::Echo
717 subscribers
4.26K photos
130 videos
583 files
6.48K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
李鹏日记.pdf
1.3 MB
#Book PDF 版本
duangsuse::Echo
李鹏日记.odt
duangsuse 的评论:
总之,是做了最大限度的克制。
和现在香港的情况有点像,都是分不清黑白。
很可惜,类似的事情还是来了第二次。
李鹏日记.odt
461 KB
带链接的更新版本 rev1
duangsuse::Echo
duangsuse 的评论: 总之,是做了最大限度的克制。 和现在香港的情况有点像,都是分不清黑白。 很可惜,类似的事情还是来了第二次。
出现这种情况的时候,总会有那么一小部分别有用心的人,带着邪恶的目的扰乱正常的请愿活动,导致暴乱
李鹏日记.pdf
1.3 MB
rev1 的 PDF
duangsuse::Echo
李鹏日记.odt
#tech 这几天比较咸鱼什么都没干,有喜欢的朋友试着写一点简单模板化的自然语言处理程序(无须词库和机器学习猜词),试着统计一下句式、时间、人名地名什么的,多提取点信息出来。
这几天感觉自己的编程能力(尤其是形象思维『可视化...』我感觉我几乎什么都想不起来了)和敲键盘的速度都有很大下降... 不稳定
可能很咸鱼吧
#CXX #Windows https://github.com/ysc3839/FontMod

早在几个月前开发被用于修复 Telegaram 在 Windows 上默认 SimSun 字体问题的 TgFont(现在已经改名 FontMod)
现在经过重构后,不仅功能更新,其代码质量也得到了一定的提升(唯一有选项的一个就是继续模块化拆分编译单元)

和某个朋友讨论的时候提到了这个项目,现在来说一下其实现的一些(大体的)概览
——

Mod 和新开发程序自然是不同的啦,一般来说都是『修改的补丁』,所以 FontMod 必然使用某种方式将自己的更改附加到 Telegram Desktop 上

Windows 上这一般使用 DLL 注入实现,不过注入的 DLL (动态链接库,可以包含 DLLMain 符号)要干什么呢? (hook win32 API)
FontMod 注入之后是先解析配置文件,然后使用自己的 MyCreateFontIndirectW 代替 Windows 自己动态链接上的 pfnCreateFontIndirectW

HMODULE hGdi32 = GetModuleHandleW(L"gdi32.dll");
auto pfnCreateFontIndirectW = GetProcAddress(hGdi32, "CreateFontIndirectW");

现在我将从几个文件简要说明一下实现,以及一些实现细节...

—- 项目管理部分
yaml-cpp/ 这是 git submodule 依赖,用于解析 YAML 配置文件
.gitmodules
.gitattributes — 保持 *.rc UTF16 BOM 和 CRLF(必要)
.gitignore
CMakeLists.txt
project(FontMod)
link_external_msproject(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}.vcxproj)
add_subdirectory("yaml-cpp")
add_dependencies(${PROJECT_NAME} "yaml-cpp")
FontMod. vcxproj (.filters)
Resources.rc — 自动生成项目发布资源
FontMod.yaml — 默认配置文件

LICENCE
README.*.md
—- 头文件接口定义
resources.h — 自动生成
DefConfigFile.hpp — 默认配置文件字符串
winmm.hpp — Windows 的老音频设备设备接口
至今不清楚这个是为什么 include

—- 实现代码
FontMod.hpp
Utils.hpp

====
功能:接管系统的字体加载创建过程,利用 YAML 配置提供的信息按照用户要求进行不同的修改替换

.... 其实要这么说的话,应该挑重点,因为内容很无聊

1. 我是 DLL,利用普通的动态链接替换方法(实现一个动态链接库的所有接口,然后在 DllMain 里加自己的逻辑)
用户需要将 FontMod 替换版的 winmm.dll 替换原版 DLL,然后在 font/ 下建立字体资源,使用 FontMod.yaml 定义配置即可

2. 读取用户的配置文件使用
void loadSettings(hmod, fileMame, errMsg, fixGSOFont, userGSOFont, debug)
YAML::Load, FindKey, ->IsMap, ->IsScalar
可配置的部分包括 fonts: replace
fonts : { <replaced>: (replace | name): <replacement> poverride }
poverrride = (ulongs) size, width, weight, (bools) italic, underLine, strikeOut, (ul2byte) charSet, outPrecision, clipPreision, quality, pitchAndFamily
同样的东西,GSOFont 再来一遍。
(bool)fixGSOFont: // USE_NCM_FONT
map 的话和 fonts: 的就没有区别了
3. 加载字体使用
上面的配置加载完(全局变量)之后,即可开始工作,不过配置是在 hook 替换的程序运行过程中使用的
auto pfnCreateFontIndirectW = GetProcAddress(hGdi32, "CreateFontIndirectW");
if (pfnCreateFontIndirectW) { InlineHook(pfnCreateFontIndirectW, MyCreateFontIndirectW, &addrCreateFontIndirectW); }
if (fixGSOFont != DISABLED) {
auto pfnGetStockObject = GetProcAddress(hGdi32, "GetStockObject");
if (pfnGetStockObject) { InlineHook(pfnGetStockObject, MyGetStockObject, &addrGetStockObject); }}
4. void InlineHook(ptr old, ptr new, ptr_mut_ptr save); 子程序是这么做的:
1. 利用 VirtualProtect 修改程序分页权限,给目标地址加写入权限 (EXECUTE_READWRITE),改完后复原
2. 初始化一个代表 jmp 机器指令的 struct,算一下从 new 跳转到 [old 的偏移量 (new - old)加上 5],作为它的参数 IPoff
3. 同样的,saved 的偏移量也是 old+5
4. 复原地址空间(此时 Hook 已经写入),返回。
常量 5 是怎么来的,具体可汇编这个程序
mov edi, edi
push ebp
mov ebp, esp
看看字节长度是多少
0x00000000    6689ff mov di, di
0x00000003 6655 push bp
0x00000005 6689e5 mov bp, sp

它的意思是跳到程序逻辑起始开始执行,frame 的 winding 就不需要了(这三条指令是不需要子程序相关信息的)
修改的程序使用 inline assembly __declspec(naked) HGDIOBJ WINAPI CallOrigGetStockObject(int i)
也是通过此法调用
很辣鸡,可是我果然还是变得 很慢了吧...
simple.c
604 B
#C 随便到网上找了个方法算内联汇编大小
这程序等价么 #CXX
duangsuse::Echo
这程序等价么 #CXX
我始终搞不明白

1. 为什么有些程序要使用这么复杂的控制结构和不明所以的算术,如果只是比较 (size <= actualsize) 为什么写成 (actualsize + 1 > size), 而且还 do while 重复两遍,还在 if 里面重复,用 while 不就可以了?或者也可以 continue; break; 啊?
2. 为什么有些部分写得和一些 Perl 脚本一样,完全没有 C++ 的感觉,甚至冗余一大片

3. 提升建议:可以使用函数式编程 std::function 抽提一些难以抽提的逻辑,比如 stol, stoul 都可以被填成一个模板,FindNode 也可以弄 FindSclarChild, FindMapChild
我真的不明白,为什么就一定要写这么多此 it->second, 它在理论上有必要的优雅性吗?如果在编写的时候是这么写的... 总之不好看吧 (附注: it 是封装的 KvPair)
这是原版的,一堆模板看得简直眼花
沒毛病
考虑到 GSOFont 配置的结构体和普通 replace 的不一样,就算了,可是如此之长的配置加载... 这些代码重复多一遍都是很淡疼的,何况扫描键值的部分别无二致,只是后期操作有变化,就不能使用 Lambda 抽提吗?
还有个简单一点的习惯问题,就是这么多 if 嵌套看的时候是要死人的啊!(何况我一看,这些 if 除了条件执行外没有任何的 else...) 利用控制流预先 return / continue / break 了更好