Search code examples
delphiwinapiclipboardgpxtmemo

How to paste a custom format clipboard data into a TMemo?


This question refers to this one along with its accepted answer posted here on stackoverflow.

I don't feel comfortable at Windows API programming.

Exploring the way EasyGPS by Topografix handles clipboard manipulations, I discovered that it uses a custom clipboard format named GPX wich is actually plain XML text (GPX to be precise). Using Clipboard.AsText is excluded.

I stumble at this stage:

program ProbeClipboard;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  ClipBrd;

var
  CF_GPX: Cardinal;
  ClipboardData: THandle;

begin
  CF_GPX:=RegisterClipboardFormat('GPX');

  if ClipBoard.HasFormat(CF_GPX) then
  begin
    Writeln('GPX format available in clipboard');
    //
    OpenClipboard(0);

    ClipboardData := GetClipboardData(CF_GPX);

    if ClipboardData = 0 then
      raise Exception.Create('Clipboard data Error');

    /// How to use GlobalLock and GlobalUnLock
    /// so that I can paste the Clipboard data
    /// to a TMemo instance for example

    CloseClipboard;
  end;
end.

Please, help me to fix that program.


Solution

  • I'd write it like this:

    program ProbeClipboard;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      Windows,
      ClipBrd;
    
    var
      CF_GPX: Cardinal;
      ClipboardData: Windows.HGLOBAL;
      Ptr: Pointer;
      Size: DWORD;
    
    begin
      CF_GPX := RegisterClipboardFormat('GPX');
    
      Clipboard.Open;
      try
        if Clipboard.HasFormat(CF_GPX) then
        begin
          Writeln('GPX format available in clipboard');
    
          ClipboardData := Clipboard.GetAsHandle(CF_GPX);
          if ClipboardData=0 then
            RaiseLastOSError;
    
          Ptr := Windows.GlobalLock(ClipboardData);
          if Ptr=nil then
            RaiseLastOSError;
    
          try
            Size := Windows.GlobalSize(ClipboardData);
    
            //Ptr now points to a memory block of Size bytes 
            //containing the clipboard data
          finally
            Windows.GlobalUnlock(ClipboardData);
          end;
        end;
      finally
        Clipboard.Close;
      end;
    end.
    

    Note that I moved the clipboard Open command, which locks the clipboard to be outside the test for the CF_GPX format. That is to avoid a race condition which exists in your code. In your code the clipboard could be modified between the HasFormat call and the OpenClipboard call.

    I also used the Clipboard class exclusively. This class has all you need and you don't need to use the raw Win32 clipboard API.

    I even put error checking in!