`
datoplay
  • 浏览: 1615495 次
文章分类
社区版块
存档分类
最新评论

Delphi 字体修改一例

 
阅读更多
Delphi 字体修改一例


声明

个人可以自由转载本文,不过应保持原文的完整性,并通知我;商业转载先请和我联系。

本文没有任何明确或不明确地提示说本文完全正确,阅读和使用本文的内容是您自己的选择,本人不负任何责任。

如果您发现本文有错漏的地方,请您给我指出;如果有什么不理解的,请您给我提出。

意见、建议和提出的问题最好写在我的主页 http://llf.126.com 的留言版上。

前言

汉化人大宇在汉化 CTris2000 这个 Delphi 程序的时候,修改了所有 RCData 中的字体设置,但仍然有一个窗体的字体很难看,我帮他做了修改,在这里就以它为例说一下 Delphi 程序字体字号的修改。

本来,我以为要详细的说才能说清,不过现在看来,也未必,所以在这里还是简单的说一下算了。

Delphi 程序的字体

关于 Delphi 程序的字体,以我想大概有三种情况:

一、RCData 格式。这种格式的字体字号的问题有很多工具,诸如 eXeScope 、ResHacker 等工具都可以非常方便的修改,而且这也是 Delphi 程序中的字体设置使用最多的方法,而且大多数 Delphi 程序都只使用这一种方式,而其修改方法相对成熟的多,所以我不讨论这种方式。

二、SDK 格式。有些 Delphi 程序为了追求最小的独立可执行文件尺寸,不使用 Delphi 缺省的 VCL 运行库,而是自行使用 SDK 的编程方式,不过这种程序不多,如果有,个头也很小,一般是几K、十几K的居多,如果在这些程序里出现字体不协调的问题,可以使用和修改 C 字体字号相同的方法修改。

三、VCL 内部格式。VCL 是 Delphi 使用的函数库,其内部很可能使用了不是我们所希望的“宋体,9”的窗体,不过我想来想去,也只有类似 VB 函数的 InputBox 有这种可能,也就是 CTris2000 中要求输入姓名的那个窗体,故我们要谈的就是这种方式的程序的字体的修改,而且,几乎可以确定的固定在 InputBox 上,当然,即使是这一种情况,也比较类似 C 字体的修改,而不是 VB 。(我不知道 Delphi 中相同功能的函数的函数名,所以暂称其为 InputBox)。

修改过程

我修改的过程比较繁琐,所以在这里剔除复杂的部分,简单的说。

首先,使用 W32dasm 反汇编汉化后的 CTris2000.exe ,存盘,打开 CTris2000.alf 文件,查找 CreateFont ,发现只有 CreateFontIndirectA ,而没有 CreateFontA ,这真是一个烦人的开始。继续查找,发现 CreateFontIndirectA 被三个地方调用,地址分别是 4124EC 、420460 和 42A7F3 。

运行 Trw2000 ,调入 CTris2000.exe ,然后键入“bpx 4124EC”、“bpx 420460” 和 “bpx 42A7F3”设置断点,按“F5”运行,中断时键入“dd *esp”查看堆栈的栈顶指针所指的地址的内容,发现大多数情况此地址的开头都是“FFFFFFF4”,也就是“-12”,是正常的,不过有一次,它是“FFFFFFF5”,也就是“-11”,在它下面一点,我们见到了这种字体的名称“MS Sans Serif”。

用 ResHacker 检查 CTris2000.exe ,发现并不是所有的“MS Sans Serif,8”都被改成了“宋体,9”,所以首先把这些没有改成“宋体,9”的项都改成“宋体,9”,存盘。

用 UEdit 打开 CTris2000.exe ,查找“MS Sans Serif”,只有一个,在 0x5b0b8 处,为了验证,把这个“MS Sans Serif”改成“System”,运行程序,发现那个输入窗体的字体确实如我们所想的变成“宋体,12”了。

0x5b0b8 在数据段,所以,数据基偏移 = 基地址 + 数据RVA - 数据Offset = 400000h + 5c000h - 5ae00 = 401200h ,所以,0x5b0b8 的在代码中为 401200h + 5b0b8 = 45C2B8h 。在 CTris2000.alf 查找“0045C2B8”,没找到,那么,查找“0045C2B”吧,找到几处,如“0045C2B7”、“0045C2B6”和“0045C2B0”,很是奇怪。

运行 Trw2000 ,调入 CTris2000.exe ,像上面一样设断点,运行到有问题的 CreateFontA 的时候,键入“dd 0045C2B0”,看看是什么?原来是“FFFFFFF5”!好吧,把“0045C2B0”当作突破口。

打开 CTris2000.alf ,查找“0045C2B0”,发现两个地方,代码如下:

* Referenced by a CALL at Address:
|:0041979B   
|
:00419604 53                      push ebx
:00419605 56                      push esi
:00419606 57                      push edi
:00419607 6A48                    push 00000048
:00419609 A1D0E54500              mov eax, dword ptr [0045E5D0]
:0041960E 50                      push eax
:0041960F 6A08                    push 00000008

* Reference To: kernel32.MulDiv, Ord:0000h
                                  |
:00419611 E836BEFEFF              Call 0040544C
:00419616 F7D8                    neg eax
:00419618 A3B0C24500              mov dword ptr [0045C2B0], eax
:0041961D A13CD64500              mov eax, dword ptr [0045D63C]
:00419622 80780800                cmp byte ptr [eax+08], 00
:00419626 743A                    je 00419662
:00419628 E893FFFFFF              call 004195C0
:0041962D 8BD8                    mov ebx, eax
:0041962F 8BC3                    mov eax, ebx
:00419631 2C80                    sub al, 80
:00419633 752D                    jne 00419662
:00419635 BE68964100              mov esi, 00419668
:0041963A BFB7C24500              mov edi, 0045C2B7
:0041963F B904000000              mov ecx, 00000004
:00419644 F3                      repz
:00419645 A5                      movsd
:00419646 6A48                    push 00000048
:00419648 A1D0E54500              mov eax, dword ptr [0045E5D0]
:0041964D 50                      push eax
:0041964E 6A09                    push 00000009

* Reference To: kernel32.MulDiv, Ord:0000h
                                  |
:00419650 E8F7BDFEFF              Call 0040544C
:00419655 F7D8                    neg eax
:00419657 A3B0C24500              mov dword ptr [0045C2B0], eax
:0041965C 881DB6C24500            mov byte ptr [0045C2B6], bl

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00419626(C), :00419633(C)
|
:00419662 5F                      pop edi
:00419663 5E                      pop esi
:00419664 5B                      pop ebx
:00419665 C3                      ret

不知道大家是否能大概看懂上面的代码,不过它和我在《C 程序字号的修改》里摘抄的 MSDN 里建议的设置字号的方式是基本一样的:

	nHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);

我们可以看到,“0041960F”处的“6A08”压入的就是磅值,我们需要的是 9 磅的字体,所以把“6A08”改成“6A09”就可以了。代码基偏移 = 基地址 + 代码RVA - 代码Offset = 400000h + 1000h - 400h = 400c00h ,41960fh - 400c00h = 18a0fh ,也就是说“6a08”在 0x18a0f 处。

所以,最后的修改是这样的:把 0x5b0b8 处的 "MS Sans Serif" 改成 "宋体";把 0x18a0f 处的 6a08 改成 6a09 。

虽然我已经简化了过程,不过好像还是很麻烦,那么有没有什么简单的方法呢?有的。

一、如果实在不会这样的修改方法,也不要留着,把“MS Sans Serif”改成“System”是一种简单有效的方法,遗憾的是字体显得比较大。

二、先把“MS Sans Serif”改成“宋体”,然后用 W32dasm 反编译汉化后的程序并存盘后,用 EmEditor 打开 *.alf 文件,按“Ctrl+F”,出现查找对话框,选择“使用表达式”,在要查找的文本中输入“push 00000008/n/n* Reference To: kernel32.MulDiv,”,找到的不会很多,把“08”修改成“09”试一试,直到得到正确的结果。

需要注意,第二种方法只适用于 Delphi 程序的 InputBox 的字体修改,而第一种方法适用于所有程序。另外,我因为没有见到其它类似的 Delphi 程序,也不能肯定第二种方法就是对的,如果各位有见到,不妨一试。

分享到:
评论

相关推荐

    Delphi编程技巧.rar

    Delphi自定义消息应用一例 自 定 义 快 速 报 表 的 打 印 预 览 窗 口 如何把文件删除到回收站中 在Delphi与C 之间实现函数与对象共享 编 译 错 误 信 息 DELPHI AND THE INTERNET by Charlie Calvert [1...

    Delphi处理文字颜色/字体/字号的实例代码.rar

    一款简单的Delphi字符操作例子,本例主要是处理文字的颜色,字体类型和字号大小,另外还实现了对文字的禁止修改。欢迎大家下载学习。

    Delphi5开发人员指南

    8.9 实际创建一种字体 224 8.9.1 这个程序是如何工作的 224 8.9.2 显示字体的有关信息 230 8.10 总结 233 第9章 动态链接库 234 9.1 究竟什么是DLL 234 9.2 静态链接与动态链接 235 9.3 为什么要使用DLL 236 9.3.1 ...

    java源码包---java 源码 大量 实例

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    JAVA上百实例源码以及开源项目

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包2

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包3

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包4

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    JAVA上百实例源码以及开源项目源代码

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,...

    vc++ 开发实例源码包

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

    网管教程 从入门到精通软件篇.txt

     下例将在硬盘上添加一个 20 MB 的分区:  diskpart /add Device HardDisk0 20  Fixboot  向系统分区写入新的分区引导扇区。只有在使用故障恢复控制台时,才能使用 fixboot 命令。  fixboot [drive]  ...

    vc++ 应用源码包_1

    Visual.C++编程技巧精选500例源代码 内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与...

    vc++ 应用源码包_2

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

    winxp系统结构5课(注册表)->1认识注册表

    winxp系统结构5课(注册表)->1认识注册表 作者:netcicala 来源:www.netcicala.com 发布时间:2007-7-4 19:56:01 减小字体 增大字体 一.计算机原理2课(硬件)-> 二.计算机脚本技术25课(DOS命令/...

    vc++ 应用源码包_3

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

    vc++ 应用源码包_6

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

    vc++ 应用源码包_5

    代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...

Global site tag (gtag.js) - Google Analytics