Title: Component to Monitor Clipboard
Question: Yes I know there are some articles about monitoring clipboard, but what if I need a component to do that?
This is the solution
Answer:
Esteemed friends, right after a quite absence continued, I rewrite another article. Herein occasion I go for evidencing the implementation of a component to capture Windows's clipboard. This component, I have utilized it in a project where it was necessary to have a monitor on the clipboard, examining that tapeworm and on the basis of his contents accomplishing any action.
1. The component it comes from TComponent, no needs visual characteristic and it can be a non-visual control, by means of the following lines:
TClipMonitor = class (TComponent)
2. As we know messages are sent only to windows that they have one handle ( HWnd ) deceiving Windows, I go for creating a handle for my control. This I do it with a private property and overwriting the constructor:
private
FHWnd: HWND;
.
.
constructor TClipMonitor.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FHWnd:=AllocateHWnd (WndMethod);
end;
3. I declare a property Active that he will permit enable or disable the monitor of the clipboard of following manner:
published
property Active: Boolean read FActive write SetActive;
.....
.....
The clipboard has a singular behavior, because he works with a concept of chains, that is to all program that he wishes to monitor the clipboard to he misses a sign and the clipboard's contents, which as it must be driven appropriately according to his needs and next to pass control to the following in the waiting chain, this comes true to it with the method SetActive of the property Active:
procedure TClipMonitor.SetActive(Value: Boolean);
begin
if Value Then
NextInChain := SetClipboardViewer(FHWnd)
else
ChangeClipboardChain(FHWnd, NextInChain);
FActive:=Value;
end;
4. The following method proceeds itself to capture clipboard's message.
procedure TClipMonitor.WndMethod(var Message: TMessage);
var
Remove, Next: Integer;
begin
// MessageDlg('Este es...'+IntToStr (Message.Msg), mtInformation, [mbOK], 0);
case Message.Msg of
WM_DRAWCLIPBOARD:
Begin
if Clipboard.HasFormat(cf_text) then begin
FText:=Clipboard.AsText;
If Assigned (OnChangeClip) Then
Begin
OnChangeClip (Self);
End
end else begin
//do something with other clipboard formats
end;
//pass the message on to the next window
if NextInChain 0 then
SendMessage(NextInChain, WM_DrawClipboard, 0, 0)
End;
// Code to handle a message
WM_CHANGECBCHAIN:
Begin
//MessageDlg('Llega a ENCADENAR', mtInformation, [mbOK], 0);
Remove := Message.WParam;
Next := Message.LParam;
with Message do
if NextInChain = Remove then
NextInChain := Next
else if NextInChain 0 then
SendMessage(NextInChain, WM_ChangeCBChain,Remove, Next)
End;
// Code to handle another message
else
Message.Result := DefWindowProc(FHWnd, Message.Msg, Message.WParam, Message.LParam)
End;
end;
This procedure is the most important because the message is captured, it is determined if the format waited for is text (in my alone application I need to capture texts only), next an own event to pass this information the program that uses the component is launched or fired, this event is OnChangeClip and finally this procedure drives the step of control in the chain for the clipboard.
5. Exist however an important observation to the control, if the application that uses it for some reason does not finalize honestly the code in the event OnChangeClip, application can become blocked or worse still, the clipboard's chain will break, that cause than no other Windows's application, may receive the message that is something new in the clipboard. In order to solve the latter problem, we can change over the order in the code of following manner:
WM_DRAWCLIPBOARD:
Begin
//pass the message on to the next window
if NextInChain 0 then
SendMessage(NextInChain, WM_DrawClipboard, 0, 0);
if Clipboard.HasFormat(cf_text) then begin
FText:=Clipboard.AsText;
If Assigned (OnChangeClip) Then
Begin
OnChangeClip (Self);
End
end else begin
//do something with other clipboard formats
end;
End;
However this does not solve than the application OnChangeClip can stop for a misuse of event. For this reason I prefer leaving original code and to trust the programmer's opinion. I expect suggestions because of this piece of code.
6. Finally the task of cleanliness, by means of the destroyer accomplishing liberation comes true of the handle of fictitious window, with the following code.
destructor TClipMonitor.Destroy;
begin
if FActive Then SetActive (False);
DeallocateHWnd (FHWnd);
inherited Destroy;
end;
In order to have a perspective of control, here, the totality of code, also it can de downloaded. I expect remarks, to improve the control, please share your knowledge with this humble servant. If somebody can suggest like to emigrate this code to :NET I expect his suggestions.