确定要使用的字符集

发布于 2024-08-10 18:12:52 字数 2238 浏览 4 评论 0原文

我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千柳 2024-08-17 18:12:52

实际上,我不确定 Delphi 2009,但 MSDN 说:

请注意,DEFAULT_CHARSET 不是真正的字符集;相反,它是一个类似于 NULL 的常量,表示“以任何可用的字符集显示字符。”

所以我的猜测是,您只需要删除您提到的所有代码,它就应该可以工作。

Actually, I'm not sure about Delphi 2009, but MSDN says:

Note that DEFAULT_CHARSET is not a real charset; rather, it is a constant akin to NULL that means "show characters in whatever charsets are available."

So my guess is that you just need to remove all the code that you mentioned, and it should work.

尘曦 2024-08-17 18:12:52

不是这个问题的真正答案,而是关于 D2009+ 下此代码可能发生内存损坏的“小”注释。函数 GetLocaleInfo “MSDN:返回在区域设置数据缓冲区中检索到的字符数...”而不是 BYTES,因此在 D2009+ 下,您必须为每个字符分配 2 个字节。最好的方法是写入:

GetMem(Buffer, iSize * SizeOf(Char)); //This will be safe for all delphi versions

如果没有这个,您可能会导致不可预测的 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:

GetMem(Buffer, iSize * SizeOf(Char)); //This will be safe for all delphi versions

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文