views:

217

answers:

2

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!

+1  A: 

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.

Lars D
thank you for your comment Lars D! i'll ask someone to try my app in such a locale.
X-Ray
A: 

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.

kibab
good point. thank you.
X-Ray