Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C++

ClipSpy

Rate me:
Please Sign up or sign in to vote.
4.88/5 (55 votes)
27 Oct 2001 461.7K   7.9K   138   44
A tool for viewing clipboard and drag-and-drop data

 [Screen shot 1 - Word clipboard data - 45K]

Figure 1: ClipSpy shows what Word 97 puts on the clipboard after a simple copy operation.

 [Screen shot 2 - Word drag-n-drop data - 22K]

Figure 2: ClipSpy showing the data created by Word when dragging and dropping the same text.

Introduction

Recently, I had some free time and I was thinking about an area of Windows programming that I didn't know much about, but wanted to learn more about, namely the clipboard. I had written a utility for myself that dealt with HDROP data on the clipboard to simulate Explorer's Copy and Paste commands, but using just one format wasn't enough. I wanted to see deeper into the contents of the clipboard, and in the process maybe uncover some neat factoids about apps that use the clipboard. (For example, what's a "Woozle"? - See Figure 2 above.)

Well, the free time turned into a free weekend (lucky for me I had all my Christmas shopping done!), and the result of my self-teaching is ClipSpy, a souped-up clipboard viewer. It can also view the data in a drag-and-drop operation (since MFC uses the same class to handle drag-and-drop and the clipboard), but I chose the name ClipSpy since ClipboardAndDragAndDropSpy is a bit harder to type.

If you're just itching to learn more about the clipboard yourself, check out the "Implementation details" section of the article, where I point out interesting points in the code.

What ClipSpy Does

ClipSpy registers itself as a clipboard viewer. Nothing magical there. But when the contents of the clipboard change, ClipSpy enumerates all the data formats on the clipboard (there may be many) and displays them all in the left-hand pane. Clicking on a format in the list shows the data that was placed on the clipboard in the right-hand pane. The right pane shows the raw data as well as the ASCII representation, similar to the memory debug window in MSVC.

The left-hand pane also registers as a drop target, so you can drag any data from a program that supports drag-and-drop, drop it over the list, and ClipSpy will show all the data that the drag source provided. Again, the formats are listed in the left-hand pane, and clicking a format shows the corresponding data in the right-hand pane.

The File menu also has a few commands. The Read Clipboard command re-reads the contents of the clipboard. Use this command if you have done a drag-and-drop and you want ClipSpy to redisplay the clipboard contents. The Empty Clipboard command clears out the clipboard. The Save Selected Data command is available when you are viewing a block of data, and saves that data to a file.

Implementation Details

ClipSpy does most of its work via the MFC class COleDataObject that implements the IDataObject interface and provides access to the data on the clipboard or drag source. The function CLeftView::ReadDataAndFillList() handles enumerating the formats on the clipboard and filling the list control. The enumeration goes like this:

C++
BOOL CLeftView::ReadDataAndFillList ( COleDataObject* pDO )
{
FORMATETC etc;
UINT      uNumFormats = 0;

    // Determine how many formats are available on the clipboard.

    pDO->BeginEnumFormats();

    while ( pDO->GetNextFormat ( &etc ))
        {
        if ( pDO->IsDataAvailable ( etc.cfFormat ))
            {
            uNumFormats++;
            }
        }

For each format, ClipSpy checks to see if it is a built-in type. If not, it gets the descriptive string for the format by calling GetClipboardFormatName():

C++
TCHAR szFormat [256];

    GetClipboardFormatName ( etc.cfFormat, szFormat, 256 );

ClipSpy has a list of strings used for the built-in types (since GetClipboardFormatName() only works for custom types registered by programs). ClipSpy then tries to read the data for the format:

C++
HGLOBAL hgData;
UINT    uDataSize;
CClipSpyDoc* pDoc = GetDocument();

    // Get an HGLOBAL of the data.
    hgData = pDO->GetGlobalData ( etc.cfFormat );

    if ( NULL != hgData )
        {
        uDataSize = GlobalSize ( hgData );
        pDoc->AddDataBlock ( hgData, uDataSize );
        }
    else
        {
        pDoc->AddEmptyBlock();
        }

The functions AddDataBlock() and AddEmptyBlock() are members of the document class, which stores copies of all the data.

This same code is used when data is dropped on the list control - the function CLeftView::OnDrop() provides a COleDataObject object that is passed directly to ReadDataAndFillList().

The other interesting pieces of code are CLeftView::OnItemchanged() and CClipSpyView::OnUpdate(). The first function detects when the selection in the list changes, and calls UpdateAllViews(), which in turn calls OnUpdate(). OnUpdate() handles filling in the rich edit control with a dump of the data.

Quirks in the Program

The right-hand pane is a rich edit control, which supports copying to the clipboard. However, you should not copy from it, since doing so can lead to crashes inside OLE. Again, this is probably due to something I'm doing wrong, but in the meantime, just don't do it. :)

Since clipboard data is originally allocated with GlobalAlloc(), each block of data may be longer than the data itself. (GlobalAlloc() can allocate more memory than you request for performance and byte-alignment reasons.) For example, on Win 98, if I copy an 8-character word to the clipboard using MSVC, the clipboard contains 32 bytes of CF_TEXT (plain ANSI text) data. The first 9 are the word (8 bytes plus a terminating null), but the rest are random garbage. ClipSpy displays the entire block of data, and doesn't try to interpret the data in any way.

Something to keep in mind if you debug the program - if you are stepping through the code, do not try to use the clipboard. Since ClipSpy isn't running, the entire clipboard operation hangs and brings down ClipSpy, MSVC, and whatever program you did the clipboard operation in. Ouch! On Windows 9x, you might as well hit the reset button at that point.

Revision History

  • December 20, 1999: Version 1.0, first release
  • October 28, 2001: Version 1.2, added ability to save any block of data; added IDropTargetHelper support to CLeftView

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
Software Developer (Senior) VMware
United States United States
Michael lives in sunny Mountain View, California. He started programming with an Apple //e in 4th grade, graduated from UCLA with a math degree in 1994, and immediately landed a job as a QA engineer at Symantec, working on the Norton AntiVirus team. He pretty much taught himself Windows and MFC programming, and in 1999 he designed and coded a new interface for Norton AntiVirus 2000.
Mike has been a a developer at Napster and at his own lil' startup, Zabersoft, a development company he co-founded with offices in Los Angeles and Odense, Denmark. Mike is now a senior engineer at VMware.

He also enjoys his hobbies of playing pinball, bike riding, photography, and Domion on Friday nights (current favorite combo: Village + double Pirate Ship). He would get his own snooker table too if they weren't so darn big! He is also sad that he's forgotten the languages he's studied: French, Mandarin Chinese, and Japanese.

Mike was a VC MVP from 2005 to 2009.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 408754114-Jun-14 23:01
Member 408754114-Jun-14 23:01 
QuestionHow placing an application into pane of a MFC splitter? Pin
QMars8424-Mar-14 5:58
professionalQMars8424-Mar-14 5:58 
GeneralI can't believe it! Pin
brother.gabriel18-Jun-13 6:13
brother.gabriel18-Jun-13 6:13 
GeneralMy vote of 5 Pin
Michael Haephrati15-Feb-13 23:17
professionalMichael Haephrati15-Feb-13 23:17 
GeneralRe: My vote of 5 Pin
Uwe Keim13-Oct-16 4:28
sitebuilderUwe Keim13-Oct-16 4:28 
GeneralRe: My vote of 5 Pin
Michael Haephrati13-Oct-16 6:43
professionalMichael Haephrati13-Oct-16 6:43 
Good to know. After all you are talking about code from 2001.
- Michael Haephrati מיכאל האפרתי

GeneralMy vote of 5 Pin
jamseyang8-Feb-12 22:51
jamseyang8-Feb-12 22:51 
GeneralMy vote of 5 Pin
jamseyang8-Feb-12 22:50
jamseyang8-Feb-12 22:50 
Generalyou're very kind Pin
nenfa22-Dec-09 21:21
nenfa22-Dec-09 21:21 
GeneralJust wanted to say that, after crashing clipSpyPlus (a later C# effort by another poster), ClipSpy solved my problem! Pin
kirkaiya29-Jan-09 6:37
kirkaiya29-Jan-09 6:37 
GeneralGood! Pin
cen_jin_long19-Nov-08 21:24
cen_jin_long19-Nov-08 21:24 
QuestionNot working with the clipboard content which is dropped from the .NET Applicaiton Pin
sasik_7215-Nov-08 4:16
sasik_7215-Nov-08 4:16 
QuestionGroupwise Pin
chiga19-Jul-08 22:19
chiga19-Jul-08 22:19 
GeneralGood Job Pin
Mike Hankey23-Dec-07 16:14
mveMike Hankey23-Dec-07 16:14 
QuestionExplorer Style Cut and Paste Pin
Millard Filmore5-Oct-07 8:45
Millard Filmore5-Oct-07 8:45 
QuestionProblem with OnDrawClipboard Pin
dSolariuM4-Aug-07 1:06
dSolariuM4-Aug-07 1:06 
QuestionHow to Keep data? Pin
dSolariuM2-Aug-07 21:38
dSolariuM2-Aug-07 21:38 
AnswerRe: How to Keep data? Pin
KarstenK2-Aug-07 22:10
mveKarstenK2-Aug-07 22:10 
GeneralFYI: What went wrong when clipyspy show no formats ... Pin
llangolas25-Oct-06 4:05
llangolas25-Oct-06 4:05 
GeneralRe: FYI: What went wrong when clipyspy show no formats ... Pin
Michael Dunn26-Oct-06 17:13
sitebuilderMichael Dunn26-Oct-06 17:13 
QuestionRe: compiler error Pin
mla15428-Aug-06 16:24
mla15428-Aug-06 16:24 
GeneralClipboard Query. Pin
HakunaMatada3-Aug-06 1:39
HakunaMatada3-Aug-06 1:39 
GeneralRe: Clipboard Query. Pin
Michael Dunn4-Aug-06 13:16
sitebuilderMichael Dunn4-Aug-06 13:16 
QuestionNot a valid drop target for Opera? Pin
sklein11-Jun-06 7:03
sklein11-Jun-06 7:03 
AnswerRe: Not a valid drop target for Opera? Pin
Michael Dunn11-Jun-06 11:57
sitebuilderMichael Dunn11-Jun-06 11:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.