Delphi 7 - 为什么Windows 7会在运行时更改字符编码?

6
我有一个Delphi 7表单:Form。我的代码是:Code。当我在Windows 7上运行此表单时,我看到的是:Windows7Form。在设计时,表单中的第一个标签有波兰字母,但在运行时却没有了。在Vista或Windows XP上看起来很好。当我在代码中设置第二个标签的标题时,一切正常,字符被正确编码。在Windows 7上,顶部标签的前5个代码是:65 97 69 101 83,在Windows Vista / XP上,它们是:165 185 202 234 140。底部标签在每个系统上的前5个代码都是:165 185 202 234 140。为什么Windows 7会更改编码?我的系统设置似乎没问题。在控制面板中,我为非Unicode应用程序设置了适当的语言。编辑:这个问题不仅与表单上的标签有关,还与FastReport(切换到EASTERN_CHARSET可以解决问题)或通过COM接口访问Microsoft Excel有关。

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

2
我在Windows 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在字符串转换方面采用了另一种方法的问题,但我该如何解决? - LukLed
1
尝试在您的应用程序中调用GetThreadLocale,以确保在进一步调查之前返回相同的值... - Ken Bourassa
好主意。我明天会去做。 - LukLed

2
你遇到了我认为是TWriter.WriteString和TWriter.ReadString方法中的一个“错误”。这两个方法在Delphi内部用于将你的TLabel.Caption从设计时的实际对象移动到DFM文件,然后再在运行时将其移回实际对象。
如果你查看上述两个例程的代码,你会惊讶地发现,实际进入流中的内容是使用操作系统的默认代码页转换为Unicode的!只要开发机上使用的代码页与测试机上使用的代码页完全匹配,那么就没问题,但它们很可能不匹配,这很可能是你遇到错误的原因。请注意,你在表单上设置的EASTEASTEUROPEAN_CHARSET对Caption没有任何价值,因为TWriter.WriteString方法不知道它!
我在QC上有关于这个问题的错误报告,它已经存在多年了...他们可能认为这是“按设计”,但我认为这不是一个非常好的设计。
我建议的解决方案是快速切换到Delphi 2010。我是罗马尼亚的Delphi开发人员,曾经遇到过很多这样的问题,但现在都已经成为过去,因为Delphi 2010是UNICODE,所以我不再需要担心代码页转换。
如果你无法切换到Delphi 2010,你可能需要“黑客”Classes.pas文件,并更改TReader.ReadString例程,以始终使用你的代码页进行转换,而不是系统默认值。

很高兴知道,但这个问题只与Windows 7有关,我已经找到了解决方案。切换到Delphi 2010会非常复杂。我的应用程序大量使用JVCL 2和其他旧组件,并且有大约1000个表单。Delphi 2010正在等待更多的空闲时间。 - LukLed

1

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

GetThreadLocale返回值与GetUserDefaultLCID不同?

其中一个解决方案:

我们发现的奇怪的事情是,通过控制面板切换到不同的区域设置,然后再切换回新西兰就可以解决这个问题。我很想知道是否相同的解决方法也适用于你,以验证我们是否看到了相同的现象。

第二个:

initialization
  SetThreadLocale(LOCALE_USER_DEFAULT);
  GetFormatSettings;

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


0

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


表单的 Font.Charset 属性设置为 DEFAULT_CHARSET,标签的 ParentFont 属性设置为 true。 - LukLed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接