Widestring to string conversion in Delphi 7
my app is a non-unicode app written in Delphi 7.
I'd like to convert unicode strings to ANSI with this function :
function convertU(ws : widestring) : string;
begin
result := string(ws);
end;
I use also this code to set the right codepage to convert.
initialization
SetThreadLocale(GetSystemDefaultLCID);
GetFormatSettings;
It works great in the VCL main thread but not in a TThread, where I get some questions marks '?' as result of function convertU .
Why not in a TThread ?
Calling SetThreadLocale()
inside of an initialization
block has no effect on TThread
. If you want to set a thread's locale, you have to call SetThreadLocale()
inside of the TThread.Execute()
method.
A better option is to not rely on SetThreadLocale()
at all. Do your own conversion by calling WideCharToMultiByte()
directly so you can specify the particular Ansi codepage to convert to.
AFAIK SetThreadLocale
does not change the current system Code Page, so won't affect the widestring
to ansistring
conversion in Delphi 7, which rely on GetACP
API call, ie the system Code Page.
The system Code Page is set eg in Windows Seven in the Control Panel, then Region Languages / Administrative tab / Code Page for non Unicode Applications. This needs a system restart.
Delphi 7 uses this system Code Page, supplying 0 to all conversion API calls. So AFAIR SetThreadLocale
won't affect the widestring
to ansistring
conversion in Delphi 7. It will change the locale (eg date/time and currency formatting), not the code page used by the system for its Ansi <-> Unicode conversion.
Newer versions of Delphi have a SetMultiByteConversionCodePage()
function, able to set the code page to be used for all AnsiString
handling.
But API calls (ie all ....A()
functions in Windows.pas which are mapped by ...()
in Delphi 7) will use this system code page. So you will have to call the ...W()
wide API after a conversion to Unicode if you want to handle another code page. That is, the Delphi 7 VCL will work only with the system code page, not the value specified by SetThreadLocale
.
Under Delphi 7, my advice is:
WideString
everywhere, and specific "Wide" API calls - there are several set of components for Delphi 7 which handle WideString
; MyString = type AnsiString
(this is what we do in mORMot, by defining a custom RawUTF8
type for internal UTF-8 process). This is much better handled with Delphi 2009 and up, since you can specify a code page to every AnsiString
type, and properly handle conversion to/from Unicode, for API calls or VCL process.