剪贴板更改通知?

时间:2011-06-23 17:17:54

标签: wpf windows winforms clipboard

我知道如何将内容放入剪贴板并从剪贴板中检索内容。

但是,在这两个操作之间,可以通过另一个操作来更改剪贴板的内容。

当有任何应用程序修改剪贴板时,有没有办法得到通知?

4 个答案:

答案 0 :(得分:20)

我知道这个答案是迟到的你需要添加的唯一参考是wpf应用程序中的windows froms。我创建了一个我在互联网上找到的功能的包装器。大多数示例比我需要的更多,所以我决定创建自己的类。我喜欢隔离问题所以这个类只是在剪贴板更改时监听并向您提供剪贴板上的数据类型。例如它是文本吗?一个图像?或者什么?

无论如何,这是我的包装:

using System;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;

public static class ClipboardMonitor 
{
    public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
    public static event OnClipboardChangeEventHandler OnClipboardChange;

    public static void Start()
    {
        ClipboardWatcher.Start();
        ClipboardWatcher.OnClipboardChange += (ClipboardFormat format, object data) =>
        {
            if (OnClipboardChange != null)
                OnClipboardChange(format, data);
        };
    }

    public static void Stop()
    {
        OnClipboardChange = null;
        ClipboardWatcher.Stop();
    }

    class ClipboardWatcher : Form
    {
        // static instance of this form
        private static ClipboardWatcher mInstance;

        // needed to dispose this form
        static IntPtr nextClipboardViewer;

        public delegate void OnClipboardChangeEventHandler(ClipboardFormat format, object data);
        public static event OnClipboardChangeEventHandler OnClipboardChange;

        // start listening
        public static void Start()
        {
            // we can only have one instance if this class
            if (mInstance != null)
                return;

            Thread t = new Thread(new ParameterizedThreadStart(x =>
            {
                Application.Run(new ClipboardWatcher());
            }));
            t.SetApartmentState(ApartmentState.STA); // give the [STAThread] attribute
            t.Start();
        }

        // stop listening (dispose form)
        public static void Stop()
        {
            mInstance.Invoke(new MethodInvoker(() =>
            {
                ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);
            }));
            mInstance.Invoke(new MethodInvoker(mInstance.Close));

            mInstance.Dispose();

            mInstance = null;
        }

        // on load: (hide this window)
        protected override void SetVisibleCore(bool value)
        {
            CreateHandle();

            mInstance = this;

            nextClipboardViewer = SetClipboardViewer(mInstance.Handle);

            base.SetVisibleCore(false);
        }

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        // defined in winuser.h
        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    ClipChanged();
                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;

                case WM_CHANGECBCHAIN:
                    if (m.WParam == nextClipboardViewer)
                        nextClipboardViewer = m.LParam;
                    else
                        SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;

                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        static readonly string[] formats = Enum.GetNames(typeof(ClipboardFormat));

        private void ClipChanged()
        {
            IDataObject iData = Clipboard.GetDataObject();

            ClipboardFormat? format = null;

            foreach (var f in formats)
            {
                if (iData.GetDataPresent(f))
                {
                    format = (ClipboardFormat)Enum.Parse(typeof(ClipboardFormat), f);
                    break;
                }
            }

            object data = iData.GetData(format.ToString());

            if (data == null || format == null)
                return;

            if (OnClipboardChange != null)
                OnClipboardChange((ClipboardFormat)format, data);
        }


    }
}

public enum ClipboardFormat : byte
{
    /// <summary>Specifies the standard ANSI text format. This static field is read-only.
    /// </summary>
    /// <filterpriority>1</filterpriority>
    Text,
    /// <summary>Specifies the standard Windows Unicode text format. This static field
    /// is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    UnicodeText,
    /// <summary>Specifies the Windows device-independent bitmap (DIB) format. This static
    /// field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Dib,
    /// <summary>Specifies a Windows bitmap format. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Bitmap,
    /// <summary>Specifies the Windows enhanced metafile format. This static field is
    /// read-only.</summary>
    /// <filterpriority>1</filterpriority>
    EnhancedMetafile,
    /// <summary>Specifies the Windows metafile format, which Windows Forms does not
    /// directly use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    MetafilePict,
    /// <summary>Specifies the Windows symbolic link format, which Windows Forms does
    /// not directly use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    SymbolicLink,
    /// <summary>Specifies the Windows Data Interchange Format (DIF), which Windows Forms
    /// does not directly use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Dif,
    /// <summary>Specifies the Tagged Image File Format (TIFF), which Windows Forms does
    /// not directly use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Tiff,
    /// <summary>Specifies the standard Windows original equipment manufacturer (OEM)
    /// text format. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    OemText,
    /// <summary>Specifies the Windows palette format. This static field is read-only.
    /// </summary>
    /// <filterpriority>1</filterpriority>
    Palette,
    /// <summary>Specifies the Windows pen data format, which consists of pen strokes
    /// for handwriting software, Windows Forms does not use this format. This static
    /// field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    PenData,
    /// <summary>Specifies the Resource Interchange File Format (RIFF) audio format,
    /// which Windows Forms does not directly use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Riff,
    /// <summary>Specifies the wave audio format, which Windows Forms does not directly
    /// use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    WaveAudio,
    /// <summary>Specifies the Windows file drop format, which Windows Forms does not
    /// directly use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    FileDrop,
    /// <summary>Specifies the Windows culture format, which Windows Forms does not directly
    /// use. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Locale,
    /// <summary>Specifies text consisting of HTML data. This static field is read-only.
    /// </summary>
    /// <filterpriority>1</filterpriority>
    Html,
    /// <summary>Specifies text consisting of Rich Text Format (RTF) data. This static
    /// field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Rtf,
    /// <summary>Specifies a comma-separated value (CSV) format, which is a common interchange
    /// format used by spreadsheets. This format is not used directly by Windows Forms.
    /// This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    CommaSeparatedValue,
    /// <summary>Specifies the Windows Forms string class format, which Windows Forms
    /// uses to store string objects. This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    StringFormat,
    /// <summary>Specifies a format that encapsulates any type of Windows Forms object.
    /// This static field is read-only.</summary>
    /// <filterpriority>1</filterpriority>
    Serializable,
}

我知道这可能会有很多但是在包装之后它看起来应该是这样的: enter image description here

然后你将该课程用作:

    static void Main(string[] args)
    {

        ClipboardMonitor.Start();

        ClipboardMonitor.OnClipboardChange += new ClipboardMonitor.OnClipboardChangeEventHandler(ClipboardMonitor_OnClipboardChange);

        Console.Read();

        ClipboardMonitor.Stop(); // do not forget to stop



    }

    static void ClipboardMonitor_OnClipboardChange(ClipboardFormat format, object data)
    {
        Console.WriteLine("Clipboard changed and it has the format: "+format.ToString());
    }

答案 1 :(得分:4)

我所能找到的只是用C#/ VB.NET编写的Clipboard Monitor。我看到WPF和WinForms,所以我假设这是一个可行的选择。

从user32 dll中获取pinvoking一些方法。

修改

编辑时,上面的原始链接已损坏。这是一个archive.org snapshot

答案 2 :(得分:1)

  

然而,在这两个操作之间,可能是另一个操作   更改剪贴板内容的操作。

当应用程序调用OpenClipboard()时,其他任何应用程序都无法使用剪贴板。一旦锁定剪贴板的应用程序调用CloseClipboard(),那么任何应用程序都可以使用并锁定剪贴板。

  

当有任何应用程序修改时,是否有通知的方法   剪贴板?

是。请参阅API SetClipboardViewer()和消息WM_DRAWCLIPBOARD和WM_CHANGECBCHAIN。

此处有更多信息:http://msdn.microsoft.com/en-us/library/ms649016(v=vs.85).aspx#_win32_Adding_a_Window_to_the_Clipboard_Viewer_Chain

答案 3 :(得分:0)

这是我几年前写的一篇文章,详细介绍了剪贴板,甚至通过Windows API进行监控: http://www.clipboardextender.com/developing-clipboard-aware-programs-for-windows/6 请特别注意“常见错误”部分。几乎没有人第一次这样做。