首页  编辑  

自定义剪切板数据格式

Tags: /超级猛料/OS.操作系统/Clipboard.剪贴板/   Date Created:

{ How to copy/paste custom items to/from  the clipboard
}
// 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
// This can be done ny a Windows API function (unit ShellAPI)
const
MyClipboardFormatStr = 'MyData';
var
MyClpFormat : integer;
MyClpFormat:=RegisterClipboardFormat(MyClipboardFormatStr);
// The variable SLMClpFormat will contain a unique format handle for
// your own clipboard format.
// Then you can start copy items to the clipboard. You will need a
// function for pointer incrementation which is given here:
procedure IncPointer(var p : Pointer;increment : integer);
begin
 p:=PChar(p)+Increment;
end;
// Say you have a data record defined as
type
PMyDataRec = ^TMyDataRec;
TMyDataRec = record
 Name : string[50];
 Value : integer;
end;
// This will work of course also with other types
// Furthermore let's say the data records are stored in a Listbox
// and shall be copied to a list box.
// Copy like this:
procedure TForm1.CopyItems;
 var
 i : integer;
 dh : THandle;
 ic : integer;
 p : Pointer;
 pi : pInteger;
begin
 ic:=List1.SelCount; { get number of items to be copied }
 dh:=GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,(SizeOf(TMyDataRec)*ic)+SizeOf(Integer));
 { alloc 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;