Delphi7中的宽字符串到字符串的转换

Delphi7中的宽字符串到字符串的转换,delphi,unicode,localization,delphi-7,ansi,Delphi,Unicode,Localization,Delphi 7,Ansi,我的应用程序是用Delphi7编写的非unicode应用程序 我想使用此函数将unicode字符串转换为ANSI: function convertU(ws : widestring) : string; begin result := string(ws); end; 我还使用此代码设置要转换的正确代码页 initialization SetThreadLocale(GetSystemDefaultLCID); GetFormatSettings; 它在VCL主线程中工作得很好

我的应用程序是用Delphi7编写的非unicode应用程序

我想使用此函数将unicode字符串转换为ANSI:

function convertU(ws : widestring) : string;
begin
  result := string(ws);
end;
我还使用此代码设置要转换的正确代码页

initialization
  SetThreadLocale(GetSystemDefaultLCID);
  GetFormatSettings;
它在VCL主线程中工作得很好,但在TThread中却不行, 在这里,我得到了一些问题标记“?”,这是函数convertU的结果


为什么不在TThread中?

初始化
块中调用
SetThreadLocale()
TThread
没有影响。如果要设置线程的区域设置,必须在
TThread.Execute()
方法内部调用
SetThreadLocale()


更好的选择是根本不依赖
SetThreadLocale()
。通过直接调用
WideCharToMultiByte()
进行您自己的转换,这样您就可以指定要转换到的特定Ansi代码页。

AFAIK
SetThreadLocale
不会更改当前的系统代码页,因此不会影响Delphi 7中的
widestring
转换,它依赖于
GetACP
API调用,即系统代码页

例如,在Windows 7中,在控制面板中设置系统代码页,然后在非Unicode应用程序中设置区域语言/管理选项卡/代码页。这需要重新启动系统

Delphi7使用此系统代码页,为所有转换API调用提供0。因此,在Delphi7中,AFAIR
SetThreadLocale
不会影响
widestring
ansisting
的转换。它将更改区域设置(例如日期/时间和货币格式),而不是系统用于Ansi Unicode转换的代码页

较新版本的Delphi有一个
setMultibyteConversionDepage()
函数,可以设置用于所有
ansisting
处理的代码页

但是API调用(即Windows.pas中所有由Delphi 7中的
..()
映射的
..A()
函数)将使用此系统代码页。因此,如果要处理另一个代码页,则必须在转换为Unicode后调用
…W()
宽API。也就是说,Delphi 7 VCL将仅与系统代码页一起工作,而不是由
SetThreadLocale
指定的值

根据Delphi 7,我的建议是:

  • 在任何地方使用
    WideString
    和特定的“Wide”API调用-Delphi 7有多组组件处理
    WideString
  • 使用您自己的类型,使用专用的字符集,但在使用VCL/RTL或“Ansi”API调用之前,您需要进行显式转换-例如
    MyString=type AnsiString
    (这是我们在mORMot中所做的,通过为内部UTF-8进程定义自定义
    RawUTF8
    类型)

这在Delphi 2009及更高版本中处理得更好,因为您可以为每个
解析类型指定一个代码页,并正确处理API调用或VCL进程与Unicode之间的转换;一个简单的
stringVar:=wideStringVar将起作用。第二,问题是并非所有WideChar都可以直接转换为AnsiString;有些字体的宽度不止一个字符,有些字体的字符值在AnsiChar中无法表示,有些字体不包含所有可能的Unicode值。如果您看到的是
,这意味着您正在显示它们,这可能是第三个问题-线程不应在不使用
同步化的情况下访问GUI控件。因为您没有发布显示代码,所以很难说是否是这样。问题是:为什么在TThread中使用时会出现问号?我重复一遍:如果您看到
,则显示文本。您提供了零代码或有关如何显示它的信息。我使用Debugger查看返回值是否为系统默认LCID的TThread感知?如果您是应用程序中所有代码的作者,则显式调用WideChartMultiByte是可行的选项。如果包含第三方代码,则区域设置的线程范围设置可能是最佳折衷方案。是。谢谢我现在混合使用这两种方法:WideCharToMultiByte和SetThreadLocale(),因为我首先开始使用WideCharToMultiByte,但我认为我将删除对该函数的调用,并且只对每个线程使用SetThreadLocale。AFAIK
SetThreadLocale
不会更改当前的系统代码页,因此不会影响Delphi7中widestring到ansistring的转换,它依赖于
GetACP
API调用。我只想处理默认的系统代码页。我注意到,对于UnicodeAnsi转换,使用的代码页是默认用户LCID,而不是默认系统LCID,这是一个问题。