c#中监控剪贴板的两种方法

最近在做一个云剪贴板的程序,需要用一个c#桌面应用程序来监控剪贴板。本来想的是,新建一个线程用while循环检查剪贴板内容的改动,不过发现不成功,如果用GetText()访问剪贴板则不管剪贴板内有没有文字都返回空字符串,用SetText()设置剪贴板则出错:“在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。”

所以我google了一下,发现貌似监视剪贴板可以不用“幕后线程”去不断检查,有专门的API来进行监视,并通过触发事件来告诉我们。

方法一:

首先要using一个System.Runtime.InteropServices.

然后写下下面的声明:

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

       [DllImport("User32.dll", CharSet = CharSet.Auto)]
       public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
       IntPtr ClipboardViewerNext;
       private void RegisterClipboardViewer()
       {
           ClipboardViewerNext = SetClipboardViewer(this.Handle);
       }

       private void UnregisterClipboardViewer()
       {
           ChangeClipboardChain(this.Handle, ClipboardViewerNext);
       }

然后在Form_Load中进行RegisterClipboardViewer:

        private void Form1_Load(object sender, EventArgs e)
        {
            RegisterClipboardViewer();
        }

然后重写Form.WndProc方法:

        protected override void WndProc(ref Message m)
        {
            switch ((int)m.Msg)
            {
                case 0x308: //WM_DRAWCLIPBOARD
                    {
                        //Do something here..
                        break;
                    }
                default:
                    {
                        base.WndProc(ref m);
                        break;
                    }
            }
        }

然后就OK了。

但是我对这种API调用很不爽,看着十分别扭,而且不google一下的话不可能知道。难道就真的不能用“幕后线程”去监控剪贴板么?

方法二:

答案当然是否定的。经过我的探究,既然访问ClipBoard需要单线程模式,那咱就设一下:

            System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ThreadStart(func));
            th.SetApartmentState(System.Threading.ApartmentState.STA);
            th.Start();

然后在func()方法里写上个while(true)的循环去监视就没有之前的问题了。

  1. 你好,按照你的方法做了测试,代码如下,但是出错,不知道什么问题? 麻烦帮忙看看。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Net.Mail;
    using System.Runtime.InteropServices;

    namespace email
    {
    ///
    /// Interaction logic for MainWindow.xaml
    ///

    public partial class MainWindow : Window
    {
    string textInClipboard = null;
    public MainWindow()
    {
    InitializeComponent();
    }
    private void button1_Click(object sender, RoutedEventArgs e)
    {
    try
    { //using System.Net.Mail; based on .NET 3.5
    SmtpClient smtp = new SmtpClient();
    smtp.Host = "mail.agriview.com.au";
    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
    smtp.Credentials = new System.Net.NetworkCredential("kyle.l@agriview.com.au", "joyce");
    MailMessage mm = new MailMessage("kyle.l@agriview.com.au", "kyle30542@gmail.com");
    mm.Body = "this is the body of email";
    mm.Subject = "mail subject";
    smtp.Send(mm);
    }
    catch
    {
    throw;
    }
    }
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
    System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ThreadStart(viewClipboard));
    th.SetApartmentState(System.Threading.ApartmentState.STA);
    th.Start();
    textInClipboard = Clipboard.GetText();
    }
    private void button2_Click(object sender, RoutedEventArgs e)
    {
    //轮询,改变则弹出
    if (!Clipboard.GetText().Equals(textInClipboard))
    {
    MessageBox.Show(Clipboard.GetText() + "" + textInClipboard);
    textInClipboard = Clipboard.GetText();
    }

    }
    public void viewClipboard()
    {

    while (true)
    {
    try
    {
    string currentTxt = Clipboard.GetText();
    if (currentTxt != textInClipboard)
    {
    //MessageBox.Show(currentTxt);
    button2.Content = currentTxt;
    textInClipboard = currentTxt;
    }
    else
    {
    //MessageBox.Show(Clipboard.GetText());
    }
    }
    catch
    { }

    }
    }

    }
    }

  2. 多谢你这么快的回复。

    提示 “由于其他线程拥有此对象,因此调用线程无法对其进行访问”

    能否给出完整的例子,谢谢。

    第一种方法也好像不行的。提示找不到this.handle方法。

kyle进行回复 取消回复