Преобразование потока памяти с нулевым символом в конце в строку Юникода - PullRequest
1 голос
/ 19 января 2011

В Delphi XE я собираю данные CF_UNICODETEXT из буфера обмена. Результатом является поток, который заканчивается двумя нулевыми байтами. Чтобы получить фактическую строку, которая была скопирована в буфер обмена, мне нужно удалить нули.

Этот аналогичный вопрос содержит хороший метод преобразования из TMemoryStream в строку Unicode Delphi:

function MemoryStreamToString(M: TMemoryStream): string;
begin
  SetString(Result, M.Memory, M.Size div SizeOf(Char));
end;

В моем случае, однако, это приведет к появлению строки, содержащей завершающие нули. Я мог бы это исправить, ограничив размер:

function ClipboardMemoryStreamToString(M: TMemoryStream): string;
begin
  SetString(Result, M.Memory, (M.Size - SizeOf(Char)) div SizeOf(Char));
end;

... но это выглядит ужасно, "особый случай". Интересно, есть ли более чистый способ кодирования этого, чтобы кто-нибудь (я!), Взглянув на код позже, не сразу спросил: «Почему конечный символ удаляется из потока?»

Редактировать: Одним из способов упреждения вопроса является добавление комментария. Но кроме этого?

Ответы [ 2 ]

5 голосов
/ 19 января 2011

Что не так с Clipboard.AsText? Он делает все для вас без необходимости в потоках, тыкаясь в байтах, имея дело с нулевыми терминаторами и т. Д.

Что касается поставленного вами точного вопроса, я бы просто написал:

SetString(Result, M.Memory, M.Size div SizeOf(Result[1]) - 1);
2 голосов
/ 20 января 2011

Если вы нацелены на CF_UNICODETEXT, вам нужно указать Юникод , в частности:

// For old Delphi versions
{$IFNDEF UNICODE}
type
  UnicodeString = WideString;
{$ENDIF}

// For CF_TEXT
function MemoryStreamToAnsiString(M: TMemoryStream): AnsiString;
begin
  SetString(Result, M.Memory, M.Size);
  if (Result <> '') and (Result[Length(Result)] = #0) then
    SetLength(Result, Length(Result) - 1);
end;

// For CF_UNICODETEXT
function MemoryStreamToUnicodeString(M: TMemoryStream): UnicodeString;
begin
  SetString(Result, M.Memory, M.Size div SizeOf(WideChar));
  if (Result <> '') and (Result[Length(Result)] = #0) then
    SetLength(Result, Length(Result) - 1);
end;

// I'm not sure that you should use this form
function MemoryStreamToString(M: TMemoryStream): String;
begin
  SetString(Result, M.Memory, M.Size div SizeOf(Char));
  if (Result <> '') and (Result[Length(Result)] = #0) then
    SetLength(Result, Length(Result) - 1);
end;

Если вы уверены на 100%, что строка заканчивается нулем, то:

// For CF_TEXT
function MemoryStreamToAnsiString(M: TMemoryStream): AnsiString;
begin
  SetString(Result, M.Memory, M.Size - 1);
end;

// For CF_UNICODETEXT
function MemoryStreamToUnicodeString(M: TMemoryStream): UnicodeString;
begin
  SetString(Result, M.Memory, (M.Size div SizeOf(WideChar)) - 1);
end;

function MemoryStreamToString(M: TMemoryStream): String;
begin
  SetString(Result, M.Memory, (M.Size div SizeOf(Char)) - 1);
end;
...