Jump to content
PawelPepe

Delphi Clipboard - WM_CLIPBOARDUPDATE (sent, but no changes)

Recommended Posts

Hey,

I have got a serious problem with detecting Windows Clipboard changes.

I am trying to write simple application that detects clipboard changes and offers to user some actions.

 

To make it work I capture the WM_CLIPBOARDUPDATE message (Of course, I first add listening options -> AddClipboardFormatListener(Handle); which I release when exiting the program -> RemoveClipboardFormatListener(Handle);).
And it works. I respond when the clipboard has an image (Clipboard.HasFormat(CF_PICTURE)) or text (Clipboard.HasFormat(CF_TEXT)).

 

BUT - apparently this message is sent when I run system services (even though the clipboard contents DO NOT CHANGE), e.g.
Computer Management (compmgmt.msc)
Event Viewer (eventvwr.msc)
Performance Monitor (perfmon.msc)
and probably other programs I don't know about. 


Why!!!!?

 

That is, it only happens when the clipboard has some content (if it is empty, nothing happens). If it has text or an image or anything else - my application receives a message about changing the contents of the clipboard (which is in fact the same - nothing changes). Why do these services send WM_CLIPBOARDUPDATE?
Or in other words - what to do to ignore this specific situation (i.e. I receive the message, but I don't want to react - because nothing has changed in the clipboard).
Somehow I don't see anything in the Clipboard implementation in Delphi that would help me...

 

Thanks for any help,

-Pawel

Share this post


Link to post

Windows messes with the clipboard so higher integriity processes do not see/get content put there by lower integrity processes. This may be the source of the extra change messages. The problem tasks you list all run with a High integrity level while most things like File Explorer run with Medium. 

 

Might have to keep track of the clipboard content and check it is has really changed (not just went from empty to having something or the reverse). 

  • Like 1

Share this post


Link to post
59 minutes ago, PawelPepe said:

Why!!!!?

I used ApiMonitor to track this behavior, the result of all clipboard functions called for MMC.exe :

image.thumb.png.6dfc5f7011d8c17d29c888e5e0f0396a.png

 

One function in particular is the culprit so i tested it and found 

SetClipboardViewer(0); // invalid handle here

This will trigger sending WM_CLIPBOARDUPDATE to all registered handlers, mmc is calling it, i think many of these system administration tools will call it too.

 

1 hour ago, PawelPepe said:

what to do to ignore this specific situation

Save the clipboard content or part of it and compare for changes on every WM_CLIPBOARDUPDATE.

  • Like 1

Share this post


Link to post

@Brian Evans

@Kas Ob.

 

Thanks, good to know. Yes, I think I will have to think about some compare data system, to check if clipboard data really changed.

 

@Attila Kovacs

OK Captain!

 

Here is a simple code that demonstrate the problem:

 

unit Main_Form;

interface

uses ...;


type
  TMainFrm = class(TForm)
  
  ...
  
  private
      procedure MESSAGE_WM_CLIPBOARDUPDATE(var Msg: TMessage); message WM_CLIPBOARDUPDATE;
          { Private declarations }
  public
    { Public declarations }
  end;
  
implementation

{$R *.dfm}

uses ...;



procedure TMainFrm.MESSAGE_WM_CLIPBOARDUPDATE(var Msg: TMessage);
var
   Success : boolean;
   RetryCount : integer;
begin
   Inherited;
   
   if ALLOW_WM_CLIPBOARDUPDATE = True then 
      begin
         RetryCount := 0;
         Success := False;
         while Success = False do
            begin
               try
                  Success := True;

                  if (Clipboard.HasFormat(CF_PICTURE) OR Clipboard.HasFormat(CF_TEXT)) then
                     begin
						// ACTION!!!!
						// Unfortunatelly, this is fired even when clipboard content not change - but message is received
                     end;

                  except
                     on E: EClipboardException do
                        begin
                           Inc(RetryCount);
                           if RetryCount < 3 then
                              begin
                                 Sleep(RetryCount * 100);
                              end
                           else
                              begin
                                 //raise Exception.Create('Cannot set clipboard after three attempts');
                              end
                        end
                     else
                        begin
                           //raise;  // if not a clipboard problem then re-raise
                        end;
               end;
            end;
      end;
end;


procedure TMainFrm.FormCreate(Sender: TObject);
begin
   AddClipboardFormatListener(Handle);
end;

procedure TMainFrm.FormDestroy(Sender: TObject);
begin
   RemoveClipboardFormatListener(Handle);
end;

 

-Pawel

Share this post


Link to post

Try using GetClipboardSequenceNumber() on each message to check if the clipboard content has actually changed. 

 

Also, the OnCreate/OnDestroy events are not the best place to register/remove your listener. Those events are tied to the lifetime of the Form object, not its HWND window, which may be recreated dynamically during the Form's lifetime. You should instead override the Form's virtual CreateWnd() and DestroyWnd() methods. 

  • Like 1

Share this post


Link to post

Yes, it does. That is showing you that the sequence number isn't changing,which means the clipboard content is not changing. You are just getting spurulous messages. So check the sequence number on each message and if it hasn't changed value since the last time you called it then ignore the message. 

  • Like 1
  • Thanks 1

Share this post


Link to post
Posted (edited)

@Remy Lebeau

 

Yes, I will change it and create virtual CreateWnd() and DestroyWnd() methods (I read about it somwhere in StackOverFlow, I think).

 

@Remy Lebeau @Kas Ob.

I checked GetClipboardSequenceNumber(). Indeed, it is incremeneted when Clipboard change - but not in our situation, as Clipboard contents is not changing, only message is sent.

 

EDIT: I see your answer, Remy - I think you may have right. Will have to test it more. If not, then will do some comparison.

 

I will have to find some good way to compare last Clipboard Content and every next one. If it differs - make action - if not, ignore.

Hmm, maybe I will write it into disk and calculate hash. 

-Pawel

Edited by PawelPepe

Share this post


Link to post
19 minutes ago, Remy Lebeau said:

Yes, it does.

I have no idea why i wrote "doesn't".

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×