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:

āčēūīšķļņž
有帮助吗?

解决方案

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.

其他提示

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

Do

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

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top