2011-01-19 3 views
1

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

This similar so question содержит хороший способ преобразования из TMemoryStream в юникод строки в Delphi:

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

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

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

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

+0

Забавно, что вы упоминаете TMemoryStream. Сегодня я удалил его из всей своей кодовой базы (там осталось много ссылок) из-за реализации фрагментации памяти! –

+0

функция плитка ... –

+0

@David: это интригующий. Какая ваша предпочтительная замена? –

ответ

2

Если цель 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; 
+0

Ну, OP использует XE, и предполагается, что он не пытается писать код, который компилируется в других версиях Delphi. Таким образом, он не должен быть таким сложным. –

5

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

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

SetString(Result, M.Memory, M.Size div SizeOf(Result[1]) - 1); 
+1

Я избегаю блока clipbrd, потому что мне нужно хранить и возвращать все доступные форматы, поэтому я имею дело только с API и точными буферами данных, которые поставляются Windows в буфере обмена. На самом деле, Clipboard.AsText делает что-то опрятное, чтобы решить мою проблему: Результат: = PChar (GlobalLock (Data)). Поток с нулевым концом соответствует формату PChar, но я бы не догадался, что получаю копию таким образом. –

+0

Если вы хотите избежать блока «Clipboard», я полагаю, что теперь вы нашли каноническое решение. Тем не менее, блок «Clipboard» можно легко использовать для чтения и записи нескольких форматов. Ясно, что вам не нужно его использовать, но я не вижу особых причин, чтобы избежать этого. –

+1

@Mood, Сохранение/восстановление буфера обмена возможно, но не без нежелательных побочных эффектов. Вы не сможете точно восстанавливать сложные форматы на 100%, и вы не можете манипулировать клипом, не вызывая проблем в других приложениях. Пожалуйста, см. Мой ответ на этот вопрос: http://stackoverflow.com/questions/4735559/c-saving-and-then-retriving-data-via-the-clipboard/4735718#4735718 –