确定要使用的字符集
我的 delphi 2009 应用程序有一个使用 GNUGetText 的基本翻译系统。我使用了一些 win API 调用来准备字体。我一直认为它工作正常,直到最近,来自马耳他的某人遇到了我的应用程序在该领域失败的问题。我的应用程序在全球范围内使用。自从 d2009 使用 unicode 以来,其中一些代码可能已经过时。
为了让我的应用程序在所有区域设置中工作,所有这些真的是必要的吗?
TForm.Font.Charset
据我所知,我必须根据设置 TForm 实例的 Font.Charset到用户的区域设置。这是正确的吗?
TranslateCharsetInfo( ) win API 函数
delphi 2009 的 windows.pas 说:
function TranslateCharsetInfo(var lpSrc: DWORD; var lpCs: TCharsetInfo;
dwFlags: DWORD): BOOL;
delphi 5 的 windows.pas 说:
function TranslateCharsetInfo(var lpSrc: DWORD; var lpCs: TCharsetInfo;
dwFlags: DWORD): BOOL; stdcall;
来自微软的 MSDN:
BOOL TranslateCharsetInfo(
__inout DWORD FAR *lpSrc,
__out LPCHARSETINFO lpCs,
__in DWORD dwFlags
);
早在编写此代码时(早在 delphi 5 天),这个词就是 inport该函数的错误是不正确的,正确的方法是:
function TranslateCharsetInfo(lpSrc: Pointer; var lpCs: TCharsetInfo;
dwFlags: DWORD): BOOL; stdcall; external gdi32;
注意 d2009 windows.pas 文件副本不是 stdcall。我应该使用 TranslateCharsetInfo 的哪个声明?
除了代码
之外,本质上我一直在做以下事情:
var
Buffer : PChar;
iSize, iCodePage : integer;
rCharsetInfo: TCharsetInfo;
begin
// SysLocale.DefaultLCID = 1802
iSize := GetLocaleInfo(SysLocale.DefaultLCID, LOCALE_IDefaultAnsiCodePage,
nil, 0);
// size=14
GetMem(Buffer, iSize);
try
if GetLocaleInfo(SysLocale.DefaultLCID, LOCALE_IDefaultAnsiCodePage, Buffer,
iSize)=0 then
RaiseLastOSError;
// Buffer contains 0 so codepage = 0
iCodePage:=Result := StrToInt(string(Buffer));
finally
FreeMem(Buffer);
end;
// this function is not called according to MSDN's directions for
// TCI_SRCCODEPAGE and the call fails.
if not TranslateCharsetInfo(Pointer(iCodePage), rCharsetInfo,
TCI_SRCCODEPAGE) then
RaiseLastOSError;
// acts upon the form
Font.Charset:= rCharsetInfo.ciCharset;
end;
我只是对此了解不够......奇怪的是,几年前当我写这篇文章时,我被说服它正在工作正确。结果...未能检查 API 调用返回代码...
是否有更聪明的方法来完成这一切? RTL/VCL 不是自动完成大部分/所有这些工作吗?我的直觉告诉我,我在这方面工作得太努力了...
谢谢您的帮助!
my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta had a problem with my app failing precisely in this area. my app is used globally. some of this code may have become obsolete since d2009 uses unicode.
is all of this truly necessary in order for my app to work in all locales?
TForm.Font.Charset
it's been my understanding i must set the TForm instance's Font.Charset according to the user's locale. is this correct?
TranslateCharsetInfo( ) win API function
delphi 2009's windows.pas says:
function TranslateCharsetInfo(var lpSrc: DWORD; var lpCs: TCharsetInfo;
dwFlags: DWORD): BOOL;
delphi 5's windows.pas says:
function TranslateCharsetInfo(var lpSrc: DWORD; var lpCs: TCharsetInfo;
dwFlags: DWORD): BOOL; stdcall;
from microsoft's MSDN:
BOOL TranslateCharsetInfo(
__inout DWORD FAR *lpSrc,
__out LPCHARSETINFO lpCs,
__in DWORD dwFlags
);
back when this code was written (back in delphi 5 days), the word was the inport of the function was incorrect and the correct way was:
function TranslateCharsetInfo(lpSrc: Pointer; var lpCs: TCharsetInfo;
dwFlags: DWORD): BOOL; stdcall; external gdi32;
notice that the d2009 windows.pas file copy is not stdcall. which declaration of TranslateCharsetInfo should i be using?
The code
that aside, essentially i've been doing the following:
var
Buffer : PChar;
iSize, iCodePage : integer;
rCharsetInfo: TCharsetInfo;
begin
// SysLocale.DefaultLCID = 1802
iSize := GetLocaleInfo(SysLocale.DefaultLCID, LOCALE_IDefaultAnsiCodePage,
nil, 0);
// size=14
GetMem(Buffer, iSize);
try
if GetLocaleInfo(SysLocale.DefaultLCID, LOCALE_IDefaultAnsiCodePage, Buffer,
iSize)=0 then
RaiseLastOSError;
// Buffer contains 0 so codepage = 0
iCodePage:=Result := StrToInt(string(Buffer));
finally
FreeMem(Buffer);
end;
// this function is not called according to MSDN's directions for
// TCI_SRCCODEPAGE and the call fails.
if not TranslateCharsetInfo(Pointer(iCodePage), rCharsetInfo,
TCI_SRCCODEPAGE) then
RaiseLastOSError;
// acts upon the form
Font.Charset:= rCharsetInfo.ciCharset;
end;
i just don't know enough about this...strangely enough, years ago when i wrote this, i was persuaded that it was working correctly. the results of...failing to check API call return code...
isn't there a smarter way to do all this? doesn't the RTL/VCL do most/all of this automatically? my instincts tell me i'm working too hard on this...
thank you for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
实际上,我不确定 Delphi 2009,但 MSDN 说:
所以我的猜测是,您只需要删除您提到的所有代码,它就应该可以工作。
Actually, I'm not sure about Delphi 2009, but MSDN says:
So my guess is that you just need to remove all the code that you mentioned, and it should work.
不是这个问题的真正答案,而是关于 D2009+ 下此代码可能发生内存损坏的“小”注释。函数 GetLocaleInfo “MSDN:返回在区域设置数据缓冲区中检索到的字符数...”而不是 BYTES,因此在 D2009+ 下,您必须为每个字符分配 2 个字节。最好的方法是写入:
如果没有这个,您可能会导致不可预测的 AV(D2009+),函数 GetLocaleInfo 可能会覆盖您的内存,因为您分配的缓冲区太小。
另外,我不明白为什么您要尝试将字符集更改为用户区域设置一,我认为您应该将字符集更改为目标翻译(例如,您的程序设置为翻译为俄语,但在英语操作系统上运行,然后您需要将字符集更改为 RUSSIAN_CHARSET,而不是 ANSI_CHARSET)。在 D2009+ 下,我不确定是否需要这样做,但我可能是错的。
Not a really answer to this question, but 'small' note on possible memory corruption with this code under D2009+. Function GetLocaleInfo "MSDN: Returns the number of characters retrieved in the locale data buffer..." not BYTES, so under D2009+ you MUST allocate 2 bytes for each characters. Best way to do this is write:
Without this you can lead to unpredicted AVs (D2009+), function GetLocaleInfo can overwrite your memory, because you have allocated too small buffer.
Also I don't understant why you're trying change charset to user locale one, I think that you should change charset to your destination translation (like, your program is set to be translated to Russian language, but running on English OS, then you need change charset to RUSSIAN_CHARSET, not ANSI_CHARSET). And under D2009+ I not sure if this is needed, but I might be wrong.