Delphi - хранит WideStrings внутри программы
Раньше я использовал INI-файлы для хранения текста Unicode, но теперь мне нужно хранить текст Unicode в той же программе. Как мне достичь этого результата?
Хотите хранить эти письма:
āčēūīšķļņž
РЕДАКТИРОВАТЬ
Вы хотите знать, как я храню текст Unicode? Ну, я только что создал приложение, оно имеет INI: TIniFile
3x TTNTEdit
(Section
, Ident
, Value
) и еще одна кнопка, когда я нажимаю кнопку, она вызывает:
INI.WriteString(TnTEdit1.Text,TnTEdit2.Text,TnTEdit3.Text);
а затем моя другая программа читает значение Unicode.
5 ответов
Если вам определенно нужно использовать Delphi 7, есть несколько вариантов:
Храните строки в ресурсах, связанных с исполняемым файлом.
Храните строки в большой записке или в той же вещи, расположенной в глобальном модуле данных или любом другом визуальном или невизуальном компоненте, и обращайтесь к нему по индексу. Это возможно, потому что строки в ресурсах Delphi хранятся в XML-кодированной форме. Например, ваш пример символов
āčēūīšķļņž
будет храниться какāčēūīšķļņž
Храните строки в кодировке XML или Base64 в строковых константах внутри вашего кода.
Для преобразования строк вы можете использовать EncdDecd.pas, xdom.pas или некоторые функции System.pas, такие как UTF8Encode/UTF8Decode.
Для отображения и редактирования строк Unicode в формах Delphi вы можете использовать специальный набор элементов управления Unicode, таких как элементы управления Unicode TNT или подкласс исходных элементов управления Delphi, и самостоятельно выполнять некоторые обходные пути, как описано в этом отрывке из комментариев в TntControls.pas (часть TNT Unicode). Элементы управления):
Windows NT обеспечивает поддержку собственных окон Unicode. Чтобы добавить поддержку Unicode для потомка TWinControl, переопределите CreateWindowHandle() и вызовите CreateUnicodeHandle().
Одна из основных причин, почему это работает, заключается в том, что VCL использует только ANSI-версию SendMessage() - SendMessageA(). Если вы вызываете SendMessageA () в окне UNICODE, Windows автоматически обрабатывает преобразование ANSI/UNICODE. Так, например, если VCL отправляет WM_SETTEXT в окно с помощью SendMessageA, Windows фактически ожидает PAnsiChar, даже если целевое окно является окном UNICODE. Поэтому вызов SendMessageA с PChars не вызывает проблем.
Проблема в VCL связана с методом TControl.Perform(). Perform () напрямую вызывает оконную процедуру и принимает окно ANSI. Это проблема, если, например, VCL вызывает Perform(WM_SETTEXT, ...), передавая PAnsiChar, который в конечном итоге передается в DefWindowProcW(), который ожидает PWideChar.
Это причина для SubClassUnicodeControl(). Эта процедура создаст подкласс Windows WndProc и указатель TWinControl.WindowProc. Он определит, пришло ли сообщение из Windows или WindowProc был вызван напрямую. Затем он вызовет SendMessageA () для Windows, чтобы выполнить правильное преобразование определенных текстовых сообщений.
Другая проблема связана с TWinControl.DoKeyPress(). Он вызывается из сообщения WM_CHAR. Он преобразует WideChar в AnsiChar и отправляет полученный символ в DefWindowProc. Чтобы избежать этого, DefWindowProc также является подклассом. WindowProc сделает сообщение WM_CHAR безопасным для кода обработки ANSI, преобразовав код символа в #FF перед его передачей. Он сохраняет оригинальный WideChar в.Unused поле TWMChar. Код #FF преобразуется обратно в WideChar перед передачей на DefWindowProc.
Если вы хотите сохранить INI-файлы Unicode, вы можете попробовать следующий код. Файлы сохраняются в кодировке 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;
с Delphi 2007 на 64-битной Windows 7 Enterprise SP 1
Просто идея состоит в том, чтобы найти невизуальный компонент, который может хранить текст и хранить там ваш текст. Предпочтите, чтобы такой компонент также мог предоставить вам редактор для редактирования текста во время разработки.
Есть вызов компонента FormResource
который может это сделать. я используюTUniScript
. Я считаю, что есть и другие подобные компоненты. Однако я не нашел пригодного для использования компонента из стандартной библиотеки.
Делать
const MyString = WideString('Teksts latvie'#$0161'u valod'#$0101);
Подход
Widestring(#$65E5#$672C)
не работает, потому что Delphi 7 просто не ожидает более одного байта для, поэтому результат далеко не тот, который вы ожидаете при превышении 255 или $FF.
Другой подход
WideChar($65E5)+ WideChar($672C)
может использоваться для хранения отдельных кодовых точек Unicode в исходном коде, если вы знаете, что вам нужен
Widestring
в начале присваивания (которое также может быть пустым литералом), чтобы компилятор понимал, какой тип данных вы хотите:
const
// Compiler error "Imcompatible types"
WONT_COMPILE: WideChar($65E5)+ WideChar($672C);
// 日本
NIPPON: Widestring('')+ WideChar($65E5)+ WideChar($672C);
Выглядит громоздко, но ваши тексты UTF-16 наверняка есть в Delphi 7.
В качестве альтернативы сохраните свои константы в 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 );