// The TClipboard provides easy clipboard access. But what if you
// want to add (several) custom defined items to the clipboard?
// For all actions is the unit Clipboard required.
uses Clipboard;
// First you have to register your own ClipBoard format
// Zuerst registrieren wir unser eigenes ClipBoard Format
const
MyClipboardFormatStr = '
MyData';
var
MyClpFormat: integer;
MyClpFormat := RegisterClipboardFormat(MyClipboardFormatStr);
{ The variable SLMClpFormat will contain a unique format handle for
your own clipboard format.
Die Variable SLMClpFormat enthält ein einzigartiges Format Handle
für unser ClipBoard Format.
}
procedure IncPointer(
var p: Pointer; increment: Integer);
begin
p := PChar(p) + Increment;
end;
// Say you have a data record defined as:
// Definiere zuerst etwa einen solchen Daten Record:
type
PMyDataRec = ^TMyDataRec;
TMyDataRec =
record
Name:
string[50];
Value: Integer;
end;
{ Furthermore let's say the data records are stored in a Listbox
and shall be copied to a list box.
Angenommen, die Daten Records sind in einer ListBox gespeichert und
sollen in eine ListBox kopiert werden.
}
// Copy like this:
procedure TForm1.CopyItems;
var
i: integer;
dh: THandle;
ic: integer;
p: Pointer;
pi: pInteger;
begin
// get number of items to be copied
// Die Anzahl zu kopierenden Items
ic := List1.SelCount;
dh := GlobalAlloc(GMEM_FIXED
or GMEM_ZEROINIT,
(SizeOf(TMyDataRec) * ic) + SizeOf(Integer));
{ allocate memory for all items plus for a integer variable giving you the number of
copied items }
p := GlobalLock(dh);
{ Lock the allocated memory }
pi := pInteger(p);
pi^ := ic;
{ write number of items to allocated memory }
IncPointer(p, SizeOf(Integer));
{ increment the pointer behind the written data }
// You don't have to create an instance of clipboard, this is done automatically
for i := 1
to List1.Items.Count
do { check all items if they are selected }
begin
if List1.Items[i - 1].Selected
then
begin
{ This one is selected -> copy it o the clipboard }
PMyDataRec(p)^ := PMyDataRec(List1.Items[i - 1].Data)^;
{ of course data must point to a TMyDataRec }
IncPointer(p, SizeOf(TMyDataRec));
{ increment the pointer behind the written data }
end;
end;
// You have now filled the allocated memory with all items that shall be copied.
// Now you can put them to the clipboard
Clipboard.Open;
{ Open the clipboard will prevent overwriting of so far copied items }
Clipboard.Clear;
{ Clear the clipboard first }
Clipboard.SetAsHandle(MyClpFormat, Dh);
{ Copy to clipboard }
Clipboard.Close;
{ finally close the clipboard }
GlobalUnlock(dh);
{ and unlock the allocate memory. But don't free it, it will be used by the clipboard }
if ic = 0
then
GlobalFree(dh);
{ You can free it if you haven't copied anything }
end;
// Check first if your items are still available before pasting them from the clipbard
if Clipboard.HasFormat(MyClpFormat)
then
begin
Form1.Paste1.Enabled := True;
{ Yes, they are still available }
end;
// And this is, how you paste them after Paste1 is clicked
procedure TMDIForm.Paste1Click(Sender: TObject);
var
dh: THandle;
pdr: PSLMDataRec;
i, ic: integer;
p: Pointer;
pi: pInteger;
li: TListItem;
begin
if Clipboard.HasFormat(MyClpFormat)
then
// We have already checked, but maybe another application has overwritten the
// clipboard in between....
begin
ClipBoard.Open;
{ First open the clipboard again }
dh := Clipboard.GetAsHandle(MyClpFormat);
{ Catch the handle to the stored items }
p := GlobalLock(dh);
{ and lock it }
pi := pInteger(p);
{ The first item is an integer giving the number of items }
ic := pi^;
{ so get the number of items }
IncPointer(p, SizeOf(Integer));
{ increment the pointer behind the read data }
for i := 1
to ic
do { get all copied items one after another }
begin
li := List1.Items.Add;
{ first create a new listbox item }
pdr := New(PMyDataRec);
{ Then create a new pointer to a TMyDataRec }
pdr^ := PMyDataRec(p)^;
{ and fill it with data from the clipboard }
IncPointer(p, SizeOf(TSLMDataRec));
{ increment the pointer behind the written data }
li.Data := pdr;
{ Set the data pointer of the list item to the new record }
LI.Caption := pdr^.
Name;
{ Let the item display the record field "Name" }
// You can of course add more record fields if the item has subitems:
LI.SubItems.Add(IntToStr(Value));
end;
{ All data retrieved from clipboard }
Clipboard.Close;
{ Close it }
GlobalUnlock(dh);
{ and unlock the pointer, but don't free it. This will be done by the clipboard itself,
if necessary }
end;
end;