Figure 1   BugslayerExt.cpp


 /*----------------------------------------------------------------------
 Microsoft Systems Journal - Bugslayer Column - January 2000
 John Robbins - www.jprobbins.com
 ----------------------------------------------------------------------*/
 
 // Include the usual suspects.
 #include <windows.h>
 // Include the WinDBG extension API file.  The WinDBG documentation
 // does not mention the 64 bit interface at all.  However, if you use
 // any of the 32-bit structures or definitions WinDBG complains.
 // Therefore, I guess that means you are supposed to use them.
 #define KDEXT_64BIT
 // Turn off some warnings that happen with WinDBG extensions.
 // Unreferenced formal parameter.
 #pragma warning ( disable : 4100 )
 // Signed/unsigned mismatches.
 #pragma warning ( disable : 4211 )
 // More signed/unsigned mismatches.
 #pragma warning ( disable : 4245 )  
 #include <WdbgExts.h>
 
 // The entire WinDBG API must be undecorated names.  Since this is a C++
 // file, I will just wrap the whole thing in an extern "C".
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /*//////////////////////////////////////////////////////////////////////
                         Definitions and Typedefs
 /////////////////////////////////////////////////////////////////////*/
 // The timer structure for each individual timer.
 typedef struct tag_TIMERDATA
 {
     // TRUE if the timer is active.
     BOOL  bIsActive   ;
     // The start time for this timer.
     DWORD dwStartTime ;
 } TIMERDATA , * PTIMERDATA ;
 
 // The number of timers.
 const int k_NUMTIMERS = 4 ;
 
 /*//////////////////////////////////////////////////////////////////////
                      File Scope Globals Definitions
 /////////////////////////////////////////////////////////////////////*/
 // The structure that contains all the WinDBG functions.  This is filled
 // in with the WinDbgExtensionDllInit function.  If you want to use the
 // wrapper macros in WdbgExts.h, the extension must have this name.
 static WINDBG_EXTENSION_APIS64 ExtensionApis ;
 // The version information supplied to WinDbgExtensionDllInit.
 static USHORT g_usMajorVersion ;
 static USHORT g_usMinorVersion ;
 
 // The version for this extension.  I don't know if the first two
 // numbers are important, but the third one must be
 // EXT_API_VERSION_NUMBER64 or WinDBG says that this extension is an
 // old 32-bit version.
 static EXT_API_VERSION g_stVersion =
     {
         3 ,
         5 ,
         EXT_API_VERSION_NUMBER64 ,
         0
     } ;
 
 // The individual timers.
 static TIMERDATA g_aTimers [ k_NUMTIMERS ] =
     {
         { FALSE , 0 } ,
         { FALSE , 0 } ,
         { FALSE , 0 } ,
         { FALSE , 0 }
     } ;
 
 /*//////////////////////////////////////////////////////////////////////
                        Implementation Starts Here
 /////////////////////////////////////////////////////////////////////*/
 
 // A DllMain in case I need it for resources and stuff.
 BOOL APIENTRY DllMain ( HINSTANCE hInst              ,
                         DWORD     ul_reason_for_call ,
                         LPVOID    /*lpReserved*/      )
 {
     switch ( ul_reason_for_call )
     {
         case DLL_PROCESS_ATTACH :
             // Shrink the working set a bit...
             DisableThreadLibraryCalls ( hInst ) ;
             break ;
         case DLL_THREAD_ATTACH  :
         case DLL_THREAD_DETACH  :
         case DLL_PROCESS_DETACH :
             break ;
     }
     return ( TRUE ) ;
 }
 
 // The initialization function.
 VOID WDBGAPI
     WinDbgExtensionDllInit ( PWINDBG_EXTENSION_APIS64 lpExtensionApis ,
                              USHORT                   usMajorVersion  ,
                              USHORT                   usMinorVersion   )
 {
     // Do a little structure copy action.
     ExtensionApis = *lpExtensionApis ;
     g_usMajorVersion = usMajorVersion ;
     g_usMinorVersion = usMinorVersion ;
 }
 
 // WinDBG calls this to get the extension version.
 LPEXT_API_VERSION WDBGAPI ExtensionApiVersion ( void )
 {
     return ( &g_stVersion ) ;
 }
 
 // The "echo" command.  This prints out the arguments to the Command
 // window.  This command is very useful when you are dumping memory in a
 // breakpoint command.  The breakpoint commands do not print the
 // commands as they are executing.
 // The echo command also handles "\n" as a carraige return/linefeed so
 // can space out the display if you are interested.
 // The echo command with no arguments will just do a CR/LF to the
 // Command window.
 DECLARE_API64 ( echo )
 {
     // Is there anything in the argument parameter?
     if ( ( NULL != args ) && ( '\0' != args[ 0 ] ) )
     {
         char szBuff[ MAX_PATH ] ;
         int iBuffCurr = 0 ;
         int iArgCurr = 0 ;
         while ( '\0' != args[ iArgCurr ] )
         {
             if ( '\\' == args[ iArgCurr ] )
             {
                 if ( 'n' == args[ iArgCurr + 1 ] )
                 {
                     if ( 0 != iBuffCurr )
                     {
                         szBuff[ iBuffCurr ] = '\0' ;
                         dprintf ( "%s" , szBuff ) ;
                         iBuffCurr = 0 ;
                         // Do the CR/LF
                         dprintf ( "\n" ) ;
                     }
                     else
                     {
                         dprintf ( "\n" ) ;
                     }
                     iArgCurr +=2 ;
                 }
                 else
                 {
                     szBuff[ iBuffCurr ] = args[ iArgCurr ] ;
                     iBuffCurr++ ;
                     iArgCurr++ ;
                 }
             }
             else
             {
                 szBuff[ iBuffCurr ] = args[ iArgCurr ] ;
                 iBuffCurr++ ;
                 iArgCurr++ ;
             }
         }
         if ( 0 != iBuffCurr )
         {
             szBuff[ iBuffCurr ] = '\0' ;
             dprintf ( szBuff ) ;
         }
     }
     else
     {
         dprintf ( "" ) ;
     }
 }
 
 // The helper function all the timer functions will call to show help.
 static void ShowTimerHelp ( void )
 {
     dprintf ( "WinDBG Timer Extensions\n" ) ;
     dprintf ( "Usage :  starttimer <timer id>\n" ) ;
     dprintf ( "         elapsetime <timer id>\n" ) ;
     dprintf ( "         stoptimer  <timer id>\n" ) ;
     dprintf ( " starttimer - Starts a timer going\n" ) ;
     dprintf ( " elapsetime - Reports elapsed milliseconds since timer"
               " start\n" ) ;
     dprintf ( " stoptimer  - Reports the time and ends the timer\n" ) ;
     dprintf ( "<timer id>  - A timer value between 1 and %d\n" ,
                k_NUMTIMERS ) ;
 }
 
 static BOOL ConvertParamToIndex ( int & iIndex , PCSTR args )
 {
     // Are there any arguments?
     if ( ( NULL == args ) && ( '\0' == args[ 0 ] ) )
     {
         ShowTimerHelp ( ) ;
         return ( FALSE ) ;
     }
     // Try to convert the argument into a number between 1 and
     // k_NUMTIMERS.
     iIndex = atol ( args ) ;
     if ( ( iIndex <= 0 ) || ( iIndex > k_NUMTIMERS ) )
     {
         dprintf ( "Invalid argument -- %s\n" , args ) ;
         ShowTimerHelp ( ) ;
         return ( FALSE ) ;
     }
     // Bump the value down to the index range.
     iIndex-- ;
     return ( TRUE ) ;
 }
 
 // The timer system.
 // starttimer <timer id>
 DECLARE_API64 ( starttimer )
 {
     int iIndex ;
     if ( TRUE == ConvertParamToIndex ( iIndex , args ) )
     {
         // Is this timer item already in use?
         if ( TRUE == g_aTimers[ iIndex ].bIsActive )
         {
             dprintf ( "Replacing active timer number %d\n" ,
                       iIndex + 1 ) ;
         }
         g_aTimers[ iIndex ].bIsActive = TRUE ;
         g_aTimers[ iIndex ].dwStartTime = GetTickCount ( ) ;
     }
 }
 
 // elapsedtime <timer id>
 DECLARE_API64 ( elapsedtime )
 {
     int iIndex ;
     if ( TRUE == ConvertParamToIndex ( iIndex , args ) )
     {
         if ( TRUE == g_aTimers[ iIndex ].bIsActive )
         {
             DWORD dwElapsed = GetTickCount ( ) -
                               g_aTimers[ iIndex ].dwStartTime ;
             dprintf ( "Elapsed time (%d) = %d ms\n" ,
                        iIndex + 1                   ,
                        dwElapsed                     ) ;
         }
         else
         {
             dprintf ( "Timer %d was not started\n" , iIndex ) ;
         }
     }
 }
 
 // stoptimer <timer id>
 DECLARE_API64 ( stoptimer )
 {
     int iIndex ;
     if ( TRUE == ConvertParamToIndex ( iIndex , args ) )
     {
         if ( TRUE == g_aTimers[ iIndex ].bIsActive )
         {
             DWORD dwElapsed = GetTickCount ( ) -
                               g_aTimers[ iIndex ].dwStartTime ;
             dprintf ( "Timer (%d) ran %d ms\n" ,
                       iIndex + 1               ,
                       dwElapsed                 ) ;
             g_aTimers[ iIndex ].bIsActive = FALSE ;
         }
         else
         {
             dprintf ( "Timer %d was not started\n" , iIndex ) ;
         }
     }
 }
 
 // The help command for this extension.  WinDBG will also call this if
 // the user uses the "?" command.
 DECLARE_API64 ( help )
 {
     dprintf ( "Bugslayer WinDBG Extension DLL\n" ) ;
     dprintf ( "Echo output\n" ) ;
     dprintf ( "Usage :  echo <text>\n" ) ;
     dprintf ( " Prints the text to the command window.\n" ) ;
     dprintf ( " The text can contain '\\n' to delineate CR/LF\n" ) ;
     ShowTimerHelp ( ) ;
 }
 
 // This closes the extern "C" from above.  This must be the last thing
 // in the file.
 #ifdef __cplusplus
 }
 #endif