·汉化新世纪 ·汉化新世纪论坛 ·百家争鸣 ·论坛集萃 ·汉化问答 ·软件介绍
文章首页 >> 汉化教学 >> VC汉化 >> VC类软件CPU-Z汉化版非标准字体修改全攻略    Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎

VC类软件CPU-Z汉化版非标准字体修改全攻略

作者: 炎之川 来源:汉化教学 时间:2003-07-30 点击:13496

本文最初贴于 2002.8.27,于 2002.8.29 做了修正,修正了之前错误的修改方法,请大家重新看一下。感谢大家的阅读、反馈及指点,同时感谢 Ronnier 兄指正错误及讲解。

 


CPU-Z 汉化版非标准字体修改全攻略
---- 兼谈使用 CreateFontA 函数创建的非标准字体的通用修改方法

在这篇文章中,我将以 CPU-Z 汉化版(txf 汉化)为例,简单讲解一下调用 CreateFontA 函数创建界面非标准字体的软件的修改方法。

下载了 txf 兄制作的 CPU-Z 1.14 汉化版,汉化的不错,但界面字体不甚美观,具体问题如图一所示,我们要做的就是让一切字体回复正常。

先用 eXescope 看了看汉化版的资源,界面字体设置是“宋体,10”,一般来说,我们在汉化时都是设置为“宋体,9”,“宋体,10”显示的字体较大,当然不好看,所以马上全部改成了“宋体,9”,不过保存后退出来测试一看,我们需要改的字体完全没有变化,ft!

看来是非标准字体在捣鬼了,打开 W32Dasm 反汇编主程序,等待反汇编完成,找到以下代码段(W32Dasm的使用不是本文所叙述目的,所以略去不讲,相关知识请查阅看雪学院的教学文章)

让我们先看调用 CreateFontA 函数创建字体得几个地方:
(如何判断每一段代码设置的究竟是那一部分的字体?实践是检验真理的唯一标准,所以……)

可以看到,软件使用了一种奇怪的字体“Courier”,使用16进制编辑软件搜索“Courier”并将其改为“宋体”后发现,软件的选项卡和所有非标准字体出现的地方,字体都变得非常非常非常小了!(如图2)看来确实是非标准字体在作怪。

-------------------------------------------------------------------------------
第一处调用 CreateFontA 函数创建字体:
这段代码控制“CPU”选项卡中的内容的字体,代码比较干净,除了字号,没有其他多余的设置。(我们就可以省事多了^^)

* Possible StringData Ref from Data Obj ->"Courier" //使用的字体,很奇怪吧:)

:004046A0 683C724300 push 0043723C
:004046A5 6A00 push 00000000
:004046A7 6A00 push 00000000
:004046A9 6A00 push 00000000
:004046AB 6A00 push 00000000
:004046AD 6A00 push 00000000 //改6A86,代码页设置为中国(PRC)
:004046AF 6A00 push 00000000
:004046B1 6A00 push 00000000
:004046B3 6A00 push 00000000
:004046B5 6A00 push 00000000
:004046B7 6A00 push 00000000
:004046B9 6A00 push 00000000
:004046BB 6A00 push 00000000
:004046BD 6AF8 push FFFFFFF8 //压入字体为10磅,改为 push FFFFFFF4,压入12磅字(9号字),显示正常

* Reference To: GDI32.CreateFontA, Ord:0036h

:004046BF FF1550004300 Call dword ptr [00430050]
:004046C5 50 push eax

修改之后,“CPU”选项卡字体显示的就非常正常了。

-------------------------------------------------------------------------------
这段代码是第二处调用 CreateFontA 函数创建字体的地方,其字体已经是宋体了,然后就实际修改效果来看,好像怎么改都没有用……所以可以直接跳过。

* Possible StringData Ref from Data Obj ->"宋体"

:0040553E 6844744300 push 00437444
:00405543 6A00 push 00000000
:00405545 6A00 push 00000000
:00405547 6A00 push 00000000
:00405549 6A00 push 00000000
:0040554B 6A00 push 00000000

* Reference To: GDI32.CreateFontA, Ord:0036h

:0040554D 8B2D50004300 mov ebp, dword ptr [00430050]
:00405553 6A00 push 00000000
:00405555 6A00 push 00000000
:00405557 6A01 push 00000001
:00405559 68BC020000 push 000002BC //粗体字,好像界面上没有?此处调用应该可以忽略。
:0040555E 6A00 push 00000000
:00405560 6A00 push 00000000
:00405562 6A00 push 00000000
:00405564 6A18 push 00000018
:00405566 FFD5 call ebp
:00405568 50 push eax
:00405569 8D8E54050000 lea ecx, dword ptr [esi+00000554]
:0040556F E84C6B0200 call 0042C0C0

-------------------------------------------------------------------------------
第三处调用 CreateFontA 函数创建字体:
这段结构控制的是“特性”、“缓存”“主板”这3个选项卡里面的具体项目的非标准字体:

* Possible StringData Ref from Data Obj ->"Courier" //此处已在上面的修改中,改为“宋体”

:00407C6D 683C724300 push 0043723C
:00407C72 6A00 push 00000000
:00407C74 6A00 push 00000000
:00407C76 6A00 push 00000000
:00407C78 6A00 push 00000000
:00407C7A 6A00 push 00000000 //改6A86,代码页设置为中国(PRC)
:00407C7C 6A00 push 00000000
:00407C7E 6A00 push 00000000
:00407C80 6A00 push 00000000
:00407C82 6A00 push 00000000
:00407C84 6A00 push 00000000
:00407C86 6A00 push 00000000
:00407C88 6A00 push 00000000
:00407C8A 6AF8 push FFFFFFF8 //改为 push FFFFFFF4,压入12磅字(9号字)

* Reference To: GDI32.CreateFontA, Ord:0036h

:00407C8C FF1550004300 Call dword ptr [00430050]
:00407C92 50 push eax

修改之后,“特性”、“缓存”“主板”这3个选项卡字体显示的就非常正常了。

-------------------------------------------------------------------------------
第四处,控制的是“内存”选项卡里面的具体项目的非标准字体:

* Possible StringData Ref from Data Obj ->"Courier"
|
:00407C6D 683C724300 push 0043723C
:00407C72 6A00 push 00000000
:00407C74 6A00 push 00000000
:00407C76 6A00 push 00000000
:00407C78 6A00 push 00000000
:00407C7A 6A00 push 00000000 //改6A86,代码页设置为中国(PRC)
:00407C7C 6A00 push 00000000
:00407C7E 6A00 push 00000000
:00407C80 6A00 push 00000000
:00407C82 6A00 push 00000000
:00407C84 6A00 push 00000000
:00407C86 6A00 push 00000000
:00407C88 6A00 push 00000000
:00407C8A 6AF8 push FFFFFFF8 //改为 push FFFFFFF4,压入12磅字(9号字)
* Reference To: GDI32.CreateFontA, Ord:0036h
|
:00407C8C FF1550004300 Call dword ptr [00430050]
:00407C92 50 push eax

修改之后,“内存”选项卡字体显示的就非常正常了。

 

注意,上面的修改,特别的地方是改了代码页,为什么要修改呢?因为我发现在 98 下查看初步修改后的文件,发现项目出现了中文和英文不能平齐显示的问题,改代码也可以解决这个问题。

注意,上面的修改,特别的地方是改了代码页,为什么要修改呢?因为我发现在 98 下查看初步修改后的文件,发现项目出现了中文和英文不能平齐显示的问题,改代码也可以解决这个问题。


注意:在本文最初贴出的时候,由于我的疏忽,搞错了代码页设置的具体参数位置,所以有一些朋友在按照我说的修改之后,出现了一些奇怪的问题……正确的修改位置应如上所示,在此对由于我的疏忽而给大家带来的误导说声抱歉。

另外,飞鹰兄指出:“把语系那里改为 push 86,也就是字节代码 6A86 是错误的,因为 86 大于 7F ,而所有大于 7F 的单字节数字被认为负数,所以这一句应该改成 push 00000086 ,也就是字节代码的 6886000000,这样改后在 Win9X 下应该就不会出现乱码。”。

经过查询梁利锋大师的文章,发现其实改为 push FFFFFF86 是没有错的,具体原因摘录如下:
“在 CreateFont 的参数中,语系是这样的:“BYTE lfCharSet”。也就是说,语系是一个单字节参数,在 Win32 环境中,压入堆栈的只能是四字节参数,所以“6a86”压入的是“FFFFFF86”,而“6886000000”压入的是“00000086”,但是对于这种单字节参数,系统的处理方法是简单的舍弃前三个字节,所剩的就是“86”了。”


以上改完,每个选项卡里面具体每一项的非标准字体就完全搞定了,但是选项卡名称的问题还是没有解决(如图三)。从反汇编的代码来看,我们应该修改的已经都改了,而程序中虽然存在 CreateFontIndirectA 函数,但经过检查,此函数没有明显的用途。那么为什么还没有完全解决问题呢?

最后无奈,用 Fontkey 载入程序,看看到底还有什么涉及到字体的地方。很意外的发现,居然还有一处漏网之鱼!

摘录如下:

CreateFontA(DWORD:FFFFFFF8,DWORD:00000000,DWORD:00000000,DWORD:00000000,DWORD:00000190,DWORD:00000000,DWORD:00000000,DWORD:00000000,DWORD:00000000,DWORD:00000000,DWORD:00000000,DWORD:00000000,DWORD:00000000,LPSTR:0043723C:"宋体")
CreateFontA returns: 6E0


可以从上面看出,这段字体设置也是使用 CreateFontA 函数设置的,但在 W32dasm 反汇编出来的代码中却没有这一段!看来这就是最后的问题所在了。

-------------------------------------------------------------------------------
经过 offset -> VA 转换,转到这段字体设置代码所在位置:
这一处控制的是“选项卡”的字体

* Possible StringData Ref from Data Obj ->"Courier" //又是这个字体!看来我们应该以字体名为关键字搜索:)
|
:00405621 683C724300 push 0043723C
:00405626 6A00 push 00000000
:00405628 6A00 push 00000000
:0040562A 6A00 push 00000000
:0040562C 8DBECC000000 lea edi, dword ptr [esi+000000CC]
:00405632 6A00 push 00000000
:00405634 6A00 push 00000000 //改6A86,代码页设置为中国(PRC)
:00405636 6A00 push 00000000
:00405638 6A00 push 00000000
:0040563A 6A00 push 00000000
:0040563C 6890010000 push 00000190
:00405641 6A00 push 00000000
:00405643 6A00 push 00000000
:00405645 6A00 push 00000000
:00405647 6AF8 push FFFFFFF8 //该死的字号设置!改为 push FFFFFFF4
:00405649 FFD5 call ebp
:0040564B 50 push eax
:0040564C 8BCF mov ecx, edi
:0040564E E86D6A0200 call 0042C0C0
:00405653 85FF test edi, edi
:00405655 7403 je 0040565A
:00405657 8B7F04 mov edi, dword ptr [edi+04]


从上面可以看出,或许是 W32Dasm 的问题,反汇编处理的代码不是那么完美,对于使用函数之处,可能无法正确的加上提示,所以在我们具体使用中,要注意灵活的应用:)


最后修改总结如下:

首先把对话框的字体改为“宋体,9”,然后用16进制编辑工具查找“”,改为“宋体”,多余的补00,然后搜索以下内容:

以下一共有3处,对应的是第 1、3、4 次 CreateFontA 字体调用。
查找:683C7243006A006A006A006A006A006A006A006A006A006A006A006A006AF8
修改:683C7243006A006A006A006A006A866A006A006A006A006A006A006A006AF4

最后一处无提示的 CreateFontA 调用
查找:683C7243006A006A006A008DBECC0000006A006A006A006A006A0068900100006A006A006A006AF8
修改:683C7243006A006A006A008DBECC0000006A006A866A006A006A0068900100006A006A006A006AF4

以上修改在 txf 兄汉化的 CPU-Z 1.14 中测试通过,估计也可以用于以后的版本。

经过上面的修改实例,我们可以终结出常规的调用 CreateFontA 函数创建界面非标准字体的软件的修改方法。

以一个拥有完整的 14 个参数的 CreateFontA 函数调用来讲,完美的“宋体,9”显示结构应该是这样的

* Possible StringData Ref from Data Obj ->"宋体"
|
:00XXXXXX 683C724300 push 0043723C
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push FFFFFF86 (语系为中文)
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000(默认显示字体风格)
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6A00 push 00000000
:00XXXXXX 6AF4 push FFFFFFF4(9号字)
* Reference To: GDI32.CreateFontA, Ord:0036h

其中 00XXXXXX 代表 VA 地址,依不同软件具体情况而定。

最后说说我的想法。虽然现在已经有了梁利锋大师制作的自动字体设置工具,可以自动修改非标准字体,但其使用的强制修改方法并不是万能的,而且很容易引起堆栈不平衡等等问题,给程序的运行安全带来了隐患。最重要的是,自动字体设置工具的成功率目前还不高,上面作为例子的 CPU-Z 就不能正确修改。虽然我也很懒,但还是不得不自己反汇编来研究。所以说,对于有一些水平的汉化人来说,稍微懂一些非标准字体的手动修改方法还是很有必要的。

最后特别感谢 Ronnier 兄对我的指点。


CreateFontA 函数结构相关英文资料(来源: MSDN)

With its 14 parameters, CreateFont is one of the more complex API functions out there:

Private Declare Function CreateFont Lib "gdi32" Alias _
"CreateFontA" (
ByVal font_height As Long,
ByVal font_width As Long,
ByVal escapement As Long,
ByVal orientation As Long,
ByVal weight As Long,
ByVal italic As Long,
ByVal underscore As Long,
ByVal strikeout As Long,
ByVal character_set As Long,
ByVal output_precision As Long,
ByVal clipping_precision As Long,
ByVal quality As Long,
ByVal pitch_and_family As Long,
ByVal face_name As String) As Long

You can set many of these parameters to 0 to tell the font mapper to use a reasonable default value. Here's a quick summary of the parameters:

font_height: This value is the height of the font in pixels. If this number is negative, the font mapper picks a font with characters with height approximately the absolute value of this number. If it's positive, the font mapper picks a font with a character cell height equal to the height value. The cell height includes some blank internal leading space (more about this later), so this makes the characters a little bit smaller.

font_width: This value is the width of the font in pixels. If zero, the font mapper uses a default width that matches the height. If the font isn't fixed width, this is the approximate average character width.

escapement: This is the font's rotation from the horizontal in degrees times 10 (as shown in Figure 2).

orientation: This should be the orientation of the characters, but Windows assumes orientation is the same as escapement, so it ignores orientation!

weight: This specifies the font's weight as a number between 0 and 900. The value 0 selects the default, 400 is normal, and 700 is bold.

italic: If this value is non-zero, the text is italicized.

underscore: If this value is non-zero, the text is underscored.

strikeout: If this value is non-zero, the text is stricken out.

character_set: This value specifies character sets such as Russian, Greek, and Arabic. Usually you should set this to ANSI_CHARSET (0).

output_precision: This parameter determines how closely the font selected by the font mapper must match the other parameters you specify. The value OUT_TT_ONLY_PRECIS (7) forces the font mapper to select a TrueType font even if it doesn't match the other parameters exactly. For our purposes, this is reasonable since CreateFont can only rotate TrueType fonts.

clipping_precision: This determines whether text that lies outside a window's clipping region is clipped by character, stroke, and so forth. When you draw rotated text, you should combine any other value you use here with the value CLIP_LH_ANGLES (16).

quality: This specifies draft or proof quality.

pitch_and_family: This parameter specifies the pitch (fixed or variable width) and font family used if the font you request is unavailable. If you specify a font that's likely to be present on the computer, like Times New Roman, you don't need to worry about this.

face_name: Thi is the font's name—for example, "Times New Roman" or "Courier New."

汉化新世纪 责任编辑: 乾 .:|:. 标签(Tag): CreateFontA VC 字体

·上一篇: 《汉化新世纪论坛精华》发布! ·下一篇: 我也来谈国旗修改问题

· 版权申明: 本文引自《汉化教学》,如有版权疑问请及时联系本站,以便本站处理。

· 转载申明: 本文引自《汉化教学》[ 作者: 炎之川],如需转载请直接联系原始作者,并请注明原始出处。

相关文章                                                                                发表评论 打印此文 关闭窗口

| 设为首页 | 加入收藏 | 联系我们 | 友情链接
Creative Commons License,创作共用协议(中文版)  署名 非商业性使用 禁止演绎
本站内容,除转载或版权特别申明的内容外,皆遵守 创造共用协议中文版之“署名-非商业性使用-禁止演绎 2.5 中国大陆”条款
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.5 China License.
本网站内容源自汉化新世纪论坛的摘录和汉化新世纪成员的原创文章。
凡汉化新世纪论坛的文字皆默认为汉化新世纪与原作者共同拥有并授权发布。
如对本站发布文章有所异议请来信告知,我们将及时删除。
凡商业摘录本站文字请先与我们联系,本站将保留非授权商业发布的追究权利。
凡非商业摘录本站文字请明显注明出处和原作者,并不得改动,凡改动必先征求原作者同意。
苏ICP备05002283号