|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Contents
IntroductionThis article talks about a system-tray based clipboard utility called 'SmartClip' that can extend the Windows clipboard functionality by adding the ability to store multiple clipboard entries. This is similar in functionality to the 'Office Clipboard'. We first examine why SmartClip is a better-suited clipboard utility for the profile of a programmer. We then proceed to understand the Windows Clipboard APIs that can be used to create such a utility. This is followed by a discussion on the architecture of the utility. Why we need a clipboard enhancement utility?The native clipboard capability of Windows works well for transferring small amounts of data, but becomes very cumbersome if you want to manipulate a lot of data. Every time you cut or copy, the new data overwrites the previous clipboard contents. SmartClip enhances the regular clipboard functionality in Windows by capturing every piece of data that you copy to the clipboard, and storing it internally. Once the data is in the SmartClip, you can select an item from the SmartClip using a hotkey - this item is automatically placed back on the clipboard, ready to be pasted into any application. You can preview the current clipboard content on the 'Preview Panel' (a hot key activated clipboard viewer). How it helpsThe main advantages of SmartClip over Office Clipboard are as follows: Unlike other utilities, SmartClip is designed to be as non-intruding as possible to the user's current activity. It provides Global Hotkeys, which eliminates any mouse operation to activate its most used features. The user will not lose the keyboard focus, even when the clipboard preview panel (described later) is activated. Also, SmartClip is very conservative on its memory usage and will not hog any system resources. It does not require any elaborate installation. Just copy it to a directory and launch it. How it worksIn order to explain this utility, I will explain the basics of Windows Clipboard. If you are familiar with the concepts of how the clipboard works, you can skip this section and go directly to SmartClip architecture. Windows Clipboard'Clipboard' is a set of functions exposed by Windows to let applications transfer data across or within applications. In essence, it is a piece of memory that is managed by Windows. Putting data into clipboardIf an application wants to put some data into clipboard, it involves the following steps:
The following is a sample code that explains how we can put textual data into clipboard. // An example that shows how to put 'Text' data into clipboard // pTxtData -> memory pointer that contains the text to be copied BOOL PutTextToClipboard(LPCTSTR pTxtData) { // Open the clipboard - We pass in the Main window handle if (!OpenClipboard( AfxGetMainWnd() )) return FALSE; // Now that we have opened the clipboard, we empty its contenst. // Calling this function also makes the current application the // owner of the clipboard EmptyClipboard(); // Allocate a global memory object for the text to be copied. HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, lstrlen(pTxtData)); // Lock the handle and copy the text to the buffer. LPTSTR lptstrCopy = GlobalLock(hglbCopy); memcpy(lptstrCopy, pTxtData, lstrlen(pTxtData)); GlobalUnlock(hglbCopy); // Place the handle on the clipboard. // CF_TEXT is a standard clipboard format defined by Windows SetClipboardData(CF_TEXT, hglbCopy); // Close the clipboard. CloseClipboard(); return TRUE; } Now that we have learned how to put content into the clipboard, we will proceed to the next section that will explain why we need different Clipboard formats. Getting Data from clipboardIf an application wants to get some data from clipboard, it involves the following steps:
The following sample code explains how we can get textual data from the clipboard: // An example that shows how to get 'Text' data into clipboard // Returns the data got from the Clipboard, if not NULL LPCTSTR GetTextFromClipboard() { LPCTSTR = NULL; // Check if the clipboard contains textual data // CF_TEXT is a standard clipboard format for TEXT // defined in Winuser.h if (!IsClipboardFormatAvailable(CF_TEXT)) return strTxtData; // Open the clipboard if (!OpenClipboard(hwndMain)) return strTxtData; // Get the handle of the Global memory that contains the text HGLOBAL hglb = GetClipboardData(CF_TEXT); if (hglb != NULL) { // Get the size of the data SIZE_T DataSize = GlobalSize(hData); LPTSTR lptstr = GlobalLock(hglb); if (lptstr != NULL) { // Allocate data and copy the data strTxtData = new BYTE[DataSize]; memcpy(strTxtData, lptstr, DataSize); GlobalUnlock(hglb); } } // before returning close the clipboard CloseClipboard(); return strTxtData; } Clipboard formatsFor any other application to use the data that you have put into the clipboard, it needs to understand the 'format' in which the data is kept. To facilitate this, when we call the
It is recommended that when an application puts some data into clipboard, it should do so in as many formats as possible. For example, when someone copies a cell in MS Excel, it puts the same data in more than 20 different clipboard formats (internally calling Advanced clipboard capabilities - Delayed renderingWhen placing a clipboard format on the clipboard, an application can delay rendering the data in that format until the data is needed. To do so, an application can specify If a window delays rendering a clipboard format, it must be prepared to render the format upon request for as long as it is the clipboard owner. The system sends the clipboard owner a
This is a visual indication of MSWord internally using 'delayed rendering'. Clipboard viewer and Clipboard viewer chainA clipboard viewer is a window that displays the current content of the clipboard. The ClipBook viewer found in %windir%\system32\clipbrd.exe is an example of a clipboard viewer. When the content of the clipboard changes, the system sends a
A clipboard viewer chain is the linking together of two or more clipboard viewers so that they are dependent upon one another for operation. This interdependency (chain) allows all running clipboard viewer applications to receive the messages sent to the current clipboard. An application window can add itself to the clipboard viewer chain by calling the SmartClip architectureAs mentioned before, SmartClip is a system-tray based application. As the primary objective of our application is to capture and store clipboard contents, we need to be notified whenever there is a change in the clipboard contents. For this, we register ourselves as a clipboard viewer. // Enter the Clipboard Viewer Chain m_hWndNextViewer = SetClipboardViewer(); This ensures that whenever the contents of the clipboard change, we will get notified through the void CMainFrame::OnDrawClipboard() { CFrameWnd::OnDrawClipboard(); if(m_bEnabled) { HWND hOwner = ::GetClipboardOwner(); if(hOwner != m_hWnd) { // Capture the data!! m_ClipboardMgr.GetClipboardEntries(); } // Pass the message to the Next Viewer ::SendMessage(m_hWndNextViewer, WM_DRAWCLIPBOARD, NULL, NULL); } Invalidate(); } How much to save?We should note that each time someone wants to put something into the clipboard, they would want to do so in as many formats as possible. Normally, this would not cause a memory overhead, as the clipboard owner will not render all these formats unless some one specifically asks for a format. If our policy is to save a copy of whatever is put into clipboard, it is obvious that this will result in a lot of memory wastage. Let us take Excel copying something into clipboard as a sample scenario. Excel will store the data in more than 20 different formats (Excel internally optimizes the memory usage using delayed rendering). The average size of data for a specific format could be assumed to be around 200 Kb (quite possible, if it is a large selection). If SmartClip decides to keep a copy of all the formats, it would result in around 4 Mb of data in memory. Since SmartClip keeps copies of multiple clipboard operations in memory, the resulting memory problem worsens. To avoid this memory problem, SmartClip is quite selective in the formats that it chooses to store. In the current implementation, we only store textual data, though the architecture allows this to be extended to as many formats as required. Class diagramsTo understand the architecture of SmartClip better, let us take a look at its class hierarchy.
For each clipboard format that we want to store, we create an instance of a class derived from BOOL CClipboardEntry::GetFromClipboard()
{
// Clipboard is already opened by CClipboardEntryArray
ASSERT(m_ClipboardType != CB_CF_EMPTY);
ASSERT(m_pCBData == NULL);
// Get the data
HANDLE hData = GetClipboardData(m_ClipboardType);
ASSERT(hData != NULL);
if(hData)
{
m_dwCBDataSize = GlobalSize(hData);
BYTE* pData = (BYTE*)::GlobalLock(hData);
if(pData != NULL)
{
// Allocate data and copy the entry
m_pCBData = new BYTE[m_dwCBDataSize];
ASSERT(m_pCBData != NULL);
if(m_pCBData)
memcpy(m_pCBData, pData, m_dwCBDataSize);
}
GlobalUnlock(hData);
}
return TRUE;
}BOOL CClipboardEntry::PutToClipboard()
{
// Clipboard is already opened by CClipboardEntryArray
ASSERT(m_ClipboardType != CB_CF_EMPTY);
ASSERT(m_pCBData != NULL);
if(m_pCBData)
{
// Allocate a global memory object for the Data
HGLOBAL hgData = GlobalAlloc(GMEM_MOVEABLE,
m_dwCBDataSize);
if (hgData == NULL)
{
return FALSE;
}
// Lock the handle and copy the text to the buffer.
BYTE* pData = (BYTE*)GlobalLock(hgData);
memcpy(pData, m_pCBData, m_dwCBDataSize);
GlobalUnlock(hgData);
// Place the handle on the clipboard.
SetClipboardData(m_ClipboardType, hgData);
}
return TRUE;
}
In SmartClip, we have two derived class for class CClipboardEntryArray : public CArray<CClipboardEntry CClipboardEntry*, CClipboardEntry*> Since SmartClip is capable of storing configurable amount of clipboard operations, it internally maintains a list of Global HotkeysNow that we have seen how SmartClip stores clipboard data, we proceed to see how we can use the utility. SmartClip comes with global hotkeys, which help you to navigate and preview clipboard contents. The default hotkey to navigating up through the Global Hotkeys - caveatsGlobal hotkeys are registered using the SmartClip - 'Preview panel'SmartClip has a viewer or preview panel that is capable of rendering the current clipboard contents. This viewer can also be activated using a hotkey. The default hotkey is 'Ctrl+Alt+C'. When activated, this viewer appears as a small window at the bottom right corner of the desktop, near the system tray. The viewer is designed such that it does not intrude into the current activity of the user. To facilitate this, once the viewer is activated, it deactivates or hides itself after a brief amount of time. The code that is responsible for rendering the viewer is the implementation of
SettingsThe following screenshot shows the Settings screen of SmartClip.
Through this dialog, the user can set things like, how many clipboard entries to track (I would recommend putting a value like 20), the default hotkeys for various operations etc. A user can also enable or disable SmartClip temporarily. Another useful feature is to let SmartClip launch itself automatically at Windows startup. To enable this, SmartClip registers itself in the following registry key -
Tips and tricksWhen you paste stuff from 'rich' sources, you find that the formatting is maintained at the destination. Though this is very useful, it can prove to be very annoying at times. In OfficeXP, there is a Paste 'Smart tag' that helps you strip the formatting if required. SmartClip helps you strip formatting information very easily. This is how you can do it:
Future enhancementsOne of the enhancements that I will be working on is to add more clipboard formats. Also, as a user, if you find any glaring limitations, please mail it to me at feedback@chiramattel.com. Please do mention SmartClip as the subject. Also, visit this URL for any future updates. ConclusionAs a programmer, I use the clipboard very often and I found the native clipboard support to be lacking. Hence I wrote this tool. I have been using this tool for quite some time now and found it very useful. I should say, once you start using SmartClip, it is very addictive. Revision History
|
||||||||||||||||||||||