clipboard Listener event is being called twice

2020-07-17 14:41发布

问题:

i want to save the changes in my clipboard. so i registered my application to get all the changes that happens to the Clipboard.

Using

    [DllImport("User32.dll")]
    protected static extern bool AddClipboardFormatListener(int hwnd);

and then

protected override void WndProc(ref Message m)
    {
switch (m.Msg)
        {
            case WM_CLIPBOARDUPDATE:
                OnClipboardChanged();
                break;
             ...
        }
     }

private void OnClipboardChanged()
{
    if (Clipboard.ContainsText())
        {
         MessageBox.Show(Clipboard.GetText().ToString());
        }
}

The Problem is: When copying text from an application like visual studio or firefox, the OnClipboardChanged() function will be called twice or 3 times sometimes.

I think that those application will write the Data to the clipboard with different formats, this is why the function is called more than once. But how would i prevent saving the same data because OnClipboardChanged() is being called more than once ?

回答1:

Because they're opening/closing the clipboard multiple times. I've seen such madness before. Excel used to perform 24 separate operations when copying a chart.
Instead of this (pseudocode):

openClipboard
for each format {
  place data on clipboard(format)
}
closeClipboard

they're probably doing this:

for each format {
  openClipboard
  place data on clipboard(format)
  closeClipboard
}

Update: The usual mitigation strategy is to avoid reacting to every update, and react to the LAST update after a reasonable "settle time" has elapsed with no further clipboard notifications. 500ms will usually be more than adequate.



回答2:

Prevent multiple calls to the clipboard

private int _i = 0;
private int i
{
    get
    {
        async void setI()
        {
            await Task.Run(() =>
            {
                Thread.Sleep(20);
                i = 0;
            }
            );
        }
        setI();
        return _i;
    }
    set
    {
        _i = value;
    }
}
private IntPtr HwndHandler(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
    if (msg == WM_CLIPBOARDUPDATE)
    {
        if(i<1)
        {
            this.ClipboardUpdate?.Invoke(this, new EventArgs());
            i++;
        }
    }
    handled = false;
    return IntPtr.Zero;
}


标签: c# clipboard