C# захват буфера обмена Windows

222
08 февраля 2019, 21:20

Задача:

  • Слушать буфер обмена
  • При копировании пользователем информации в другом окне, запоминать ее
  • Определять чем она является
  • Работать с ней, если она - текст

Условия:

  • Консольное приложение на C#
  • Программа свернута (не находится в фокусе)

Реализации которые я видел используют WinApi, вот один пример из таких реализаций:

[DllImport("user32.dll")]
        static extern IntPtr SetClipboardViewer(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern bool ChangeClipboardChain(IntPtr hWndDel, IntPtr hWndNext);
        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wparam1, IntPtr lparam);
        IntPtr hWndNextWnd; //Для хранения указателя на следующее окно
        protected override void WndProc(ref Message m) // переопределяем метод 
        {
            switch (m.Msg) //Анализируем сообщение Windows
            {
                case (0x0001): // Код WM_CREATE наше окно создано
                    hWndNextWnd = SetClipboardViewer(this.Handle); // Помещаем наше окно в цепочку и сохраняем указатель на следующее 
                    break;
                case (0x0002): // Код WM_DESTROY окно будет разрушено, нужно удалитmся из цепочки буфера обмена
                    ChangeClipboardChain(this.Handle, hWndNextWnd); // Удаляем наше окно и передаём указатель на следующее окно
                    break;
                case (0x030D): // Код WM_CHANGECBCHAIN одно из окон удаено из цепочки, нужно востоновить цепочку
                    if (m.WParam == hWndNextWnd) // Если удаляемое окно это следующие окно в цепочке
                        hWndNextWnd = m.LParam; //Следующим окном делаем окно идущее в цепочке за удаляемым 
                    else if (hWndNextWnd != IntPtr.Zero) // Если дескриптор следующего окна определён
                        SendMessage(hWndNextWnd, m.Msg, m.WParam, m.LParam);// Посылаем сообщение этому окну
                    break;
                case (0x0308): //Код WM_DRAWCLIPBOARD содержимое буфера изменилось можно работать
                {
                    //НА МЕСТЕ ЭТОГО КОММЕНТАРИЯ ПИШИТЕ СВОЙ КОД
                    SendMessage(hWndNextWnd, m.Msg, m.WParam, m.LParam);// Посылаем сообщение о изменении бефера дальше по цепочке
                }
                    break;
            }
            base.WndProc(ref m); //обращаемся к нашему методу

Вопрос: Как реализовать такое без WinForm(как в данном примере)?

Т.Е. что делать если у меня консоль и мне негде переопределять метод WndProc?

Answer 1

Совсем без WinForms такое проделать будет затруднительно. Но кто вам мешает использовать Windows Forms в консольном приложении?

Достаточно подключить библиотеку System.Windows.Forms.dll и написать что-то вроде вот такого

using (var handler = new ClipboardHandler())
{
    handler.CreateControl();
    Application.Run();
}

Только не забудьте про STAThread. Если же вам нужен способ прервать цикл обработки сообщений - можно воспользоваться CancellationToken:

var cts = new CancellationTokenSource();
// ...
using (var handler = new ClipboardHandler())
{
    handler.CreateControl();
    using (cts.Token.Register(Application.ExitThread, useSynchronizationContext: true))
        Application.Run();
}

Например, можно настроить правильную остановку при нажатии Ctrl+C или Ctrl+Break:

Console.CancelKeyPress += (o, e) =>
{
    e.Cancel = true;
    cts.Cancel();
};

К сожалению, закрытие консольного окна так просто не перехватывается.

READ ALSO
Unity вложенные префабы (Nested prefabs)

Unity вложенные префабы (Nested prefabs)

Есть у меня префаб - блокИз этих блоков построены разные здания - так же префабы

231
Получить координаты клика мыши на PictureBox

Получить координаты клика мыши на PictureBox

Как получить координаты клика мыши на PictureBox на форме WinForms?

239
IoC container (место в сборке)

IoC container (место в сборке)

У меня есть проект, состоящий из N слоев, на основе ASPNET Core

205