Of course, you can run an infinite loop somewhere in a separate thread, but in my opinion such a solution is at least incorrect. Windows provides the ability to track clipboard changes — that is, changes will be tracked and processed in real time. As I understand it, this is what interests you, not while (true) :)
The article by Tom Archer describes how to organize tracking in WinForms. I will cite a brief transcription of the “Step-by-Step Instructions” section (with translation and some changes in the code).
one
You need to call a couple of functions from the Win32 library - SetClipboardViewer , ChangeClipboardChain , and SendMessage To do this in the .NET application, you must import them using the DllImport attribute. In the example below, these functions are imported into the WinForms application:
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 place the current window in the buffer notification chain. Original text:
public partial class frmMain : Form { ... IntPtr nextClipboardViewer;
3
Call the SetClipboardViewer function. In the example, it is called in the form constructor:
public frmMain() { InitializeComponent(); nextClipboardViewer = (IntPtr)SetClipboardViewer((int) this.Handle); }
four
Inside the frmMain class frmMain override the WndProc method. In the example, only two messages are WM_DRAWCLIPBOARD : WM_DRAWCLIPBOARD and WM_CHANGECBCHAIN .
In the code that handles WM_DRAWCLIPBOARD , the user-defined method DisplayClipboardData() is called, which displays the contents of the buffer; then the same message is transmitted to the next window in the chain.
In the code processing WM_CHANGECBCHAIN , it is checked whether the window removed from the buffer chain is next (relative to the current one). If so, nextClipboardViewer assigned the window following the deleted one.
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; } }
five
Finally, the window is removed from the buffer chain when the .NET Runtime calls the Dispose method of the frmMain class frmMain
protected override void Dispose( bool disposing ) { ChangeClipboardChain(this.Handle, nextClipboardViewer); ...
The instructions do not describe the DisplayClipboardData method. It looks like this for me:
private void DisplayClipboardData() { txtBox.Text = Clipboard.GetText(); }
Ie, the text from the buffer is simply displayed in the text field on the form. In your case, you need to insert array processing.
Just in case, a full listing of what happened to me:
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(); } } }
Plus, don't forget to add the line ChangeClipboardChain(this.Handle, nextClipboardViewer); to the Dispose method in the frmMain.Designer.cs file
The code compiles and works great in Win10 x64. The text from the buffer is inserted into the text field immediately after copying, no need to additionally press any buttons