2

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.

Community
  • 1
  • 1
menjaraz
  • 7,551
  • 4
  • 41
  • 81

1 Answers1

5

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!

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thank you to point me that the out-of-the-box Clipboard singleton does the job, I was too focused on Windows API despite of my poor proficiency. Will a PChar do instead of Pointer since the alleged GPX custom clipboard format is actually a plain text? – menjaraz Jan 01 '12 at 20:36
  • Exactly how to pull out the string data depends on what encoding it is in. Do you know? ANSI? UTF8? UTF16? All the same I'd be looking to use the `SetString` procedure to do this to make sure I didn't overrun a buffer. – David Heffernan Jan 01 '12 at 20:45
  • Use SetString(utf8str, PAnsiChar(Ptr), Size-1) – David Heffernan Jan 01 '12 at 20:56
  • Please can you do me a favour? It would be nice if you can point to me where on the stackoverflow/stackexchange sites I can find extensive material on the `tidying up` process you've introduced to me before. I need some reference to convince someone on SO who doesn't see it fit. – menjaraz Jan 02 '12 at 07:55
  • @menjaraz Tidying up? Picked that up from what others do and from comments from moderators on meta. But it's pretty much obvious. For example, if you point out an error in an answer and then the answer is edited to correct the error, it is only polite to delete the comment. – David Heffernan Jan 03 '12 at 01:37