Страницы

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

пятница, 5 октября 2018 г.

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

Нужно, чтобы код, который проверяет буфер обмена, работал постоянно. Сейчас он у меня срабатывает только по нажатию на кнопку. Как это можно организовать ?
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. А мне нужно, чтобы это происходило без нажатия на кнопку А. Бесконечным циклом не вышло:программа просто не запускается.


Ответ

Конечно, можно запустить бесконечный цикл где-нибудь в отдельном потоке, но на мой взгляд такое решение как минимум некорректно. 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. Текст из буфера вставляется в текстовое поле сразу после копирования, никаких кнопок дополнительно нажимать не надо

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

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