Click here to Skip to main content
15,885,309 members
Articles / Web Development / HTML

TraceTool 12.7: The Swiss-Army Knife of Trace

Rate me:
Please Sign up or sign in to vote.
4.97/5 (234 votes)
20 Nov 2016CPL19 min read 1.9M   39K   1K  
A C#, C++, Delphi, ActiveX , Javascript , NodeJs and Java trace framework and a trace viewer: Tail, OutputDebugString, event log, and with Log4J, Log4Net, and Microsoft Enterprise Instrumentation Framework (EIF) support. This also comes with full support for Pocket PC, Silverlight, and Android.
// ClipboardHistory.cpp : Defines the initialization routines for the DLL.
//
// General : use of MFC : Use MFC in a Static Library
// C++ : Additional Include directories : tracetool folder : ../Source
// C++ : Basic Runtime check : both
// C++ : runtime library : Multi-threaded Debug (/MTd)

#include "stdafx.h"
#include "ClipboardHistory.h"
#include "..\..\Source\tracetool.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CClipboardHistoryApp

BEGIN_MESSAGE_MAP(CClipboardHistoryApp, CWinApp)
END_MESSAGE_MAP()


// CClipboardHistoryApp construction

CClipboardHistoryApp::CClipboardHistoryApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}


// The one and only CClipboardHistoryApp object

CClipboardHistoryApp theApp;
char PlugName[] = "ClipBoardHistory" ;
TCHAR ClassName [] = L"VS9TTCLIP" ;
WinTrace * PlugTraces  ;
HWND hwndNextViewer; 
HWND hClipboardWnd ;
bool IsPaused = false ;


struct CClipFormatData { UINT uFormat; LPCTSTR szFormatName; };

CClipFormatData g_aClipData[] = {
   { CF_TEXT,            _T("CF_TEXT") },
   { CF_BITMAP,          _T("CF_BITMAP") },
   { CF_METAFILEPICT,    _T("CF_METAFILEPICT") },
   { CF_SYLK,            _T("CF_SYLK") },
   { CF_DIF,             _T("CF_DIF") },
   { CF_TIFF,            _T("CF_TIFF") },
   { CF_OEMTEXT,         _T("CF_OEMTEXT") },
   { CF_DIB,             _T("CF_DIB") },
   { CF_DIBV5,           _T("CF_DIBV5") },
   { CF_PALETTE,         _T("CF_PALETTE") },
   { CF_PENDATA,         _T("CF_PENDATA") },
   { CF_RIFF,            _T("CF_RIFF") },
   { CF_WAVE,            _T("CF_WAVE") },
   { CF_UNICODETEXT,     _T("CF_UNICODETEXT") },
   { CF_ENHMETAFILE,     _T("CF_ENHMETAFILE") },
   { CF_HDROP,           _T("CF_HDROP") },
   { CF_LOCALE,          _T("CF_LOCALE") },
   { CF_OWNERDISPLAY,    _T("CF_OWNERDISPLAY") },
   { CF_DSPTEXT,         _T("CF_DSPTEXT") },
   { CF_DSPBITMAP,       _T("CF_DSPBITMAP") },
   { CF_DSPMETAFILEPICT, _T("CF_DSPMETAFILEPICT") },
   { CF_DSPENHMETAFILE,  _T("CF_DSPENHMETAFILE") },
   { 0, _T("") } 
};

//-------------------------------------------------------------------------

void PrintLastError (char * title)
{
   LPVOID lpMsgBuf;
   if (!FormatMessage( 
      FORMAT_MESSAGE_ALLOCATE_BUFFER | 
      FORMAT_MESSAGE_FROM_SYSTEM | 
      FORMAT_MESSAGE_IGNORE_INSERTS,
      NULL,
      GetLastError(),
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
      (LPTSTR) &lpMsgBuf,
      0,
      NULL ))
   {
      // Handle the error.
      return;
   }
   // Display the string.
   if (PlugTraces != NULL)
      PlugTraces->Error()->Send (title,(char *)lpMsgBuf) ;
   else
      TTrace::Error()->Send (title,(char *)lpMsgBuf) ;

   // Free the buffer.
   LocalFree( lpMsgBuf );
}

//-------------------------------------------------------------------------


void AddDataBlock (TraceNodeEx * clipTrace , TCHAR * format , HGLOBAL hgData, const SIZE_T uSize )
{
   LPVOID pvData;
   unsigned MaxByte ;
   TCHAR temp [101] ; 

   MaxByte = (unsigned) uSize ;
   if (MaxByte > 1000)
      MaxByte = 1000 ;

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

   // Use the given trace node to add dump
   _stprintf_s ((TCHAR *)temp, 100,L"%s . %d byte(s)", format , (unsigned) uSize) ;
   clipTrace->AddDump (temp, (char *) pvData , 0 , MaxByte) ;

   // Unlock the HGLOBAL.
   GlobalUnlock ( hgData );
}

//-------------------------------------------------------------------------

void WINAPI ShowClipboardContent(void)  
{ 
    LPSTR lpstr; 
    HGLOBAL hglb; 
    UINT uFormat = (UINT)(-1); 
    TraceNodeEx * clipTrace ;

    static UINT auPriorityList[] = 
    { 
        CF_TEXT ,
        CF_UNICODETEXT,
        CF_OEMTEXT,
        49307,   // Rich Text Format 
        CF_DIB ,
        CF_DIBV5 ,
        CF_METAFILEPICT,
        CF_ENHMETAFILE,
        CF_HDROP
    }; 

    uFormat = GetPriorityClipboardFormat(auPriorityList, 9); 

    //create an empty node, setting the left part to the text .
    // using a loop display the different formats in the clipboard as a dump

    clipTrace = new TraceNodeEx (PlugTraces->Debug()) ;

    switch (uFormat) 
    { 
    case CF_UNICODETEXT :
    case CF_TEXT: 
    case CF_OEMTEXT :
    case CF_HDROP:
        if (OpenClipboard(NULL))   // hwnd
        { 
            hglb = GetClipboardData(uFormat); 
            if (hglb == NULL)
            {
               PrintLastError("GetClipboardData error") ;
               clipTrace->leftMsg = "" ;
            } else {
                lpstr = (char*)GlobalLock(hglb); 

                //GetClientRect(hwnd, &rc); 

                if (uFormat == CF_UNICODETEXT) {
                    size_t len = wcslen( (wchar_t *)lpstr) ;
                    char  *pmb = (char *)malloc(len+1);
                    size_t i ;

                    size_t s = wcstombs_s (&i,pmb,len,(wchar_t *)lpstr,  len) ;
                    clipTrace->leftMsg = pmb ;
                    free (pmb) ;
                } else if (uFormat == CF_HDROP) {
                    int count, i, bufferSize ;
                    clipTrace->leftMsg = "<File list>" ;

                    //First call to know number of files
                    count = DragQueryFile((HDROP) hglb, 0xFFFFFFFF, NULL, 0);

                    TMemberNode * members ;
                    members = clipTrace->Members()->Add ("File list") ;
                    for (i=0; i < count ; i++)
                    {
                        // First call to know buffer size to allocate
                        bufferSize = DragQueryFile((HDROP)hglb, i, NULL, 0);
                        char  *Filename = (char *)malloc(bufferSize+1);

                        // get file name
                        DragQueryFileA((HDROP)hglb, i, Filename, bufferSize + 1);
                        members->Add (Filename) ;
                        free (Filename) ;

                    }
                } else { 
                    clipTrace->leftMsg = lpstr ;
                }

                GlobalUnlock(hglb); 
                CloseClipboard(); 
            }
        } 
        break; 

    case CF_DIB :
    case CF_DIBV5 :
    case CF_METAFILEPICT:
    case CF_ENHMETAFILE:
        clipTrace->leftMsg = "<Bitmap>" ;
        break;

    case 0: 
        clipTrace->leftMsg = "<Empty>" ;
        break; 

    default: 
        clipTrace->leftMsg = "<not text format>" ;
        break;

    } 

    COleDataObject xDataObj;

    if ( !xDataObj.AttachClipboard() )
    {
        clipTrace->Send() ;
        return;
    }

    FORMATETC        etc;
    CClipFormatData* pClip;
    TCHAR            szFormat[256];     // format name
    //TCHAR            FormatCode [20] ;

    // Get all the data and pass it to the doc for storage.

    xDataObj.BeginEnumFormats() ;

    while ( xDataObj.GetNextFormat ( &etc ))
    {
        //sprintf (FormatCode, " (%d)", etc.cfFormat) ; 

        // See if this is a built-in clipboard format.  If so, we already have
        // a description string for it - we just have to find it in the 
        // g_aClipData array.
        for ( pClip = &g_aClipData[0]; 0 != pClip->uFormat; pClip++ )
        {
            if ( etc.cfFormat == pClip->uFormat )
            {
                lstrcpy ( szFormat, pClip->szFormatName );
                //lstrcat ( szFormat, FormatCode) ;
                break;
            }
        }

        // If we didn't find the format in g_aClipData, then it's a custom
        // format, and we need to get the name from Windows.
        if (pClip->uFormat == 0)
        {
            GetClipboardFormatName ( etc.cfFormat, szFormat, 256 );
            //lstrcat ( szFormat, FormatCode) ;
        }

        HGLOBAL hgData;
        SIZE_T  uDataSize;

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

        if ( NULL != hgData )
        {
            uDataSize = GlobalSize ( hgData );
            AddDataBlock (clipTrace,szFormat, hgData, uDataSize ); 
            // Free the memory that GetGlobalData() allocated for us.
            GlobalFree ( hgData );
        }
        else
        {
            // The data isn't in global memory, so try getting an IStream 
            // interface to it.
            STGMEDIUM stg;

            if ( xDataObj.GetData ( etc.cfFormat, &stg ) )
            {
                switch ( stg.tymed )
                {
                case TYMED_HGLOBAL:
                    {
                        uDataSize = GlobalSize ( stg.hGlobal );
                        AddDataBlock (clipTrace, szFormat, stg.hGlobal, uDataSize );
                    }
                    break;

                case TYMED_ISTREAM:
                    {
                        LARGE_INTEGER li;
                        ULARGE_INTEGER uli;

                        li.HighPart = li.LowPart = 0;

                        if ( SUCCEEDED( stg.pstm->Seek ( li, STREAM_SEEK_END, &uli )))
                        {
                            HGLOBAL hg = GlobalAlloc ( GMEM_MOVEABLE | GMEM_SHARE, uli.LowPart );
                            void* pv = GlobalLock ( hg );

                            stg.pstm->Seek ( li, STREAM_SEEK_SET, NULL );

                            if ( SUCCEEDED( stg.pstm->Read ( pv, uli.LowPart, (PULONG) &uDataSize )))
                            {
                                GlobalUnlock ( hg );

                                AddDataBlock (clipTrace, szFormat, hg, uDataSize );
                                // Free the memory we just allocated.
                                GlobalFree ( hg );
                            }
                            else
                            {
                                GlobalUnlock ( hg );
                            }
                        }
                    }
                    break;  // case TYMED_ISTREAM
                }
                ReleaseStgMedium ( &stg );
            }
        }
    }   // end while
    clipTrace->Send() ;
}

//-------------------------------------------------------------------------

LRESULT APIENTRY ClipBoardWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
   switch (uMsg) 
   { 
   case WM_DESTROY:       
      ChangeClipboardChain(hwnd, hwndNextViewer); 
      return (LRESULT) NULL ; 
   case WM_CHANGECBCHAIN: 

       // wParam
       //    Handle to the window being removed from the clipboard viewer chain. 
       // lParam
       //    Handle to the next window in the chain following the window being removed. 
       //    This parameter is NULL if the window being removed is the last window in the chain. 

       // If the next window is closing, repair the chain. 

       if ((HWND) wParam == hwndNextViewer) 
           hwndNextViewer = (HWND) lParam; 

       // Otherwise, pass the message to the next link. 

       else if (hwndNextViewer != NULL) 
           SendMessage(hwndNextViewer, uMsg, wParam, lParam); 

       return (LRESULT) NULL ; 

   case WM_DRAWCLIPBOARD: 
      // Update the window by using Auto clipboard format. 
      if (IsPaused == false)
         ShowClipboardContent () ; // (hwnd); 

      // Pass the message to the next window in clipboard 
      // viewer chain. 

      if (hwndNextViewer != 0)
         SendMessage(hwndNextViewer, uMsg, wParam, lParam); 
      break ; // clipboard contents changed. 

   }
   return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

//-------------------------------------------------------------------------



// CClipboardHistoryApp initialization

BOOL CClipboardHistoryApp::InitInstance()
{
	CWinApp::InitInstance();

	return TRUE;
}

int CClipboardHistoryApp::ExitInstance()
{
   return CWinApp::ExitInstance();
}

//-------------------------------------------------------------------------


extern "C"
{

   //-------------------------------------------------------------------------

   // Get the plugin name 
   __declspec(dllexport) void  __cdecl GetPlugName (char * lpPlugName)//  __cdecl 
   {
      strcpy_s (lpPlugName, 50, PlugName) ;
   }

   //-------------------------------------------------------------------------

   //Initialise the plugin. Called after TraceTool load the plugin
   __declspec(dllexport) void __cdecl Start() 
   {

      PlugTraces = new WinTrace("CLIPBH" , "Clipboard History") ;
      PlugTraces->DisplayWin() ;

      // attach the window to the plugin (itself)
      PlugTraces->LinkToPlugin (PlugName, CST_PLUG_ONACTION) ; 

      // add a button on right (100 pixels)
      PlugTraces->CreateResource (103,CST_RES_BUT_RIGHT,100,"Show last");

      //----

      WNDCLASSEX wcex;
      wcex.cbSize          = sizeof(WNDCLASSEX); 
      wcex.style		   = WS_OVERLAPPED  ; 
      wcex.lpfnWndProc	   = (WNDPROC)ClipBoardWndProc;
      wcex.cbClsExtra	   = 0;
      wcex.cbWndExtra	   = 0;
      wcex.hInstance	   = theApp.m_hInstance;
      wcex.hIcon		   = 0;
      wcex.hCursor		   = ::LoadCursor(NULL, IDC_ARROW);
      wcex.hbrBackground   = (HBRUSH)(COLOR_WINDOW+1);
      wcex.lpszMenuName	   = (TCHAR *)ClassName;
      wcex.lpszClassName   = (TCHAR *)ClassName;
      wcex.hIconSm		   = 0 ;

      SetLastError(S_OK);
      ATOM classEx = RegisterClassEx(&wcex);
      if (!classEx)
         PrintLastError("RegisterClassEx failed") ;

      SetLastError(S_OK);
      hClipboardWnd = CreateWindow(
         ClassName,                 //   LPCTSTR lpClassName,
         L"",                       //   LPCTSTR lpWindowName,
         WS_OVERLAPPEDWINDOW,       //   DWORD dwStyle,
         0 ,                        //   int x,
         0 ,                        //   int y,
         0 ,                        //   int nWidth,
         0,                         //   int nHeight,
         ((HWND)-3),                //   HWND hWndParent : HWND_MESSAGE    
         NULL,                      //   HMENU hMenu,
         theApp.m_hInstance,               //   HINSTANCE hInstance,
         NULL);                     //   LPVOID lpParam

      if (!hClipboardWnd)
         PrintLastError("CreateWindow failed") ;

      hwndNextViewer = SetClipboardViewer(hClipboardWnd); 

   }

   //-------------------------------------------------------------------------

   //Stop the plugin (free any resources before unloading)
   __declspec(dllexport) void __cdecl Stop() 
   {
      ChangeClipboardChain(hClipboardWnd, hwndNextViewer); 

      if (DestroyWindow (hClipboardWnd)  == 0)
         PrintLastError("DestroyWindow failed") ;

      if (UnregisterClass (ClassName, theApp.m_hInstance) == 0)
         PrintLastError("UnregisterClass failed") ;

      if (PlugTraces == NULL)  // plugin stopped
         return ;

      delete PlugTraces ;
      PlugTraces = NULL;
   }

   //-------------------------------------------------------------------------

   // Called when the user click on a button, label or menu on a WinTrace. 
   // The plugin must call WinTrace.LinkToPlugin with CST_PLUG_ONACTION  in order to receive this event.
   // Parameters
   //    WinId  is the Wintrace Id
   //    ResourceId is the User created resource or a tracetool resource.See the Tracetool resources table above
   //    NodeId is the node id of the current selected trace (can be empty)
   // Return value : 
   //    when true : tracetool perform the default action 
   //    when false : tracetool don't perform any action

   __declspec(dllexport) BOOL __cdecl OnAction (char * WinId , int ResourceId ,char *  NodeId) 
   {
      if (PlugTraces == NULL)  // plugin stopped
         return true ;
      switch ( ResourceId )
      {
      case CST_ACTION_PAUSE       :   // Pause on
         IsPaused = true ;
         break ;     

      case CST_ACTION_RESUME      :   // resume from Pause
         IsPaused = false ;
         break ;      

      case 103                    :   // user defined action : "Show last"
         ShowClipboardContent() ;
         break ;      

      case CST_ACTION_CLOSE_WIN   :   // Close win
         return false ;                    // disable close button. Stop the plugin before closing
      }

      return true ;
   }

   //-------------------------------------------------------------------------

   //Called when a node is to be deleted on a WinTrace 
   //The plugin must call WinTrace.LinkToPlugin with CST_PLUG_ONBEFOREDELETE in order to receive this event.
   //WinId  is the WinTrace Id
   //NodeId is the node id of the current selected trace
   //Return value : 
   //when true : TraceTool delete the node 
   //when false : TraceTool don't delete the node
   __declspec(dllexport) BOOL __cdecl  OnBeforeDelete (char * WinId , char *  NodeId) 
   {
      return true ;
   }

   //-------------------------------------------------------------------------

   //Called every 500 ms. Can be used for example to refresh labels 
   //The plugin must call LinkToPlugin with CST_PLUG_ONTIMER in order to receive this event 
   __declspec(dllexport) void __cdecl OnTimer() 
   {
   }

   //-------------------------------------------------------------------------

}

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.

License

This article, along with any associated source code and files, is licensed under The Common Public License Version 1.0 (CPL)


Written By
Architect
Belgium Belgium
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions