Rob,
Yes I asked the wrong question! What I meant to ask was as I
obviously have to place things back on the clipboard that are in a specially
registered format, how do I do that not knowing what the format is? I
haven't found anyway to use the numeric constants for these special
types...it seems you need to know the CF_ constant type? And there is no
listing I can find to use for converting from one to the other! Also, how
can I save what is on the clipboard to a stream so it can be loaded into a
blob along with it's format type so I can then load it back into the
clipboard later? There's nothing in the Clipbrd unit that I can use for
that.
Since I only seem to be able to get the format in a numeric value, I
guess I'll have to set up a name=value pair or something like that that I
can refer to in code to get the exact format and then save that in it's CF_
form as a string value in my dB so that I know what format it is when I
reload the clipboard. As per the code included in the first part of this
thread I have to then get the format as a THandle. Does that sound right or
is there a simpler way?
And finally, also from the code, I have to use a pointer to the data
on the clipboard and save that to a stream and back again. But try as I
might I do not seem to be able to get the syntax correct for doing this.
I've read and re-read the sections on using pointers but I'm missing
something! I can get the size of the buffer needed via the included
procedure ok, but that's it. Here's the entire .pas file to the component:
////////////////////// code begins /////////////////////////////////////
unit EnhancedClipboard;
{ Enhanced Clipboard Component
============================
Author: Chaos
License: Free for everyone to use regardless of purpose on the
condition that all improvements are fed back to the
community.
Disclaimer: USE AT OWN RISK. I COMPLETLY WASH MY HANDS OF ANY LIABLITY
OR RESPONSIBILITY IF YOU USE THIS CODE. YOUR ON YOUR OWN.
Provides easy access to all the features of the windows clipboard
including notifications and custom formats.
The component does not try to duplciate what the delphi TClipboard
does, but tries to pick up where it left off and enhance its use by
being a component which TClipbaord isnt, and by providng some methods
to which make life easier.
The delphi TClipboard is provided via a property for ease of use
for standard functionlity or thru the ClipBrd unit.
This unit provides three new methods of note:
NB all these methods assume Memory handles only, but this seems to be
the
norm.
CopyDataToClipBoard
This method takes a pointer to some data, and a size, and
will alloc global memory, copy the data from pointer to the
global memory, and add it to the clipboard with the format specified.
CopyDataFromClipboard
You must provide a preAllocated memory pointer, a valid format which
can be found out thru the standard TClipboard class, and a size. See
the DataSize method for a way to get the size.
It will fetch the pointer from the clipboard, validate it, and
then copy it to the pointer specified.
DataSize
Gets the data size by using GlobalSize.
The component also provides an Event, the OnChange event. This event
fires whenever the clipboard contents change. It also provides the
formats in the form of a list of words, but they are also availble thru
the standard TClipboard which is passed to the event.
Use:
Just drop Component onto a form, set the property NotifyOnChange,
and if applicable an event handler as per normal.
Examples:
1) Example of event handler:
Procedure TGridLayout.EnhancedClipboardChange(Sender: TComponent;
Clipboard: TClipboard;
FormatsAvailable: TList;
var
NotifyOtherApplications: Boolean);
begin
if FormatsAvailable.IndexOf(Pointer(CF_TEXT)) > -1 then
MyAction.Enabled := true
else
MyAction.Enabled := false;
end;
2) Example of copying to the clip board. We will copy a string.
if Length(MyString) > 0 then
EnhancedClipboard.CopyDataToClipboard(CF_TEXT, Pointer(MyString),
length(MyString)-1);
3) Example of pasting from the clipboard. We will use CF_TEXT;
if (EnhancedClipboard.Clipboard.HasFormat(CF_TEXT)) then
begin
Size := EnhancedClipboard.DataSize(CF_TEXT);
if (Size > 0) then
begin
SetLength(MyString, Size);
EnhancedClipboard.CopyDataFromClipboard(CF_TEXT,
Pointer(MyString), Size);
ProcessMyString(MyString);
end;
end;
-- OutStanding issue, doest read clip board on create cause onchange isnt
assigned.
}
interface
uses
Windows, Messages, SysUtils, Classes, clipbrd;
type
TEnhClipboardNotifyProc = Procedure(Sender: TComponent;
Clipboard: TClipboard;
FormatsAvailable: TList;
var NotifyOtherApplications: boolean)
of object;
TEnhancedClipboard = class(TComponent)
private
{ Private declarations }
FNextInChain: THandle;
FOnChange: TEnhClipboardNotifyProc;
FHandle: HWND;
FNotifyOnChange: boolean;
Procedure WndProc(var Msg: TMessage);
protected
{ Protected declarations }
Procedure WMDrawClipboard(var Msg: TWMDrawClipboard); {message
WM_DrawClipboard;}
Procedure WMChangeCBChain(var Msg: TWMChangeCBChain); {message
WM_ChangeCBChain;}
Procedure SetNotifyOnChange(Value: Boolean);
Function GetClipBoard: TCLipboard;
Function GetFormatsAsList: TList;
public
{ Public declarations }
Constructor Create(AOwner: TComponent); override;
Destructor Destroy; override;
Procedure CopyDataToClipboard(Format: word; Data: Pointer; Size:
Longint);
Function DataSize(Format: word): longint;
Function CopyDataFromClipboard(Format: word; Data: Pointer; Size:
longint): Pointer;
{ Property Handle: THandle read FHandle write FHandle;}
published
{ Published declarations }
Property NotifyOnChange: boolean read FNotifyOnChange write
SetNotifyOnChange;
Property OnChange: TEnhClipboardNotifyProc read FOnChange write
FOnChange;
Property Clipboard: TClipboard read GetClipBoard;
end;
procedure Register;
implementation
uses Forms, Math;
Function GetErrorStr: PChar;
var lpMsgBuf: pointer;
begin
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
nil,
GetLastError(),
0,
@lpMsgBuf,
0,
nil
);
Result := PChar(lpMsgBuf);
end;
Constructor TEnhancedClipboard.Create(AOwner: TComponent);
var Msg: TWMDRAWCLIPBOARD;
begin
inherited Create(AOwner);
{ Allocate a window Handle for messages }
FHandle := Classes.AllocateHWnd(WndProc);
{ Update the app about whats on the clip board now we wont be notified
until a change occurs }
with ClipBrd.Clipboard do
try
open;
if ClipBrd.Clipboard.FormatCount > 0 then
WMDrawClipboard(Msg);
finally
close;
end;
end;
Destructor TEnhancedClipboard.Destroy;
begin
Classes.DeAllocateHWnd(FHandle);
inherited Destroy;
end;
Procedure TEnhancedClipboard.WMDrawClipboard(var Msg: TWMDrawClipboard);
var Formats: TList;
NotifyOtherApps: boolean;
begin
Formats := nil;
if assigned(OnChange) then
begin
try
{ Get all the formats as a set }
Formats := GetFormatsAsList;
{ Set the notify other apps to true by default }
NotifyOtherApps := true;
{ Trigger the Event }
OnChange(Self, Clipboard, Formats, NotifyOtherApps);
if (NotifyOtherApps) and
(FNextInChain <> 0) then
PostMessage(FNextInChain, WM_DrawClipboard, 0, 0);
finally
Formats.Free;
end;
end;
inherited;
end;
Procedure TEnhancedClipboard.WMChangeCBChain(var Msg: TWMChangeCBChain);
begin
with Msg do
begin
if FNextInChain = Remove then
FNextInChain := Next
else
if FNextInChain <> 0 then
PostMessage(FNextInChain, WM_ChangeCBChain, Remove, Next);
end;
inherited;
end;
Procedure TEnhancedClipboard.SetNotifyOnChange(Value: boolean);
begin
assert(FHandle > 0, 'Handle must never be 0. Please Assign a handle or
left the application handle default in');
FNotifyOnChange := Value;
if (FNotifyOnChange) then
begin
if not (csDesigning in ComponentState) then
FNextInChain := SetClipboardViewer(FHandle)
end
else
ChangeClipboardChain(FHandle, FNextInChain);
end;
Function TEnhancedClipboard.GetFormatsAsList: TList;
var i: longint;
begin
Result := TList.Create;
with Result do
begin
Capacity := ClipBrd.Clipboard.FormatCount;
for i := 0 to Capacity do
Result.Add(Pointer(ClipBrd.Clipboard.Formats[i]));
end;
end;
Function TEnhancedClipboard.GetClipBoard: TClipboard;
begin
Result := clipbrd.Clipboard;
end;
Procedure TEnhancedClipboard.CopyDataToClipboard(Format: word; Data:
pointer; Size: longint);
var ClipData: THandle;
begin
ClipData := 0;
Assert(Data <> nil, 'You must provide a preallocated pointer');
Assert(Size > 0, 'You must specify the size of the memory block pointer
to by Data');
Assert(Format > 0, 'You must provide a valid format');
with ClipBrd.Clipboard do
try
Open;
try
try
ClipData := GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE, Size);
Move(Data^, GlobalLock(ClipData)^, Size);
SetAsHandle(Format, ClipData);
finally
if ClipData <> 0 then
GlobalUnlock(ClipData);
end;
except
if ClipData <> 0 then
GlobalFree(ClipData);
raise;
end;
finally
Close;
end;
end;
Function TEnhancedClipboard.DataSize(Format: Word): longint;
var ClipData: THandle;
Flags: longint;
begin
Result := 0;
Assert(Format > 0, 'You must provide a valid format');
with ClipBrd.Clipboard do
begin
try
Open;
if HasFormat(Format) then
begin
ClipData := GetAsHandle(Format);
Flags := GlobalFlags(ClipData);
if not (Flags AND GMEM_DISCARDED = GMEM_DISCARDED) then
Result := GlobalSize(ClipData);
end;
finally
Close;
end;
end;
end;
Function TEnhancedClipboard.CopyDataFromClipboard(Format: word; Data:
Pointer; Size: longint): pointer;
var ClipData: THandle;
ClipDataSize, BufferSize, Flags: Longint;
begin
Result := nil;
Assert(Data <> nil, 'You must provide a preallocated pointer');
Assert(Size > 0, 'You must specify the size of the memory block pointer
to by Data');
Assert(Format > 0, 'You must provide a valid format');
with ClipBrd.Clipboard do
begin
try
Open;
if HasFormat(Format) then
begin
ClipData := GetAsHandle(Format);
Flags := GlobalFlags(ClipData);
if not (Flags AND GMEM_DISCARDED = GMEM_DISCARDED) then
ClipDataSize := GlobalSize(ClipData)
else
raise Exception.Create('Clipboard Data Invalid');
BufferSize := Min(Size, ClipDataSize);
try
Move(GlobalLock(ClipData)^, Data^, BufferSize);
finally
GlobalUnlock(ClipData);
end;
end
else
raise Exception.Create('Format not availble on clipboard');
finally
Close;
end;
end;
end;
Procedure TEnhancedClipboard.WndProc(var Msg: TMessage);
var WMDrawClipboardMsg: TWMDrawClipboard absolute Msg;
WMChangeCBChainMsg: TWMChangeCBChain absolute Msg;
begin
case Msg.Msg of
WM_DRAWCLIPBOARD: WMDrawClipboard(WMDrawClipboardMsg);
WM_CHANGECBCHAIN: WMChangeCBChain(WMChangeCBChainMsg);
else
DefWindowProc(FHandle, Msg.Msg, Msg.WParam, Msg.LParam);
end;
end;
procedure Register;
begin
RegisterComponents('Utils', [TEnhancedClipboard]);
end;
end.
/////////////////////// code ends //////////////////////////////////////
>From "Robert Meek"
Personal e-mail: [EMAIL PROTECTED]
dba / "Tangentals Design"
Visit us at: www.TangentalsDesign.com
Home of "The Keep"!
Member of: "Association of Shareware Professionals"
Moderator for: "The Delphi", "Delphi-DB", and "Delphi-Talk" programming
lists at elists.org,
and proud to be a donator to the Jedi VCL 3.0.
-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf
Of Rob Kennedy
Sent: Tuesday, April 12, 2005 12:50 AM
To: Borland's Delphi Discussion List
Subject: Re: Oh boy...need pointer help...addendum!
Robert Meek wrote:
> So when ever the info on the Windows Clipboard changes, and this
> project is running, aform pops up with a listbox on it displaying line by
> line all clipboard formats currently available, but in integer form.
> Checking the Windows.pas file I found the constants for Clipboard formats,
> and I was able to verify that it was working correctly...for example when
I
> would copy plain text to the clipboard the CF_TEXT constant would be
> enumerated, and for a bmp file, the CF_METAFILEPICT, CF_DIB,
CF_ENHMETAFILE,
> CF_BITMAP, and CF_ENHMETAFILE were listed. But along with these obvious
> formats, there were also listed a number of 5 digit formats for which no
> constants can be found. Could these perhaps be specially registered
formats
> that are used by such as Office applications, and/or other image editors,
> etc.?
Yes. Custom clipboard formats are assigned IDs between $c000 and $ffff.
> And if they are, how can I find out exactly what they are
To get the name used to register those formats, call
GetClipboardFormatName. That's all you can get from the OS, though. The
only thing the OS knows about a clipboard format is the name and ID used
to register it. Other than that, the format is dictated entirely by the
applications that need to use it.
> and if I
> would need to load back to the clipboard using these special formats if I
> want the registering applications to be able to make use of them?
I think you answered your own question. Do you honestly expect an
application to be able to make use of the format if you *don't* load the
information back onto the clipboard?
> I also noticed that when I copied a jpg file to the clipboard, I got
> the same exact list of constant references as I did for the bmp file. Are
> all picture/image types represented on the clipboard as bmp's? And if so
> when pasted back into an application, how does it know it's a jpg at all?
How did you copy it?
> In any case, the questions and request for help made in the first
> message of this thread still goes.
There was in fact no question in the first message. Can you be a little
more specific about what you're having trouble with? What have you
tried, and how has it failed?
--
Rob
_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi
_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi