Custom Clipboard Manager
In this article I explain how to use system Clipboard API capabilities, and get an application functionality such as Spike in MS Word.
Recently I got a task to develop an application that enables users to monitor all clipboard text transactions made through Cut/Copy operation inside one application, and to transfer selected data to another application, through a custom paste operation. There was also a request to add two “ENTER” keystrokes at the end of every paste operation.
By default, operating system Clipboard API enables the user, through Cut/Copy/Paste operations, to temporarily store selected data inside a dedicated part of memory, and then to transfer that data into the same or a different application. It also enables only a single Clipboard data transaction, and to get something more, there is a need to develop and use a custom Clipboard Manager application.
According to demands for the app that should be developed, there are several things that Clipboard Manager should do:
-
The prime task is to monitor all data changes inside the system Clipboard made by Cut/Copy operations. When that event occurs the app should get Clipboard data and if it contains plain text, it should store it inside a custom data table.
-
The second task is to enable the user to select textual data from the data table and transfer it to the selected program trough custom Paste operation.
-
The third task is to give the user some extra Hotkey functionalities, like a Hotkey for deleting all memorized data, selecting data for Paste operations, minimizing and maximizing app, pasting all data at once, etc.
Windows operating system and all applications developed to run under it are event-driven. All events that happen at operating system level such as Clipboard changes, Hot Key pressed event, Foreground window has changed, etc., are registered by the operating system and if necessary, the operating system creates a message about that event and sends that message to the application window that is registered for monitoring such an event.
If there is a need to observe Clipboard changes, such as in this case, it is necessary to register application window Handle to the operating system Clipboard format listener list. That means that every time the content of Clipboard is changed, the operating system shall send a message about that event to the registered application's Window Procedure.
To get messages about what combination of keys is pressed, it is necessary to register the application's Window Handle and Hot Key combination to the system, and every time this key combination is pressed, the system shall send a message about that event to the registered application's Window Procedure.
What is important here is to notice that the system knows where to send a message about a certain event over the registered application window Handle. Also, the system message contains the Handle of the window that raised the observed event and code of the message.
Some of the message codes:
-
- const int WM_HOTKEY = 0x0312;
- const int WM_CLIPBOARDUPDATE = 0x031D;
All messages sent to the window by the operating system can be processed by the WndProc function.
- #region- WndProc -
- protected override void WndProc(ref Message m)
- {
-
- if (m.Msg == WM_HOTKEY)
- {
-
- }
-
- else if (m.Msg == WM_CLIPBOARDUPDATE)
- {
-
- }
- else
- base.WndProc(ref m);
- }
- #endregion
Of course, before using this function, there is a need to register an application to the operating system for getting the desired messages.
This library contains several functions that are needed for registering the application for monitoring different events.
This function makes an attempt to register window handle to system Clipboard format listener list. If succeeded, the window shall receive WM_CLIPBOARDUPDATE message every time when the system Clipboard changes its content.
This function removes window handle from Clipboard format listener. If succeeded, the window shall not receive any more messages about system Clipboard changes.
This function makes an attempt to register window handle and Hotkey combination to the operating system. If succeeded, the window shall receive a WM_HOTKEY message every time when the selected key combination is pressed.
-
- const int None = 0x0000;
- const int Alt = 0x0001;
- const int Control = 0x0002;
- const int Shift = 0x0004;
- const int WinKey = 0x0008;
-
- const int MOD_NOREPEAT = 0x4000;
-
-
- const int V = (int)Keys.V;
-
- bool Is_Registered = RegisterHotKey(this.Handle, V, Control | MOD_NOREPEAT, V);
This function removes registered Window Handle and Hotkey combination from the operating system. If succeeded, the window shall not receive any more messages when the Hotkey combination is pressed.
This function gets the handle of the currently active/selected/focused window.
-
- IntPtr handle = new IntPtr();
-
-
- handle = GetForegroundWindow();
This function makes an attempt to set active/selected/focused window with the selected handles.
-
- bool Is_Set = SetForegroundWindow(handle);
Usage of all those functions are considered unsafe, and according to that, they should be declared as an instance of UnsafeNativeMethods class, with necessary security attribute information.
- #region- DllImport section -
- [SuppressUnmanagedCodeSecurityAttribute]
- internal static class UnsafeNativeMethods
- {
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- internal static extern IntPtr GetForegroundWindow();
-
- [DllImport("user32.dll")]
- internal static extern int SetForegroundWindow(IntPtr point);
-
- [DllImport("user32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool AddClipboardFormatListener(IntPtr hwnd);
-
- [DllImport("user32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
-
- [DllImport("user32.dll")]
- internal static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
-
- [DllImport("user32.dll")]
- internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
- }
- #endregion
-
- new UIPermission(UIPermissionWindow.AllWindows).Demand();
Now that we know the necessary theory let's create an application.
Download full solution developed in MS Visual Studio 2019, with open source code inside.
Open it in Visual Studio and build a complete project. After that thoroughly examine and analyze the whole project with program code.
All the best,
Željko Perić