FishClip – Enjoy Two Clipboards

I named this little program FishClip, as an homage to the short fish memory myth 😀 What good this program is? This gif should explain everything:

fishclip_demo

FishClip allows you to access your previous clipboard content. I wrote this last year because i had the task at work, to insert some data into a new database with dirrefent frontend and this tool helped me alot giving me a second Clipboard.
For the problem, how to paste the older Clipboard text, i used the keyboard shortcut: “CTRL + B” , because it is just next to V in the keyboardlayout, but the “B” can be interpreted as the first letter of  “BACK” aswell 😛
This program is a perfect usage example of our SuperKeylogger component, wherewith i implemented the listening and reacting to the keyboard shortcut.
Download Sources inc. Binary


Some details about the implementation:

For manipulating the clipboard, these lines do the magic:

[...]
System.Windows.Forms.Clipboard.SetDataObject(OldClipBoard);
SendKeys.SendWait("^v");  //sends crtl v to the active appl.
System.Windows.Forms.Clipboard.SetDataObject(CurrentClipBoard);
[...]

That was pretty simple but for getting informed about clipboard changes and buffering them in the “OldClipBoard” variable, i needed to register the program as a Clipboard viewer:

[...]
/// <summary>
/// Register this form as a Clipboard Viewer application
/// </summary>
private void RegisterClipboardViewer()
{
_ClipboardViewerNext = RAD.ClipMon.Win32.User32.SetClipboardViewer(this.Handle);
}
...
 
and overrode the WndProc method, to handle the Clipboard Event:
 
...
protected override void WndProc(ref Message m)
{
switch ((RAD.ClipMon.Win32.Msgs)m.Msg)
{
//
// The WM_DRAWCLIPBOARD message is sent to the first window
// in the clipboard viewer chain when the content of the
// clipboard changes. This enables a clipboard viewer
// window to display the new content of the clipboard.
//
case RAD.ClipMon.Win32.Msgs.WM_DRAWCLIPBOARD:
 
if (!itsME)
{
if (CurrentClipBoard == null)
{
//CurrentClipBoard = Clipboard.GetDataObject();
CurrentClipBoard = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
}
else
{
OldClipBoard = (string)CurrentClipBoard.Clone();
 
CurrentClipBoard = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
//CurrentClipBoard = Clipboard.GetDataObject();
}
}
//GetClipboardData();
 
//
// Each window that receives the WM_DRAWCLIPBOARD message
// must call the SendMessage function to pass the message
// on to the next window in the clipboard viewer chain.
//
RAD.ClipMon.Win32.User32.SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
break;
 
//
// The WM_CHANGECBCHAIN message is sent to the first window
// in the clipboard viewer chain when a window is being
// removed from the chain.
//
case RAD.ClipMon.Win32.Msgs.WM_CHANGECBCHAIN:
// When a clipboard viewer window receives the WM_CHANGECBCHAIN message,
// it should call the SendMessage function to pass the message to the
// next window in the chain, unless the next window is the window
// being removed. In this case, the clipboard viewer should save
// the handle specified by the lParam parameter as the next window in the chain.
 
//
// wParam is the Handle to the window being removed from
// the clipboard viewer chain
// lParam is the Handle to the next window in the chain
// following the window being removed.
if (m.WParam == _ClipboardViewerNext)
{
// If wParam is the next clipboard viewer then it
// is being removed so update pointer to the next
// window in the clipboard chain
//
_ClipboardViewerNext = m.LParam;
}
else
{
RAD.ClipMon.Win32.User32.SendMessage(_ClipboardViewerNext, m.Msg, m.WParam, m.LParam);
}
break;
 
default:
//
// Let the form process the messages that we are
// not interested in
//
base.WndProc(ref m);
break;
 
}
 
}
[...]

Download Sources for more info.

Leave a Reply

Your email address will not be published. Required fields are marked *