PawelPepe 1 Posted May 25 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
Brian Evans 105 Posted May 25 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). 1 Share this post Link to post
Kas Ob. 121 Posted May 25 59 minutes ago, PawelPepe said: Why!!!!? I used ApiMonitor to track this behavior, the result of all clipboard functions called for MMC.exe : 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. 1 Share this post Link to post
PawelPepe 1 Posted May 25 @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
Remy Lebeau 1392 Posted May 25 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. 1 Share this post Link to post
Kas Ob. 121 Posted May 25 1 hour ago, Remy Lebeau said: Try using GetClipboardSequenceNumber() on each message to check if the clipboard content has actually changed. It doesn't help. 1 Share this post Link to post
Remy Lebeau 1392 Posted May 25 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. 1 1 Share this post Link to post
PawelPepe 1 Posted May 25 (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 May 25 by PawelPepe Share this post Link to post
PawelPepe 1 Posted May 25 @Remy Lebeau It works! Thank you! @Brian Evans, @Kas Ob. Thanks for help! 1 Share this post Link to post
Kas Ob. 121 Posted May 25 19 minutes ago, Remy Lebeau said: Yes, it does. I have no idea why i wrote "doesn't". Share this post Link to post