Хм, почему ты это делаешь? Почему вы кодируете WideString в UTF-8 только для того, чтобы снова сохранить его обратно в WideString. Вы, очевидно, используете Unicode-версию Windows API. Поэтому нет необходимости использовать строку в кодировке UTF-8. Или я что-то упустил.
Поскольку функции Windows API являются либо Unicode (два байта), либо ANSI (один байт). UTF-8 здесь был бы неправильным выбором, потому что в основном он содержит один байт на символ, но для символов выше основания ASCII он использует два или более байтов.
В противном случае эквивалент для вашего старого кода в Unicode Delphi будет:
var
UnicodeStr: string;
UTF8Str: string;
begin
UnicodeStr:='some unicode text';
UTF8Str:=UTF8Encode(UnicodeStr);
Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;
WideString и string (UnicodeString) похожи, но новая UnicodeString быстрее, потому что она подсчитывается, а WideString - нет.
Ваш код был неправильным, потому что строка UTF-8 имеет переменное число байтов на символ. «А» хранится как один байт. Просто байт-код ASCII. «ü», с другой стороны, будет храниться как два байта. А поскольку вы затем используете PWideChar, функция всегда ожидает два байта на символ.
Есть еще одно отличие. В более старых версиях Delphi (ANSI) Utf8String был просто AnsiString. В Unicode-версиях Delphi Utf8String представляет собой строку с кодовой страницей UTF-8 за ней. Так что ведет себя по-разному.
Старый код все равно будет работать правильно:
var
UnicodeStr: WideString;
UTF8Str: WideString;
begin
UnicodeStr:='some unicode text';
UTF8Str:=UTF8Encode(UnicodeStr);
Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;
Он будет действовать так же, как в Delphi 2007. Так что, возможно, у вас есть проблема в другом месте.
Мик, ты прав. Компилятор делает некоторую дополнительную работу за кулисами. Поэтому, чтобы избежать этого, вы можете сделать что-то вроде этого:
var
UTF8Str: AnsiString;
UnicodeStr: WideString;
TempString: RawByteString;
ResultString: WideString;
begin
UnicodeStr := 'some unicode text';
TempString := UTF8Encode(UnicodeStr);
SetLength(UTF8Str, Length(TempString));
Move(TempString[1], UTF8Str[1], Length(UTF8Str));
ResultString := UTF8Str;
end;
Я проверил, и все работает точно так же. Поскольку я перемещаю байты непосредственно в память, в фоновом режиме не выполняется преобразование кодовой страницы. Я уверен, что это можно сделать с большей элегантностью, но дело в том, что я вижу в этом путь к тому, чего вы хотите достичь.