Click here to Skip to main content
Click here to Skip to main content

ClipSpy

By , 27 Oct 2001
 

 [Screen shot 1 - Word clipboard data - 45K]
Fig. 1: ClipSpy shows what Word 97 puts on the clipboard after a simple copy operation.

 [Screen shot 2 - Word drag-n-drop data - 22K]
Fig. 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:

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():

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:

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

About the Author

Michael Dunn
Software Developer (Senior) VMware
United States United States
Member
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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5mvpMichael Haephrati מיכאל האפרתי15 Feb '13 - 23:17 
GeneralMy vote of 5memberjamseyang8 Feb '12 - 22:51 
GeneralMy vote of 5memberjamseyang8 Feb '12 - 22:50 
Generalyou're very kindmembernenfa22 Dec '09 - 21:21 
GeneralJust wanted to say that, after crashing clipSpyPlus (a later C# effort by another poster), ClipSpy solved my problem!memberkirkaiya29 Jan '09 - 6:37 
GeneralGood!membercen_jin_long19 Nov '08 - 21:24 
QuestionNot working with the clipboard content which is dropped from the .NET Applicaitonmembersasik_7215 Nov '08 - 4:16 
QuestionGroupwisememberchiga19 Jul '08 - 22:19 
GeneralGood JobmemberMike Hankey23 Dec '07 - 16:14 
QuestionExplorer Style Cut and PastememberMillard Filmore5 Oct '07 - 8:45 
QuestionProblem with OnDrawClipboardmemberdSolariuM4 Aug '07 - 1:06 
QuestionHow to Keep data?memberdSolariuM2 Aug '07 - 21:38 
AnswerRe: How to Keep data?memberKarstenK2 Aug '07 - 22:10 
GeneralFYI: What went wrong when clipyspy show no formats ...memberllangolas25 Oct '06 - 4:05 
GeneralRe: FYI: What went wrong when clipyspy show no formats ...sitebuilderMichael Dunn26 Oct '06 - 17:13 
QuestionRe: compiler errormembermla15428 Aug '06 - 16:24 
GeneralClipboard Query.memberHakuna-Matada3 Aug '06 - 1:39 
GeneralRe: Clipboard Query.sitebuilderMichael Dunn4 Aug '06 - 13:16 
QuestionNot a valid drop target for Opera?membersklein11 Jun '06 - 7:03 
AnswerRe: Not a valid drop target for Opera?sitebuilderMichael Dunn11 Jun '06 - 11:57 
GeneralRe: Not a valid drop target for Opera?membersklein11 Jun '06 - 12:25 
GeneralDrag and drop from IEmemberyogishka16 May '06 - 2:34 
GeneralTarget application information - paste operationmemberyogishka28 Mar '06 - 22:57 
Questionhow to get HDROP from IE when there is url on the image filememberhuom17 Mar '06 - 18:17 
AnswerRe: how to get HDROP from IE when there is url on the image filesitebuilderMichael Dunn18 Mar '06 - 5:26 

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130513.1 | Last Updated 28 Oct 2001
Article Copyright 1999 by Michael Dunn
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid