Delphi - 在程序中存储 WideStrings

发布于 2024-11-29 14:53:29 字数 131 浏览 1 评论 0原文

过去我使用 INI 文件来存储 unicode 文本,但现在我需要在可执行文件中存储 unicode 文本。我怎样才能做到这一点?

我想存储这些字母:

āčēūīšķļņž

In the past I used INI-Files to store unicode text, but now I need to store unicode text in the executable. How can I achieve this?

I want to store these letters:

āčēūīšķļņž

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(5

篱下浅笙歌 2024-12-06 14:53:29

如果你想保存 Unicode INI 文件,那么你可以尝试以下代码。这些文件以 UTF8 编码 保存。

您也可以看一下这个 Unicode 库,您可以在其中找到很多辅助函数。

uses IniFiles;

function WideStringToUTF8(const Value: WideString): AnsiString;
var
  BufferLen: Integer;
begin
  Result := '';

  if Value <> '' then
  begin
    BufferLen := WideCharToMultiByte(CP_UTF8, 0, PWideChar(Value), -1, nil, 0, nil, nil);
    SetLength(Result, BufferLen - 1);
    if BufferLen > 1 then
      WideCharToMultiByte(CP_UTF8, 0, PWideChar(Value), -1, PAnsiChar(Result), BufferLen - 1, nil, nil);
  end;
end;

function UTF8ToWideString(const Value: AnsiString): WideString;
var
  BufferLen: integer;
begin
  Result := '';

  if Value <> '' then
  begin
    BufferLen := MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(Value), -1, nil, 0);
    SetLength(Result, BufferLen - 1);
    if BufferLen > 1 then
      MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(Value), -1, PWideChar(Result), BufferLen - 1);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  IniFile: TIniFile;
const
  UnicodeValue = WideString(#$0101#$010D#$0113#$016B#$012B#$0161);
begin
  IniFile := TIniFile.Create('C:\test.ini');

  try
    IniFile.WriteString('Section', 'Key', WideStringToUTF8(UnicodeValue));
    IniFile.UpdateFile;
  finally
    IniFile.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  IniFile: TIniFile;
  UnicodeValue: WideString;
begin
  IniFile := TIniFile.Create('C:\test.ini');

  try
    UnicodeValue := UTF8ToWideString(IniFile.ReadString('Section', 'Key', 'Default'));
    MessageBoxW(Handle, PWideChar(UnicodeValue), 'Caption', 0);
  finally
    IniFile.Free;
  end;
end;

在此处输入图像描述
64 位 Windows 7 Enterprise SP 1 上使用 Delphi 2007

If you want to save the Unicode INI files then you might try the following code. The files are saved in UTF8 encoding.

Also you might take a look at this Unicode library where you can find a lot of helper functions.

uses IniFiles;

function WideStringToUTF8(const Value: WideString): AnsiString;
var
  BufferLen: Integer;
begin
  Result := '';

  if Value <> '' then
  begin
    BufferLen := WideCharToMultiByte(CP_UTF8, 0, PWideChar(Value), -1, nil, 0, nil, nil);
    SetLength(Result, BufferLen - 1);
    if BufferLen > 1 then
      WideCharToMultiByte(CP_UTF8, 0, PWideChar(Value), -1, PAnsiChar(Result), BufferLen - 1, nil, nil);
  end;
end;

function UTF8ToWideString(const Value: AnsiString): WideString;
var
  BufferLen: integer;
begin
  Result := '';

  if Value <> '' then
  begin
    BufferLen := MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(Value), -1, nil, 0);
    SetLength(Result, BufferLen - 1);
    if BufferLen > 1 then
      MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(Value), -1, PWideChar(Result), BufferLen - 1);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  IniFile: TIniFile;
const
  UnicodeValue = WideString(#$0101#$010D#$0113#$016B#$012B#$0161);
begin
  IniFile := TIniFile.Create('C:\test.ini');

  try
    IniFile.WriteString('Section', 'Key', WideStringToUTF8(UnicodeValue));
    IniFile.UpdateFile;
  finally
    IniFile.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  IniFile: TIniFile;
  UnicodeValue: WideString;
begin
  IniFile := TIniFile.Create('C:\test.ini');

  try
    UnicodeValue := UTF8ToWideString(IniFile.ReadString('Section', 'Key', 'Default'));
    MessageBoxW(Handle, PWideChar(UnicodeValue), 'Caption', 0);
  finally
    IniFile.Free;
  end;
end;

enter image description here
with Delphi 2007 on 64-bit Windows 7 Enterprise SP 1

昨迟人 2024-12-06 14:53:29

如果您确实需要使用 Delphi 7,则有一些变体:

  1. 将字符串存储在链接到可执行文件的资源中。

  2. 将字符串存储在大备忘录或相同的东西中,位于全局数据模块或任何其他可视或非可视组件上,并通过索引访问它。这是可能的,因为 Delphi 资源中的字符串以 XML 编码的形式存储。例如,您的符号示例 āčēūīšķļņž 将存储为 āčēūīš& ;#311;ļņž

  3. 将 XML 编码或 Base64 编码的字符串存储在代码内的字符串常量中。

对于字符串转换,您可以使用 EncdDecd.pas 、 xdom.pas 或 System.pas 的某些函数,例如 UTF8Encode/UTF8Decode。

要在 Delphi 表单中显示和编辑 Unicode 字符串,您可以使用特殊的 Unicode 控件集,例如 TNT Unicode Controls 或对原始 Delphi 控件进行子类化并自行执行一些其他解决方法,如本节中所述摘自 TntControls.pas 中的注释(TNT Unicode 控件的一部分):

Windows NT 提供对本机 Unicode 窗口的支持。添加
Unicode 支持
TWinControl 后代,重写 CreateWindowHandle() 并调用
CreateUnicodeHandle()。

此方法有效的一个主要原因是 VCL 仅使用 ANSI
的版本
SendMessage()——SendMessageA()。如果您在
统一码
窗口,Windows 处理 ANSI/UNICODE 转换
自动地。所以
例如,如果 VCL 使用以下命令将 WM_SETTEXT 发送到窗口
发送消息A,
Windows 实际上期望一个 PAnsiChar,即使目标窗口
是一个 UNICODE
窗户。因此使用 PChars 调用 SendMessageA 不会出现任何问题。

VCL 中的问题与 TControl.Perform() 方法有关。
履行()
直接调用窗口过程并假定一个 ANSI 窗口。
这是一个
例如,如果 VCL 调用 Perform(WM_SETTEXT, ...)
传入一个
PAnsiChar 最终被传递给 DefWindowProcW()
它需要一个 PWideChar。

这就是 SubClassUnicodeControl() 的原因。这个程序
将子类化
Windows WndProc 和 TWinControl.WindowProc 指针。它将
确定是否
消息来自 Windows 或者 WindowProc 被调用
直接地。然后它会
调用 Windows 的 SendMessageA() 来执行正确的转换
某些短信。

另一个问题与 TWinControl.DoKeyPress() 有关。这是
从 WM_CHAR 调用
信息。它将 WideChar 转换为 AnsiChar,并发送
结果字符为
DefWindowProc。为了避免这种情况,DefWindowProc 是
子类也是如此。窗口过程
将使 WM_CHAR 消息对于 ANSI 处理代码来说是安全的
将字符代码转换为
#FF 在传递之前。它将原始的 WideChar 存储在
.TWMChar 的未使用字段。
代码 #FF 在传递到之前被转换回 WideChar
DefWindowProc。

If you definitely need to use Delphi 7 there are some variants:

  1. Store strings in resources linked to executable file.

  2. Store strings in big memo or same thing, located on global data module or any other visual or non-visual component and access it by index. It's possible because strings in Delphi resources stored in XML-encoded form. E.g. your symbols example āčēūīšķļņž will be stored as āčēūīšķļņž

  3. Store XML-encoded or Base64-encoded strings in string constants inside your code.

For string conversion you can use EncdDecd.pas , xdom.pas or some functions of System.pas like UTF8Encode/UTF8Decode.

To display and edit Unicode strings in Delphi forms you can use special set of Unicode controls like TNT Unicode Controls or subclass original Delphi controls and do some other workarounds by yourself, like described in this excerpt from comments in TntControls.pas (part of TNT Unicode Controls):

Windows NT provides support for native Unicode windows. To add
Unicode support to a
TWinControl descendant, override CreateWindowHandle() and call
CreateUnicodeHandle().

One major reason this works is because the VCL only uses the ANSI
version of
SendMessage() -- SendMessageA(). If you call SendMessageA() on a
UNICODE
window, Windows deals with the ANSI/UNICODE conversion
automatically. So
for example, if the VCL sends WM_SETTEXT to a window using
SendMessageA,
Windows actually expects a PAnsiChar even if the target window
is a UNICODE
window. So caling SendMessageA with PChars causes no problems.

A problem in the VCL has to do with the TControl.Perform() method.
Perform()
calls the window procedure directly and assumes an ANSI window.
This is a
problem if, for example, the VCL calls Perform(WM_SETTEXT, ...)
passing in a
PAnsiChar which eventually gets passed downto DefWindowProcW()
which expects a PWideChar.

This is the reason for SubClassUnicodeControl(). This procedure
will subclass the
Windows WndProc, and the TWinControl.WindowProc pointer. It will
determine if the
message came from Windows or if the WindowProc was called
directly. It will then
call SendMessageA() for Windows to perform proper conversion on
certain text messages.

Another problem has to do with TWinControl.DoKeyPress(). It is
called from the WM_CHAR
message. It casts the WideChar to an AnsiChar, and sends the
resulting character to
DefWindowProc. In order to avoid this, the DefWindowProc is
subclassed as well. WindowProc
will make a WM_CHAR message safe for ANSI handling code by
converting the char code to
#FF before passing it on. It stores the original WideChar in the
.Unused field of TWMChar.
The code #FF is converted back to the WideChar before passing onto
DefWindowProc.

故事与诗 2024-12-06 14:53:29

const MyString = WideString('Teksts latvie'#$0161'u valod'#$0101);

Do

const MyString = WideString('Teksts latvie'#$0161'u valod'#$0101);
ゃ人海孤独症 2024-12-06 14:53:29

很简单,想法就是找到一个非可视组件,它可以存储文本并将您的文本存储在那里。希望这样的组件还可以为您提供一个编辑器来在设计时编辑文本。

有一个组件调用 FormResource 可以做到这一点。我使用 TUniScript。我相信还有其他类似的组件。但是,我没有从标准库中找到可用的组件。

Simple, the idea is to find a non-visual component, which can store text and store your text there. Prefer that such component can also provide you an editor to edit the text in design time.

There is a component call FormResource which can do this. I use TUniScript. I believe there are other similar components. However, I did not find a usable component from the standard library.

肩上的翅膀 2024-12-06 14:53:29

Widestring(#$65E5#$672C) 方法不起作用,因为 Delphi 7 不希望 # 超过一个字节,因此结果是当价格超过 255 或 $FF 时,远不是您所期望的。

当知道您需要在源代码中使用 Widestring 时,可以使用另一种方法 WideChar($65E5)+ WideChar($672C) 在源代码中存储单个 Unicode 代码点。赋值的开始(也可以是空文字),以便编译器了解您想要哪种数据类型:

const
  // Compiler error "Imcompatible types"
  WONT_COMPILE: WideChar($65E5)+ WideChar($672C);

  // 日本
  NIPPON: Widestring('')+ WideChar($65E5)+ WideChar($672C);

看起来很麻烦,但在 Delphi 7 中肯定有您的 UTF-16 文本。

或者,将常量存储在UTF-8,ASCII 安全 - 这样您就可以轻松使用 #。优点之一是,在源代码中编写要简单得多。一个缺点是,您永远不能直接使用该常量,而必须先将其转换为 UTF-16:

const
  // UTF-8 of the two graphemes 日 and 本, needing 3 bytes each
  NIPPON: #$E6#$97#$A5#$E6#$9C#$AC;
var
  sUtf16: Widestring;
begin
  // Internally these are 2 WORDs: $65E5 and $672C
  sUtf16:= UTF8ToWideString( NIPPON );

The approach Widestring(#$65E5#$672C) does not work, because Delphi 7 just doesn't expect more than one byte for the #, so the outcome is by far not what you expect when going above 255 or $FF.

Another approach WideChar($65E5)+ WideChar($672C) can be used to store single Unicode codepoints in your source code when knowing that you need to have a Widestring at the start of the assignment (which can also be an empty literal) so the compiler understands which datatype you want:

const
  // Compiler error "Imcompatible types"
  WONT_COMPILE: WideChar($65E5)+ WideChar($672C);

  // 日本
  NIPPON: Widestring('')+ WideChar($65E5)+ WideChar($672C);

Looks cumbersome, but surely has your UTF-16 texts in Delphi 7.

Alternatively, store your constants in UTF-8, which is ASCII safe - that way you can use # easily. One advantage is, that it's a lot less cumbersome to write in your source code. One disadvantage is, that you can never use the constant directly, but have to convert it to UTF-16 first:

const
  // UTF-8 of the two graphemes 日 and 本, needing 3 bytes each
  NIPPON: #$E6#$97#$A5#$E6#$9C#$AC;
var
  sUtf16: Widestring;
begin
  // Internally these are 2 WORDs: $65E5 and $672C
  sUtf16:= UTF8ToWideString( NIPPON );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文