我的问题是如何更改字体处理才能在 Windows 7 下正常工作。我确信我已经对以前有效但不再有效的内容做出了假设。但我什至不知道从哪里开始寻找!我祈祷有人可以帮忙!以下是我理解的详细信息(我还在 Microsoft Windows 开发人员论坛上发布了这个问题,但他们没有回答):
是的,我已经落伍了(哎呀,我仍然用纯 C 语言编写 WIN32 代码!) 我编写了一个已有 10 年历史的 DLL,它在窗口的客户区域中模仿了更旧的 DOS 屏幕 I/O 库。不用说,它只允许使用固定宽度的字体。当一些使用DLL的程序被转移到Windows 7时,当使用固定宽度的TRUE TYPE字体时,会出现奇怪的闪烁(位图字体仍然可以正常工作)。我们已经追踪到这个问题一个字符写成ExtTextOut
比应有的更宽。我用三种不同的方式检查了测量结果(通过使用GetTextExtentPoint32
在 132 个字符的字符串上除以 132,通过调用GetTextMetrics
甚至通过使用GetCharABCWidths
对于所有 256 个字符),并且他们都同意字体具有相同的宽度。但ExtTextOut
正在渲染背景矩形比字体宽度宽一或两个像素。或者,它开始在参数中给出的位置左侧渲染一两个像素的背景[我这样称呼它:ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL )
.] 请记住,此 EXACT 代码在 Windows 2000、Windows XP 和 Windows 7 上的位图字体下完美运行,但在 Windows 7 下它不再与固定宽度的 True Type 字体一起正常运行。
对于那些不明白我需要做什么的人:尝试想象在一张方格纸上的每个方块上写一个字符。每个方块都使用相同的字体,但可能具有不同的前景色和/或背景色。我用TA_TOP|TA_LEFT
文本对齐方式,因为它是最简单的,任何一致应用的对齐方式都应该适用于固定宽度的字体。
我看到的是 ExtTextOut 发出的背景矩形比我在RECT *
范围。由于我提供的矩形是根据报告的字体大小创建的,因此这种情况永远不会发生——并且在 Windows XP 及更早版本上从未发生过,并且 Windows 7 下的位图(即 .FON)字体也不会发生这种情况,任何一个。但在 Windows 7 下,固定宽度的 TrueType 字体总是会发生这种情况。这是在 Windows 2000、Windows XP 和 Windows 7(32 和 64)上运行的完全相同的可执行文件。虽然我很想简单地说 Windows 7 有一个错误,我更倾向于相信我对 Windows 下的字体处理所做的一些基本假设不再正确(在为 Windows 编写软件 20 年之后)。
但我不知道如何或在哪里发现那可能是什么!请帮助我!
---修正---
对于任何感兴趣的人,我已经设法解决我认为是错误的问题 - 直到我找到相反的文档。我的解决方法包括对我的库进行两项更改:
- 使用从返回的大小
GetTextExtentPoint32()
改为“X”
的数据来自TEXTMETRICS
.
- 包括
ETO_CLIPPING
全部标记ExtTextOut()
calls.
以前,我使用的是tmHeight+tmExternalLeading
连续文本行顶部之间的像素数,如记录的那样。我发现 size.cy 值从GetTextExtentPoint32(
)不一样,而且似乎更准确。我发现的最糟糕的例子是 OCRB true type 字体。这是我在调试器中看到的我创建的 OCRB 字体(使用系统字体选择对话框):
ocrbtm.tmHeight = 11
ocrbtm.tmExternalLeading = 7
ocrbsize.cy = 11
因此,由于某种我尚未发现的原因,Windows 忽略了为 OCRB 字体定义的外部主值。使用大小值而不是 TM 会产生漂亮、整洁、紧凑的文本,这正是我想要的。
The ETO_CLIPPING
标志对我来说不是必需的,因为我将矩形设置为单个字符的尺寸并使用ETO_OPAQUE
填充背景(并覆盖以前的单元格内容。)但是如果没有剪切标志,单个字符比大小、文本度量或 ABC 宽度指示的宽度要宽——至少,基于所有到目前为止我找到的文档。
我相信高度问题已经存在很长一段时间了,但直到我们在 Windows 7 下运行我们的软件之前,其余的都是不必要的。我将其附加到我的问题中,看看是否有人可以解释我明显不明白的内容。
-- 修正案2 --
1:我能找到的所有文档都表明tmHeight+tmExternalLeading
应该产生单行间距的文本。时期。但这并不总是正确的,我找不到说明 Windows 如何确定有时返回的不同值的文档GetTextExtentPoint32()
.
2:Win7下(也许是Vista)ExtTextOut
开始填充比应有的多一点的背景(通过在右侧添加几个额外的像素),但前提是选择了 true type 字体。即使矩形是这样的,它也会这样做double字符的预期大小(在两个维度上)。DPI/缩放可能是一个因素,但由于我的系统设置为 100%,Windows 似乎在 1:1 缩放因子方面遇到了麻烦,这似乎是一个因素是一个错误。事实上,它只影响真实类型而不影响位图(.FON)字体,这一事实似乎也排除了缩放(除非有is缩放系统中的错误),因为 Windows 应该尝试缩放所有文本,而不仅仅是其中的一部分。此外,“自定义 DPI 设置”对话框中还有一个灰色(但已选中)的设置“使用 Windows XP 样式 DPI 缩放”。最后,整个问题可能是由于我在 Windows Classic 主题下运行而不是 Aero 或其他 Win7 本机主题之一造成的。
-- 修正案3 --
简单地调用 SetProcessDPIAware() 对我遇到的问题没有任何影响。由于我的问题存在于 100% DPI 设置(比例 1:1),如果我的问题is与DPI相关,那么我一定发现了DPI虚拟化的一个bug,因为微软是这样描述该功能的:
此功能的工作原理是向应用程序提供“虚拟化”系统指标和 UI 元素,就好像它以 96 DPI 运行一样。然后,应用程序渲染到 96 DPI 的离屏表面,桌面 Windows 管理器会缩放生成的应用程序窗口以匹配 DPI 设置。
我的所有设置都显示我处于 100% 缩放状态,并且在自定义设置框中查看清楚地显示这意味着 96 DPI。因此,如果从 96 DPI 到 96 DPI 的 DPI 虚拟化对我的固定宽度 true type 字体不起作用,那么 Windows 就有问题了,对吧?或者是否需要调用(或停止调用?)某些函数才能让 DPI 虚拟器正常工作?
我仍然不相信所谓的缩放问题实际上与我最初认为的字体大小有很大关系。这是因为问题体现在背景矩形被充满ExtTextOut()
而不是发出的文本字符。当字体为 True Type 时,背景矩形会放大一点。我现在还验证了无论使用 Windows Classic 主题还是标准 Windows Aero 主题都会出现此问题。现在构建一个简化的示例,以便其他人可以进行实验。
——修正案4——
我创建了一个最小的演示程序,它展示了我所看到的内容(以及我正在做的事情)。Visual Studio 2010 项目/源代码可以从http://www.svalli.com/files/fwtt.7z http://www.svalli.com/files/fwtt.7z-- 我故意不包含可执行文件,因为我不想冒传播恶意软件的风险。该程序让您选择一种固定宽度的字体,然后将两个 5x5 字符网格写入客户区,其中一个是使用GetTextExtentPoint32
尺寸和一个使用TEXTMETRIC
Microsoft 记录的大小。网格采用黑白棋盘图案,最后在中心写入黄底红字以显示重叠效果(您可能需要缩放实用程序才能清楚地看到它。)该程序还在下方绘制一个以 5 X 开头的字符串网格,从相同的左偏移开始,用作我放置单个字符的方法的比较(我匹配字符串。)菜单允许在ExtTextOut
以及其他字体的选择。还有一个命令行选项dpiaware
(区分大小写)导致程序调用SetProcessDPIAware()
当它启动时,以便也可以评估该调用的效果。
从创建这个我了解到ExtTextOut
正在填充正确的背景矩形,但使用不透明背景渲染的字符可能比应有的宽度更宽,甚至可能不从何处开始ExtTextOut
被告知开始画画!我说“应该”是因为我最终得到的字符间距与我得到的字符间距相匹配ExtTextOut
渲染整个字符串。重叠显然可能在给定矩形的一侧或两侧,例如,OCRB 在字符单元的左侧和右侧都添加了一个额外的像素,而我检查过的其他 true type 字体则在右侧添加了两个像素边缘。
我真的想以“正确”的方式做到这一点,但我找不到任何文档来显示我做错了什么或遗漏了什么。好吧,我可能在 100% 以外的比例下缺少 DPI Aware 的一些东西,但除此之外,我只是感到困惑。
——修正案5——
稍微不那么困惑了......问题是由 ClearType 引起的。关闭 ClearType 会使所有字体再次工作。在 XP 下打开 ClearType 会导致同样的问题。显然,ClearType 可以默默地(直到有人告诉我如何检测它)将字符水平拉伸几个像素,以便为它添加的阴影像素腾出空间,以平滑事物。
剪辑是解决这个问题的唯一方法吗?
-- 修正案 6 --
上面我的剪辑问题的部分答案:当创建新字体时,我现在执行以下操作(以伪代码):
CreateFontIndirect
SelectFont
GetTextMetrics
if( (tmPitchAndFamily & TMPF_TRUETYPE) && Win6.x or above )
if( SystemParametersInfo( SPI_GETCLEARTYPE ) )
lfQuality = NONANTIALIASED_QUALITY
DeleteObject( font )
CreateFontIndirect
不启用裁剪此功能almost始终适用于我正在使用的字体大小,尽管我发现一些字体仍然在字符单元格的右侧(或左侧)呈现额外的像素。幸运的是,这些似乎是在互联网上找到的免费字体,因此它们的整体质量可能低于专业字体铸造厂的标准。
如果有人能找到更好的答案,我真的,REALLY喜欢听!在那之前,我认为这已经是最好的了。感谢您阅读本文!