Мониторинг буфера обмена

      ОС Windows поддерживает список, или цепь, приложений, которые обратились с просьбой получить уведомление, когда данные поступят в буфер обмена. Каждый раз, когда в буфере обмена изменяются данные, первое приложение в этой цепочке получает сообщение - WM_DRAWCLIPBOARD. Приложения могут запросить тип данных в буфере обмена, например RTF, ASCII текст, и др. Так как нет управляемых (. NET) API для добавления приложения в цепочку, чтобы получить уведомление об изменении буфера обмена, необходимо воспользоваться Win32 SetClipboardViewer.
Есть несколько правил при использовании этой функции.
      • При вызове SetClipboardViewer, необходимо пройти дескриптор окна, которое будет получать сообщение WM_DRAWCLIPBOARD. SetClipboardViewer функция возвращает первое приложение в цепочке. Ваше приложение должно хранить в классе членов, потому что каждое приложение которое получает сообщение WM_DRAWCLIPBOARD может отправить то же сообщение к следующему приложению в цепочке (через функцию SendMessage).
      • WM_CHANGECBCHAIN. Каждое приложение, которое обрабатывает WM_DRAWCLIPBOARD, отвечает за отправку сообщения к следующему приложению в цепочке, оно также должно знать, когда изменилась цепь. К
огда приложение удаляет себя из цепочки, буфер обмена посылает сообщения WM_CHANGECBCHAIN.
      • При завершении работы необходимо удалить приложение из цепочки. Эта задача решается с помощью функции Win32ChangeClipboardChain.
      Создайте проект Windows Form и разместите элемент управления richTextBox из панели элементов. В свойстве ForeColor данного элемента управления необходимо установить цвет Black. Перейдите в листинг главной формы, нажав на клавиатуре клавишу F7. Добавьте приведенный ниже листинг.
IntPtr nextClipboardViewer;

public Form1()
{
    InitializeComponent();
    nextClipboardViewer = (IntPtr)SetClipboardViewer((int)
                this.Handle);
}
[DllImport("User32.dll")]
  protected static extern int
            SetClipboardViewer(int 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);

protected override void WndProc(ref System.Windows.Forms.Message m)
{              
    const int WM_DRAWCLIPBOARD = 0x308;
    const int WM_CHANGECBCHAIN = 0x030D;

    switch (m.Msg)
    {
        case WM_DRAWCLIPBOARD:
            DisplayClipboardData();
            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;
    }
}

void DisplayClipboardData()
{
    try
    {
        IDataObject iData = new DataObject();
        iData = Clipboard.GetDataObject();

        if (iData.GetDataPresent(DataFormats.Rtf))
            richTextBox1.Rtf = (string)iData.GetData(DataFormats.Rtf);
        else if (iData.GetDataPresent(DataFormats.Text))
            richTextBox1.Text = (string)iData.GetData(DataFormats.Text);
        else
            richTextBox1.Text = "[Clipboard data is not RTF or ASCII Text]";
    }
    catch (Exception e)
    {
        MessageBox.Show(e.ToString());
    }
}
Перейдите в обозреватель решений и откройте файл Form1.Designer.cs. Замените в данном файле функцию Dispose.
С:
protected override void Dispose(bool disposing)
{    
    if (disposing)
    {
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose(disposing);
}
НА:
protected override void Dispose(bool disposing)
{
    ChangeClipboardChain(this.Handle, nextClipboardViewer);
    if (disposing)
    {
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose(disposing);
}
Ниже представлен пример работы тестового проекта:

Ссылка для скачивания примера: Rusfolder.net


Комментариев нет:

Отправить комментарий

Большая просьба, не писать в комментариях всякую ерунду не по теме!