开发者

Converting a null-terminated memory stream to unicode string

In Delphi XE, I am capturing CF_UNICODETEXT data from the clipboard. The result is a stream that terminates with two null bytes. To get the actual string that was copied to clipboard, I need to strip the nulls.

This similar so question contains a nice method of converting from TMemoryStream to Delphi's unicode string:

function MemoryStreamToString(M: TMe开发者_StackOverflow社区moryStream): string;
begin
  SetString(Result, M.Memory, M.Size div SizeOf(Char));
end;

In my case, however, this would produce a string including the trailing nulls. I could fix that by limiting the size:

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

... but this feels ugly, "special-casey". I wonder if there is a cleaner way to code this, so that anyone (me!) looking at the code later won't immediately ask "Why is the trailing char being dropped from the stream?"

Edit: One way of pre-empting the question is adding a comment. But, other than that?


What's wrong with Clipboard.AsText? It does everything for you with no need for streams, poking at bytes, dealing with null terminators etc.

As for the precise question you raised, I would simply write:

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


If you target CF_UNICODETEXT, you need to specify unicode string specifically:

// 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;

If you're 100% sure that string is zero-terminated, then:

// 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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜