Click here to Skip to main content
15,884,388 members
Articles / Programming Languages / C++

ClipSpy

Rate me:
Please Sign up or sign in to vote.
4.88/5 (55 votes)
27 Oct 2001 463.2K   7.9K   138  
A tool for viewing clipboard and drag-and-drop data
//////////////////////////////////////////////////////////////////////////
//
// ClipSpy, Copyright 1999-2001  by Michael Dunn <mdunn at inreach dot com>
//
// This is a utility to view the raw contents of the clipboard, or the 
// data in a drag-and-drop operation.  There are still some quirks and
// bugs.  Comments/suggestions are always welcome!
//
// Revision history:
//  Dec 20, 1999: Version 1.0, first release.
//
//  Sep 27, 2001: Version 1.2, added ability to save any block of data;
//      added IDropTargetHelper support to CLeftView.
//
// You can get the latest updates for ClipSpy at:
//  http://www.codeproject.com/clipboard/clipspy.asp
//
//////////////////////////////////////////////////////////////////////////

// ClipSpyDoc.cpp : implementation of the CClipSpyDoc class
//

#include "stdafx.h"
#include "ClipSpy.h"

#include "ClipSpyDoc.h"
#include "CntrItem.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CClipSpyDoc

IMPLEMENT_DYNCREATE(CClipSpyDoc, CRichEditDoc)

BEGIN_MESSAGE_MAP(CClipSpyDoc, CRichEditDoc)
	//{{AFX_MSG_MAP(CClipSpyDoc)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CClipSpyDoc construction/destruction

CClipSpyDoc::CClipSpyDoc() : m_ppData(NULL), m_uNumBlocks(0),
                             m_uNextBlockIndex(0)
{
    m_auDataSizes.SetSize ( 0, 10 );    // grow by 10 elts
}

CClipSpyDoc::~CClipSpyDoc()
{
}

BOOL CClipSpyDoc::OnNewDocument()
{
	if (!CRichEditDoc::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}

CRichEditCntrItem* CClipSpyDoc::CreateClientItem(REOBJECT* preo) const
{
	// cast away constness of this
	return new CClipSpyCntrItem(preo, (CClipSpyDoc*) this);
}



/////////////////////////////////////////////////////////////////////////////
// CClipSpyDoc serialization

void CClipSpyDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}

	// Calling the base class CRichEditDoc enables serialization
	//  of the container document's COleClientItem objects.
	// TODO: set CRichEditDoc::m_bRTF = FALSE if you are serializing as text
	CRichEditDoc::Serialize(ar);
}

/////////////////////////////////////////////////////////////////////////////
// CClipSpyDoc diagnostics

#ifdef _DEBUG
void CClipSpyDoc::AssertValid() const
{
	CRichEditDoc::AssertValid();
}

void CClipSpyDoc::Dump(CDumpContext& dc) const
{
	CRichEditDoc::Dump(dc);
}
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
// CClipSpyDoc overrides

// Override of SaveModified(): This just returns TRUE to indicate to MFC that
// it's OK to close the document.  Not doing this would result in a message
// box when closing the app (because CRichEditDoc would prompt you to save
// the modified document).
BOOL CClipSpyDoc::SaveModified() 
{
    return TRUE;    // OK to close
}

// Override of DeleteContents(): Clear our private data, then let the base
// class handle the rest.
void CClipSpyDoc::DeleteContents() 
{
    Clear();	
	CRichEditDoc::DeleteContents();
}


/////////////////////////////////////////////////////////////////////////////
// CClipSpyDoc public interface

// Clear(): Frees any clipboard data that has been stored in the doc.
void CClipSpyDoc::Clear()
{
    if ( NULL != m_ppData )
        {
        for ( UINT u = 0; u < m_uNumBlocks; u++ )
            {
            if ( NULL != m_ppData[u] )
                {
                delete [] m_ppData[u];
                }
            }

        delete m_ppData;
        m_ppData = NULL;
        }
        
    m_auDataSizes.RemoveAll();
    m_uNumBlocks = 0;
    m_uNextBlockIndex = 0;
}

// Init(): The client calls this function to tell the doc how many blocks of
// data it will be storing.
void CClipSpyDoc::Init ( const UINT uNumBlocks )
{
    // Clear out existing data if necessary.
    if ( NULL != m_ppData )
        {
        Clear();
        }

    m_uNumBlocks = uNumBlocks;
    m_uNextBlockIndex = 0;

    m_ppData = new LPBYTE [ uNumBlocks ];
}

// AddDataBlock(): Adds a chunk of data to the document.  hgData is an HGLOBAL
// of the data, and uSize is the size in bytes.
void CClipSpyDoc::AddDataBlock ( HGLOBAL hgData, const UINT uSize )
{
LPVOID pvData;

    ASSERT ( NULL != m_ppData );        // Called Init() yet?
    ASSERT ( m_uNextBlockIndex < m_uNumBlocks );    // Too many blocks added?

    // Get a real pointer to the data.
    pvData = GlobalLock ( hgData );

    if ( NULL != pvData )
        {
        ASSERT ( AfxIsValidAddress ( pvData, uSize, FALSE ));

        // Allocate memory to hold a copy of the data.
        m_ppData [ m_uNextBlockIndex ] = new BYTE [ uSize ];

        // Copy the data to the newly-allocated memory.
        CopyMemory ( m_ppData [ m_uNextBlockIndex ], pvData, uSize );

        // Update other stuff...
        m_auDataSizes.Add ( uSize );
        m_uNextBlockIndex++;

        // Unlock the HGLOBAL.
        GlobalUnlock ( hgData );
        }
    else
        {
        // Couldn't access the data, so just add an empty block instead.
        AddEmptyBlock();
        }
}

// AddEmptyBlock(): Adds a zero-length block to the document.  The client calls
// this if a clipboard format is listed as being on the clipboard, but
// can't access the data for some reason.
void CClipSpyDoc::AddEmptyBlock()
{
    ASSERT ( NULL != m_ppData );        // Called Init() yet?
    ASSERT ( m_uNextBlockIndex < m_uNumBlocks );    // Too many blocks added?

    m_ppData [ m_uNextBlockIndex++ ] = NULL;
    m_auDataSizes.Add ( 0 );
}

// GetDataBlock(): Retrieves a pointer to a given block of data.  Can return
// NULL if the doc is empty, or the given index has an empty data block.
const LPBYTE CClipSpyDoc::GetDataBlock ( const UINT uBlockIndex ) const
{
    if ( 0 == m_uNumBlocks )
        return NULL;

    ASSERT ( uBlockIndex < m_uNumBlocks );  // Index out of range?

    return m_ppData [ uBlockIndex ];
}

// GetDataBlockSize(): Returns the length of the data block at the given index.
UINT CClipSpyDoc::GetDataBlockSize ( const UINT uBlockIndex ) const
{
    ASSERT ( uBlockIndex < m_uNumBlocks );  // Index out of range?

    return m_auDataSizes [ uBlockIndex ];
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


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