Страницы

Поиск по вопросам

воскресенье, 1 декабря 2019 г.

Наблюдение за буфером обмена

#c_sharp #winforms #winapi


Нужно, чтобы код, который проверяет буфер обмена, работал постоянно. Сейчас он у
меня срабатывает только по нажатию на кнопку. Как это можно организовать ?

 int i = 0;
            if (e.KeyCode == Keys.A)
            {
                stroka = Clipboard.GetText();

                for (i = 0; i < array.Length; i++)
                {
                    if (array[i] == "")
                    {
                        array[i] = stroka;
                        break;
                    }
                    else if (array[9] != "")
                    {
                       DialogResult dr = MessageBox.Show("Ошибка. Буфер переполнен.
Хотите очистить буфер ?","Предупреждение",MessageBoxButtons.OKCancel);
                       if (dr == DialogResult.OK)
                       {
                           for (i = 0; i < array.Length; i++)
                           {
                               array[i] = "";
                           }
                       }
                        break;
                    }

                }
            }

                if (e.KeyCode == Keys.D0)
                {
                    textBox3.Text = array[0];
                }
                if (e.KeyCode == Keys.D1)
                {
                    textBox3.Text = array[1];
                }
                if (e.KeyCode == Keys.D2)
                {
                    textBox3.Text = array[2];
                }
                if (e.KeyCode == Keys.D3)
                {
                    textBox3.Text = array[3];
                }
                if (e.KeyCode == Keys.D4)
                {
                    textBox3.Text = array[4];
                }
                if (e.KeyCode == Keys.D5)
                {
                    textBox3.Text = array[5];
                }
                if (e.KeyCode == Keys.D6)
                {
                    textBox3.Text = array[6];
                }
                if (e.KeyCode == Keys.D7)
                {
                    textBox3.Text = array[7];
                }
                if (e.KeyCode == Keys.D8)
                {
                    textBox3.Text = array[8];
                }
                if (e.KeyCode == Keys.D9)
                {
                    textBox3.Text = array[9];
                }


Копируется что-то в буфер, нажимается кнопка А и из буфера значение заносится в массив,
потом снова копируется значение, нажимается А и значение копируется в массив на позицию
i+1. А мне нужно, чтобы это происходило без нажатия на кнопку А. Бесконечным циклом
не вышло:программа просто не запускается.
    


Ответы

Ответ 1



Конечно, можно запустить бесконечный цикл где-нибудь в отдельном потоке, но на мой взгляд такое решение как минимум некорректно. Windows предоставляет возможность отслеживать изменения буфера обмена - т.е., изменения будут отслеживаться и обрабатываться в реальном времени. Как я понимаю, вас интересует именно это, а не while (true) :) В статье за авторством Тома Арчера рассказывается, как организовать отслеживание в WinForms. Приведу краткое переложение раздела "Пошаговые инструкции" (с переводом и некоторыми изменениями в коде). 1 Необходимо вызвать пару функций из библиотеки Win32 —SetClipboardViewer, ChangeClipboardChain, и SendMessage Для того, чтобы сделать это в приложении .NET, необходимо импортировать их, используя атрибут DllImport. В примере ниже эти функции импортируются в приложение WinForms: using System.Runtime.InteropServices; ... public partial class frmMain : Form { [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); ... 2 Определим член класса для помещения текущего окна в цепь уведомлений буфера Оригинальный текст: Define a class member to hold the current first window in the Clipboard notification chain: public partial class frmMain : Form { ... IntPtr nextClipboardViewer; 3 Вызовем функцию SetClipboardViewer. В примере она вызывается в конструкторе формы: public frmMain() { InitializeComponent(); nextClipboardViewer = (IntPtr)SetClipboardViewer((int) this.Handle); } 4 Внутри класса frmMain переопределим метод WndProc. В примере обрабатываются только два сообщения: WM_DRAWCLIPBOARD и WM_CHANGECBCHAIN. В коде, обрабатывающем WM_DRAWCLIPBOARD, вызывается пользовательский метод DisplayClipboardData(), который выводит содержимое буфера; затем то же сообщение передаётся следующему в цепи окну. В коде, обрабатывающем WM_CHANGECBCHAIN, проверяется, является ли окно, удалённое из цепи буфера, следующим (по отношению к текущему). Если да, nextClipboardViewer присваивается окно, следующее за удалённым. protected override void WndProc(ref 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; } } 5 Наконец, окно удаляется из цепи буфера, когда .NET Runtime вызывает метод Dispose класса frmMain protected override void Dispose( bool disposing ) { ChangeClipboardChain(this.Handle, nextClipboardViewer); ... В инструкции не описан, собственно, метод DisplayClipboardData. У меня он выглядит так: private void DisplayClipboardData() { txtBox.Text = Clipboard.GetText(); } Т.е., в текстовое поле на форме просто выводится текст из буфера. В вашем случае нужно вставить обработку массива. На всякий случай, полный листинг того, что вышло у меня: using System.Windows.Forms; using System.Runtime.InteropServices; namespace clipborad { public partial class frmMain : Form { Random r = new Random(); [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); IntPtr nextClipboardViewer; public frmMain() { InitializeComponent(); nextClipboardViewer = (IntPtr)SetClipboardViewer((int) this.Handle); } protected override void WndProc(ref System.Windows.Forms.Message m) { // defined in winuser.h 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; } } private void DisplayClipboardData() { txtBox.Text = Clipboard.GetText(); } } } Плюс не забываем добавить строку ChangeClipboardChain(this.Handle, nextClipboardViewer); в метод Dispose в файле frmMain.Designer.cs Код компилируется и прекрасно работает в Win10 x64. Текст из буфера вставляется в текстовое поле сразу после копирования, никаких кнопок дополнительно нажимать не надо

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

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