Search code examples
delphiappenddelphi-xe2clipboard

How do I append data to existing clipboard in a new format without removing the existing data?


I need to put data on the clipboard in several formats, one being RTF. The component I'm using handles everything except for RTF wonderfully. How can I append the RTF format data without blowing away the data placed there already by the ancestor class? I'm trying to avoid duplicating the clipboard logic from the ancestor in my copy to clipboard routine if there's a way to do so.


Solution

  • You can append to the existing clipboard data by doing the following:

    1. Call Clipboard.Open.
    2. Call the base class method that puts the other data on the clipboard.
    3. Call Clipboard.SetAsHandle, or SetClipboardData passing your RTF.
    4. Call Clipboard.Close.

    So long as the inherited call is inside your Open/Close pair you will get the desired effect.

    Here is a demonstration of what I mean:

    procedure SetBuffer(Format: Word; const Buffer; Size: Integer);
    var
      DataPtr: Pointer;
      Data: THandle;
    begin
      Data := GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE, Size);
      try
        DataPtr := GlobalLock(Data);
        try
          Move(Buffer, DataPtr^, Size);
          Win32Check(SetClipboardData(Format, Data) <> 0);
        finally
          GlobalUnlock(Data);
        end;
      except
        GlobalFree(Data);
        raise;
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Bitmap: TBitmap;
    const
      Text: string = 'foo';
    begin
      Clipboard.Open;
      try
    
        // imagine this next block is the base component's method to set the clipboard 
        Clipboard.Open;
        try
          Bitmap := GetFormImage;
          try
            Clipboard.Assign(Bitmap);
          finally
            Bitmap.Free;
          end;
        finally
          Clipboard.Close;
        end;
    
        // once that is done, we can add out extra data    
        SetBuffer(CF_UNICODETEXT, Text[1], ByteLength(Text));
      finally
        Clipboard.Close;
      end;
    end;
    

    Because we hold a lock on the clipboard the whole time, no other process can get in our way. And the base component method will empty the clipboard before it starts adding its text.