Forum > LCL

ClipBoard.GetAsText bug?

(1/2) > >>

Bart:
Hi,

Can anyone confirm this?

On win9x I have a problem with ClipBoard.GetAsText.

Take a look at this example code:


--- Code: ---  ClipText := ClipBoard.AsText;
  debugln;
  debugln('ClipText = "',ClipText,'"');
  debugln('Length = ',DbgS(Length(ClipText)));
  for i := 1 to length(ClipText) do DbgOut('#',DbgS(Ord(ClipText[i])));
  debugln;

--- End code ---

Now when I copy (from Windows Notepad) 'ABC'  to the clipboard and run the above code, the output is


--- Quote ---ClipText = "ABC                            "
Length = 31
#65#66#67#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

--- End quote ---

The first #0 after 'C' (#67) is consistent, the rest may be garbage.

I traced this down to (in /lcl/interfaces/win32/win32winapi.inc)


--- Code: ---  function ReadClipboardToStream(DestStream: TStream): Boolean;
  begin
    Result := false;

    DataHandle := Windows.GetClipboardData(FormatID);
    if DataHandle<>HWND(0) then
    begin
      Size := Windows.GlobalSize(DataHandle);      // <<-------------------- **

    .....
  end;

--- End code ---


**       Size will always be n times 32 (on win32)     

In ClipBoard.GetAsText there is code to remove the last trailing #0 (if there is one), but as the example shows, this is not enough.
Moreover, the last char in the buffer might not even be a #0 and nothing gets removed.

Can anyone confirm this?
Is it Windows (win32) only?

Bart

Martin_fr:
Interesting => I actually have seen occasionally trash when pasting from clipboard (and the same clipboard pasting outside lazarus being fine)

theo:
Should be easy to fix:


--- Code: ---var aStr:String;
begin
aStr:=#65#66#67#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0;
writeln(length(aStr));
aStr:=PChar(aStr);
writeln(length(aStr));
end;     
--- End code ---

Bart:
That's not a fix, that's a workaround.  ;)

AFAIK a string pasted from the OS clipboard cannot contain a #0.

So the issue might be fixed like this


--- Code: ---function TClipboard.GetAsText: string;
var
  MemStream: TMemoryStream;
  ASize: int64;
begin
  //DebugLn('[TClipboard.GetAsText] A ',ClipboardTypeName[ClipboardType]);
  Result:='';
  MemStream:=TMemoryStream.Create;
  try
    if GetFormat(PredefinedClipboardFormat(pcfText),MemStream) then begin
      //ASize:=MemStream.Size; <<-- replace this with the following 2 lines
      ASize := IndexByte(MemStream.Memory^, MemStream.Size, 0);
      if (ASize < 0) then ASize := MemStream.Size;
      .....

--- End code ---

Bart

theo:
Your solution is certainly correct, but I can't see any practical difference to

Result:=PChar(Result);

The overhead is 31 bytes maximum for a short time. Remains to see if a the PChar casting or the IndexByte call is faster.

Navigation

[0] Message Index

[#] Next page

Go to full version