Clipboard with Custom Clipboard Formats - Delphi
http://delphi.about.com/od/windowsshellapi/a/clipboard_spy_3.htm
Do you know that, for example, MS Word has it's own format for storing data to the clipboard?
Large number of applications paste information in other formats, for example Rich Text Format, HTML format and so forth.
Why not use Delphi to create and store our specific formats (like records) in the clipboard.
This can be very useful in moving data between two Delphi applications.
Let's say we have a record type called TMember, declared as:
type TMember = record Name : string; eMail : string; Posts : Cardinal; end;
We want to paste a variable of TMember type to the clipboard.
Before we can write information to the clipboard in a specific format, the format must be registered.
We register a new clipboard format by calling the RegisterClipboardFormat API function and
specifying a unique name for your new format - this enables us to copy and paste any type of data we want.
First we have to register the CF_TMember format (that holds TMember type variable values),
in the OnCreate procedure of the main form, so that we can use it later on during clipboard calls.
Newly created clipboard format will be named:
'OurFormat' and it will hold data from DelphiGuide variable filled in the OnCreate event and declared at the form level.
Then we send our data to the clipboard.
Sending custom format data to the clipboard is coded in the following way:
- Open the clipboard with OpenClipboard.
- Empty current contents of the clipboard with EmptyClipboard.
- Allocate and lock a global memory block.
- Copy data into the global memory block.
- Unlock the block.
- Transfer the block to the Clipboard with SetClipboardData. (Windows now controls the block).
- Close the clipboard with CloseClipboard. (So other programs can access it).
var DelphiGuide: TMember; ... MemberPointer : ^TMember; MemberHandle : HGLOBAL; ... //fill some dummy data DelphiGuide.Name := 'Zarko Gajic'; DelphiGuide.eMail := 'delphi@aboutguide.com'; DelphiGuide.Posts := 15; OurFormat := RegisterClipboardFormat('CF_TMember') ; if OpenClipboard(Handle) then begin EmptyClipboard; MemberHandle := GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE, SizeOf(TMember)) ; MemberPointer := GlobalLock(MemberHandle) ; MemberPointer^.Name := DelphiGuide.Name; MemberPointer^.eMail := DelphiGuide.eMail; MemberPointer^.Posts := DelphiGuide.Posts; GlobalUnLock(MemberHandle) ; SetClipboardData(OurFormat,MemberHandle) ; CloseClipboard() ; end;
Again, to act whenever the contents of the clipboard changes we need to respond to a WM_DrawClipboard message.
We use the HasFormat function to find out whether the clipboard contains data encoded in a specific format.
Getting custom format data from the clipboard is coded in the following way:
- Open the clipboard with OpenClipboard.
- Get a handle to the clipboard data with GetClipboardData.
- Allocate and lock a memory block to hold the clipboard data.
- Lock the clipboard data block.
- Copy data from the clipboard data block to the program's data block
(The data can now be manipulated by the application). - Unlock both memory blocks.
- Close the clipboard with CloseClipboard.
if Clipboard.HasFormat(OurFormat) then begin if OpenClipboard(Handle) then begin MemberInClip := GetClipboardData(OurFormat) ; MemberPointer := GlobalLock(MemberInClip) ; with AMember do begin Name := MemberPointer^.Name; eMail := MemberPointer^.eMail; Posts := MemberPointer^.Posts; end; GlobalUnLock(MemberInClip) ; CloseClipboard() ; with Memo1.Lines do begin Clear; Add('Clipboard has TMember data:') ; Add(AMember.Name) ; Add(AMember.email) ; Add(IntToStr(AMember.Posts)) ; end; end; end;
Note:
in normal situation we'll have one Delphi application sending data to the clipboard and another Delphi application getting data from it.
Since this is the demo project we have only one application running - we send custom formatted data to the clipboard
in the OnCreate event for the form. In the same form, we are handling the clipboard change notification, therefore when we start our project, Memo1 component is filled with data from the clipboard - i.e. the data we are sending when the form is created.
Are You in Control Now?
That's it. We have the clipboard working just as we would like it to.
No one can send data to the clipboard without us knowing that something is going on.
Even more: we can copy and paste program-specific data to the clipboard.
However, some questions stay unanswered:
What is the best way of sending an array of TMember variables to another Delphi application;
what will happen if some other application is register 'CF_TMember' with some other format, and so on.