Delphi:TRichEdit 非默认非 Unicode 系统语言中的文本作为字符串 (ANSI)

标签 delphi delphi-7 richedit input-language

设置如下:

  1. 创建一个新的 Delphi 7 应用程序,其中包含 TRichEdit 控件。我们在这里讨论的是非 Unicode 应用程序。
  2. 在 Windows 的“区域和语言选项”中安装新的输入语言,该语言的编码与 default Language for non-Unicode programs 的编码不同。 - 例如希腊语。
  3. 在应用程序中添加一个按钮,并在其 OnClick 处理程序中添加 Button1.Caption := RichEdit1.Text;,并设置其 Font.Charset 为您刚刚安装的输入语言的字符集(GREEK_CHARSET,如果我们坚持使用此示例)。
  4. 运行应用程序,切换到新的(希腊语)输入语言,在 RichEdit 中键入几个字母,然后按按钮 - 按钮的标题现在改为 ???? 符号希腊字符。

  5. 现在,如果您将非 Unicode 程序的默认语言设置为希腊语(需要重新启动 Windows),此问题就会消失 - 希腊字符将正确显示。将您的非 Unicode 程序的默认语言设置回原来的状态,问题又出现了。

所以我猜测 TRichEdit 在内部使用 Unicode,因为更改其 Font.Charset 值永远不会改变任何内容 - RichEdit 正确接受任何已安装的输入语言,并且如果您安装了两种使用不同字符集的不同非拉丁语言(例如希腊语/GREEK_CHARSET/和俄语/RUSSIAN_CHARSET/)它将接受它们,而不更改其 Font.Charset。

我还猜测,当您获取 TRichEdit 的 .Text (或 .Lines[i])值时,它会将其内部 Unicode 文本转换为 ANSI,基于 Windws 非 Unicode 程序的默认语言

此外,将 .Text 值分配给 WideString 或 UnicodeString 也无法正常工作(文本再次位于 ???? 中,而不是正确的字符),这不仅仅是当您将其分配给字符串(AnsiString)时。

所以问题是:

我希望能够根据我选择的字符集(而不是系统的非 Unicode 程序的默认语言)将 RichEdit 的文本正确转换为字符串 (ANSI)。我怎样才能做到这一点?我更喜欢一个不涉及第三方组件的解决方案,但是,当然,如果不可能的话 - 任何事情都可以。

谢谢!

P.S.:切换到 Delphi 2009 或更高版本不是一个可接受的解决方案。

最佳答案

发送底层富编辑窗口 EM_GETTEXTEX信息。您通过 GETTEXTEX指定代码页的结构。

因此,类似这样的操作会将文本提取为 UTF-16 编码的 WideString:

function GetRichEditText(RichEdit: TRichEdit): WideString;
var
  GetTextLengthEx: TGetTextLengthEx;
  GetTextEx: TGetTextEx;
  Len: Integer;
begin
  GetTextLengthEx.flags := GTL_DEFAULT;
  GetTextLengthEx.codepage := 1200;
  Len := SendMessage(RichEdit.Handle, EM_GETTEXTLENGTHEX, 
    WPARAM(@GetTextLengthEx), 0);
  if Len=E_INVALIDARG then
    raise Exception.Create('EM_GETTEXTLENGTHEX failed');
  SetLength(Result, Len);
  if Len=0 then
    exit;
  GetTextEx.cb := (Length(Result)+1)*SizeOf(WideChar);
  GetTextEx.flags := GTL_DEFAULT;
  GetTextEx.codepage := 1200;
  GetTextEx.lpDefaultChar := nil;
  GetTextEx.lpUsedDefChar := nil;
  SendMessage(RichEdit.Handle, EM_GETTEXTEX, WPARAM(@GetTextEx), 
    LPARAM(PWideChar(Result)));
end;

然后您可以将该 UTF-16 字符串转换为您喜欢的任何代码页。如果您想直接将其提取到特定的代码页中,请按如下操作:

function GetRichEditText(RichEdit: TRichEdit; AnsiCodePage: UINT): AnsiString;
var
  GetTextLengthEx: TGetTextLengthEx;
  GetTextEx: TGetTextEx;
  Len: Integer;
begin
  GetTextLengthEx.flags := GTL_DEFAULT;
  GetTextLengthEx.codepage := AnsiCodePage;
  Len := SendMessage(RichEdit.Handle, EM_GETTEXTLENGTHEX, 
    WPARAM(@GetTextLengthEx), 0);
  if Len=E_INVALIDARG then
    raise Exception.Create('EM_GETTEXTLENGTHEX failed');
  SetLength(Result, Len);
  if Len=0 then
    exit;
  GetTextEx.cb := (Length(Result)+1)*SizeOf(AnsiChar);
  GetTextEx.flags := GTL_DEFAULT;
  GetTextEx.codepage := AnsiCodePage;
  GetTextEx.lpDefaultChar := nil;
  GetTextEx.lpUsedDefChar := nil;
  SendMessage(RichEdit.Handle, EM_GETTEXTEX, WPARAM(@GetTextEx), 
    LPARAM(PWideChar(Result)));
end;

关于Delphi:TRichEdit 非默认非 Unicode 系统语言中的文本作为字符串 (ANSI),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15741774/

相关文章:

delphi - 表单设计器保存和加载

delphi - 如何使用 OmniXML 删除子节点?

delphi - 为什么 EM_SETTEXTMODE 不起作用?

delphi - tListBox 使用来自其他 ListBox 的自动完成导航

delphi - 我怎样才能在德尔福中做到这一点?

c++ - 在单字符行上调用时由 CRichEditCtrl::GetLine() 添加的虚假 '\r'?

c++ - 如何消除 RICHEDIT 控件的 MessageBeep?

delphi - 如何在 Delphi 中将 "unit only"项添加到 "New"菜单/对象存储库

c - 缺少 kernel32.dll 的依赖项