【问题标题】:Delphi 7 - Why does Windows 7 change encoding of characters in runtime?Delphi 7 - 为什么 Windows 7 在运行时更改字符编码?
【发布时间】:2011-02-02 19:49:46
【问题描述】:

我有一个 delphi 7 表单:

和我的代码:

当我在 Windows 7 中运行此表单时,我看到:

在设计时,表单的第一个标签中有波兰字母,但在运行时没有。它在 Vista 或 Windows XP 上看起来不错。当我在代码中设置第二个标签的标题时,一切正常并且字符被正确编码。

Windows 7 上顶部标签的前 5 个代码:65 97 69 101 83

Windows Vista/XP 上顶部标签的前 5 个代码:165 185 202 234 140

每个系统底部标签的前 5 个代码:165 185 202 234 140

Windows 7 更改编码,为什么?我的系统设置似乎没问题。我在控制面板中为非 unicode 应用程序设置了正确的语言。

编辑

此问题不仅与表单上的标签有关,还与 FastReport(切换到 EASTERN_CHARSET 解决问题)或通过 COM 接口访问 Microsoft Excel 相关。

【问题讨论】:

  • 我不熟悉 Delphi,但表单设计器是否允许指定与默认代码页不同的编码(即 Windows-1250)?这是什么版本的Delphi? IIRC Unicode 支持最近才添加...
  • @0xA3 这是 Delphi 7,它不是 unicode 应用程序,但我在区域设置中为非 unicode 应用程序设置了波兰语。这就是为什么 Label2 显示正确,但第一个仍然不起作用的原因。
  • 您是否检查过 DFM 中如何定义 Label1 和 Label2? Label1.caption 是如何保存在 DFM 中的?
  • @Ken Bourassa DFM 商店 #260#261#280#281#346#347#262#263#323#324。这看起来像 Unicode。字母匹配unicode码,所以dfm没有错。
  • 在 XP 或 Vista 兼容模式下运行应用是否有效(右键单击 .exe,属性 -> 兼容性)?

标签: delphi encoding windows-7 delphi-7


【解决方案1】:

检查标签的 Font.Charset 属性。虽然我不知道它是如何改变的(它是为某些向导预先创建的吗?) - 它可能与系统的语言环境不同。

【讨论】:

  • Form 的 Font.Charset 设置为 DEFAULT_CHARSET,标签的 ParentFont 设置为 true。
【解决方案2】:

我确实在 win XP 中重现了 Delphi 2010 中的行为。

procedure Button1Click(Sender : TObject);
begin
  ShowMessage(AnsiString(Label1.Caption));
end;

在这种情况下,Label1.Caption 到 AnsiString 的转换是通过WideCharToMultiByte (Windows API) 完成的。

API 有以下注释:

ANSI 代码页可以不同 在不同的计算机上,或者可以 换了一台电脑,领先 到数据损坏。对于最 一致的结果,应用 应使用 Unicode,例如 UTF-8 或 UTF-16,而不是特定代码 页,除非遗留标准或数据 格式阻止使用 Unicode。如果 无法使用 Unicode, 应用程序应该标记数据 具有适当编码的流 协议允许时命名。 HTML 和 XML 文件允许标记,但文本 文件没有。

所以,我最好的猜测是,行为上的差异来自这样一个事实,即您拥有的 Windows 7 版本具有与您的 vista/XP 站不同的活动代码页。

我仍然需要找到如何在系统上获取活动代码页...我最好的猜测是它是在控制面板的区域设置中定义的。但我仍然需要验证这一点......

【讨论】:

  • 控制面板设置好像没问题。我确信这是 Windows 7 有另一种字符串转换方法的问题,但我该如何解决呢?
  • 尝试在各种系统上从您的应用程序调用 GetThreadLocale,以确保在我们进一步调查之前返回相同的值...
  • 好主意。我明天会这样做。
【解决方案3】:

这个问题的答案解决了我的问题:

GetThreadLocale returns different value than GetUserDefaultLCID?

一种解决方案:

我们发现奇怪的是,通过控制面板切换到不同的区域设置,然后切换回 NZ 解决了这个问题。我很想知道相同的解决方法是否可以为您解决它,只是为了验证我们是否看到了相同的现象。

第二个:

initialization
  SetThreadLocale(LOCALE_USER_DEFAULT);
  GetFormatSettings;

两种解决方案都很好,应用程序的问题消失了。

【讨论】:

    【解决方案4】:

    您在 TWriter.WriteString 和 TWriter.ReadString 方法中遇到了我认为的“错误”。 Delphi 在内部使用这两种方法将您的 TLabel.Caption 从设计时的实际活动对象移动到 DFM 文件中,然后在运行时移回活动对象。

    如果您查看上述两个例程的代码,您会注意到(我假设很震惊)进入流的实际内容是使用操作系统的默认代码页转换为 Unicode 的!只要开发机器上使用的代码页与测试机器上使用的代码页完全匹配,那很好,而且它们可能不匹配,这很可能是您收到错误的原因。请注意,您为表单上的 Caption 设置的 EASTEUROPEAN_CHARSET 绝对没有任何价值,因为 TWriter.WriteString 方法对此一无所知!

    我在 QC 上有一个关于这个问题的错误报告,它已经存在很多年了......他们可能认为这是“设计使然”,但我不认为这是一个很好的设计。

    我推荐的解决方案是快速切换到 Delphi 2010。我是罗马尼亚的一名 Delphi 开发人员,我遇到过很多此类问题,但现在这一切都已成为过去,因为Delphi 2010 是 UNICODE,所以我不再需要担心代码页转换。

    如果您无法切换到 Delphi 2010,您可能想要“破解”Classes.pas 文件并更改 TReader.ReadString 例程以始终使用您的代码页而不是系统默认值进行转换。

    【讨论】:

    • 很高兴知道,但这个问题只与 Windows 7 有关,我已经找到了解决方案。切换到 Delphi 2010 将非常复杂。我的应用程序大量使用 JVCL 2 和其他旧组件,并且有大约 1000 个表单。 Delphi 2010 等待更多空闲时间。
    猜你喜欢
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 2012-06-02
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    相关资源
    最近更新 更多