Delphi 7 - 为什么 Windows 7 在运行时更改字符编码?
我有一个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 相关。
I have a delphi 7 form:
and my code:
when I run this form in Windows 7, I see:
In design time, form had polish letters in first label, but it doesn't have them in runtime. It looks ok on Vista or Windows XP. When I set caption of second label in code, everything works fine and characters are properly encoded.
First 5 codes of top label on Windows 7: 65 97 69 101 83
First 5 codes of top label on Windows Vista/XP: 165 185 202 234 140
First 5 codes of bottom label on every system: 165 185 202 234 140
Windows 7 changes encoding, why? My system settings seem to be ok. I have proper language set for non-unicode applications in control panel.
EDIT
This problem is not only related with labels on forms, but also with FastReport (where switching to EASTERN_CHARSET resolves the problem) or with accesing Microsoft Excel through COM interface.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我确实在 Win XP 中重现了 Delphi 2010 中的行为。
在这种情况下,Label1.Caption 到 AnsiString 的转换是通过 WideCharToMultiByte(Windows API)。
该 API 有以下注释:
因此,我最好的猜测是,行为上的差异来自于以下事实:您所拥有的 Windows 7 版本的活动代码页与您的 vista/XP 工作站上的活动代码页不同。
我仍然需要找到如何获取系统上的活动代码页...我最好的猜测是它是在控制面板的区域设置中定义的。但我还需要验证这一点...
I did reproduce the behavior in Delphi 2010 in win XP.
In this situation, the conversion of Label1.Caption to AnsiString is done through WideCharToMultiByte (Windows API).
The API has the following note :
So, my best guess is that the difference in behavior come from the fact that the version of Windows 7 you have has a different active CodePage than on your vista/XP stations.
I still have to find how to get the active codepage on a system... My best guess is that it is defined in the regional settings in the control panel. But I still need to verify this...
您在 TWriter.WriteString 和 TWriter.ReadString 方法中遇到了我认为的“错误”。 Delphi 在内部使用这两种方法将 TLabel.Caption 从设计时的实际活动对象移至 DFM 文件,然后在运行时移回活动对象。
如果您查看上述两个例程的代码,您会注意到(我认为很震惊)进入流的实际内容是使用操作系统的默认代码页转换为 Unicode 的!只要开发计算机上使用的代码页与测试计算机上使用的代码页完全匹配就可以了,而且它们可能不匹配,这很可能就是您收到错误的原因。请注意,您为表单上的标题设置的 EASTEUROPEAN_CHARSET 绝对没有任何值,因为 TWriter.WriteString 方法不知道它!
我在 QC 上收到了关于这个问题的错误报告,它已经存在很多年了......他们可能认为这是“设计使然”,但我不认为这是一个很好的设计。
我推荐的解决方案是快速切换到 Delphi 2010。我是罗马尼亚的一名 Delphi 开发人员,我在此类问题上遇到了很多很多问题,但现在这一切都成为过去了,因为 Delphi 2010 是UNICODE 所以我不再需要担心代码页转换。
如果您无法切换到 Delphi 2010,您可能需要“破解”Classes.pas 文件并更改 TReader.ReadString 例程以始终使用您的代码页(而不是系统默认值)进行转换。
You ran into what I consider a "bug" in the TWriter.WriteString and TWriter.ReadString methods. Those two methods are internally used by Delphi to move your TLabel.Caption from the actual live object at design time into the DFM file and then back into the live object at run time.
If you look at the code for the mentioned two routines, you'll notice (in shock I assume) that the actual stuff that goes into the stream is converted to Unicode using the operating system's default code page! That's fine and dandy as long as the code page used on the development machine exactly matches the code page used on the test machine, and they probably don't match, and that's most likely why you get the error. Please note the EASTEUROPEAN_CHARSET you're setting for the Caption on the form has absolutely no value, because the TWriter.WriteString method has no idea about it!
I've got an bug report on this issue on QC, it's been there for many years... They probably think it's "by design", but I don't think it's an very good design.
The solution I'd recomand is a fast switch to Delphi 2010. I'm an Delphi developer in Romania, and I've had lots and lots of problem with this kind of stuff, but now it's all in the past because Delphi 2010 is UNICODE so I no longer need to worry about code page conversions.
If you can't switch to Delphi 2010 you might want to "hack" the Classes.pas file and change the TReader.ReadString routine to always do the conversion using YOUR code page, not the system default.
这个问题的答案解决了我的问题:
GetThreadLocale 返回的值与 GetUserDefaultLCID 不同?
一解决方案:
第二:
两种解决方案都效果很好,并且应用程序问题消失了。
Answers to this question solve my problem:
GetThreadLocale returns different value than GetUserDefaultLCID?
One solution:
and second:
Both solutions work great and problem with application disappears.
检查标签的 Font.Charset 属性。虽然我不知道它是如何更改的(它是为某个向导预先创建的吗?) - 它可能具有与系统不同的区域设置。
Check the Font.Charset property of the label. While I don't know how it got changed (was it pre-created for some wizard?) - it might have a different locale from the system one.