如何在C#中监视剪贴板内容的更改?

45
我希望我的C#程序具有以下功能:当用户执行Ctrl+C或在任何地方复制内容时(即剪贴板内容更改时),程序将得到通知,检查该内容是否符合某些条件,如果是,则成为活动程序,并处理内容等。
我可以从System.Windows.Forms.Clipboard中获取内容,但我不知道如何监视来自剪贴板的内容更改。
如果使用Windows Vista或更高版本,请使用AddClipboardFormatListener,如John Knoeller的答案所示;对于Windows XP,我必须使用旧的、更脆弱的SetClipboardViewer API,如接受的答案所示。

1
如何在WPF中实现,请参考此链接:https://dev59.com/OXRB5IYBdhLWcg3wcm6d#33018459 - marbel82
SharpClipboard作为一个库,可能会更有益,因为它将相同的功能封装在一个组件库中。然后您可以访问其“ClipboardChanged”事件,并在剪切/复制时检测各种数据格式。 - Willy Kimura
4个回答

57
我编写了一个小型实用程序类,使用 AddClipboardFormatListener 函数仅消息窗口 来实现这一功能。
/// <summary>
/// Provides notifications when the contents of the clipboard is updated.
/// </summary>
public sealed class ClipboardNotification
{
    /// <summary>
    /// Occurs when the contents of the clipboard is updated.
    /// </summary>
    public static event EventHandler ClipboardUpdate;

    private static NotificationForm _form = new NotificationForm();

    /// <summary>
    /// Raises the <see cref="ClipboardUpdate"/> event.
    /// </summary>
    /// <param name="e">Event arguments for the event.</param>
    private static void OnClipboardUpdate(EventArgs e)
    {
        var handler = ClipboardUpdate;
        if (handler != null)
        {
            handler(null, e);
        }
    }

    /// <summary>
    /// Hidden form to recieve the WM_CLIPBOARDUPDATE message.
    /// </summary>
    private class NotificationForm : Form
    {
        public NotificationForm()
        {
            NativeMethods.SetParent(Handle, NativeMethods.HWND_MESSAGE);
            NativeMethods.AddClipboardFormatListener(Handle);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == NativeMethods.WM_CLIPBOARDUPDATE)
            {
                OnClipboardUpdate(null);
            }
            base.WndProc(ref m);
        }
    }
}

internal static class NativeMethods
{
    // See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
    public const int WM_CLIPBOARDUPDATE = 0x031D;
    public static IntPtr HWND_MESSAGE = new IntPtr(-3);

    // See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool AddClipboardFormatListener(IntPtr hwnd);

    // See http://msdn.microsoft.com/en-us/library/ms633541%28v=vs.85%29.aspx
    // See http://msdn.microsoft.com/en-us/library/ms649033%28VS.85%29.aspx
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
}

这个类假设通知在应用程序的生命周期内始终是需要的,但可以通过RemoveClipboardFormatListener函数进行修改,以便在需要时取消订阅。


很好。你是否将XP也纳入其中了? - tofutim
@tofutim 不,我不确定XP机器上有哪些可用的API可以做到这一点。 - Justin
这是针对XP的 - Nilay Vishwakarma
1
同样地,您也可以尝试使用SharpClipboard。它提供了一个ClipboardChanged事件,允许您在剪切/复制各种数据格式时过滤它们并获取剪贴板内容。 - Willy Kimura
注意:在退出应用程序之前,您应该始终从剪贴板通知更改中删除窗口。 - dynamichael

16

您可以使用pinvoke调用Win32 API AddClipboardFormatListener 来实现这一功能。

监听器是一个窗口句柄(Form.Handle),窗体将通过 WM_CLIPBOARDUPDATE 通知接收剪贴板更改。

它是旧版 API SetClipboardViewer 的更可靠替代品。


谢谢。但在 MSDN 页面上, 这个 API 的最低操作系统要求是 Vista。这是真的吗?(我仍然在使用 XP。实际上,我的用户也将使用 XP。) - Weiming
2
是的,最低要求是Vista。如果您使用的是XP,则除了使用SetClipboarViewer之外别无选择。请注意,SetClipboardViewer很脆弱,尽管如果您的代码正确且您是唯一的查看者,则不应该有任何问题。 - John Knoeller
好的,我会非常谨慎。否则您的答案将是最好的。谢谢! - Weiming

14

10
SetClipboardViewer是一个脆弱而陈旧的API,您不应在新代码中使用它。请改用AddClipboardFormatListener。 - John Knoeller
1
同样地,您也可以尝试使用SharpClipboard。它提供了一个ClipboardChanged事件,允许您在剪切/复制各种数据格式时过滤它们并获取剪贴板内容。 - Willy Kimura
2
第二个链接已经失效。 - Peter Mortensen

3

这也是一个很好的例子。谢谢! - Weiming

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接