How to detect if an OutputDebugString viewer is running


#1

Have you ever noticed that your program is running slowly because you have waaaaaay too many calls to OutputDebugString (ODS) ?

What’s worse, is when it’s a complete waste, because there is no program running to benefit from ODS calls.

Here’s a programmatic way to detect if a viewer is running
P.S. my favorite ODS viewer is DebugView++ https://github.com/djeedjay/DebugViewPP

The following code is based on VB code written by Carl Barnes.
Carl based his work on info found here: http://www.unixwiz.net/techtips/outputdebugstring.html

 PROGRAM

  INCLUDE('Windows.inc'),ONCE
  MAP
      OutputDebugStringNotReady(),LONG 
      MODULE('Standard Windows APIs')
         OpenEvent    (DWORD InDesiredAccess, BOOL InInheritHandle, |
                            *CSTRING InName),HANDLE,RAW,PASCAL,NAME('OpenEventA')
      !already declared in Windows.inc!  GetLastError (),DWORD,PASCAL
      !already declared in Windows.inc!  CloseHandle  (HANDLE InObject),BOOL,PASCAL
      END
  END

  CODE
  MESSAGE('An OutputDebugString View is ['& |
         CHOOSE( OutputDebugStringNotReady()=0, |
                 'Running', 'NOT Running') &']')

OutputDebugStringNotReady  PROCEDURE()!,LONG 
!Ported from VB6 Code written by *Carl Barnes*
!PSS: OutputDebugString is expensive requiring a switch to kernel mode to access event, mutex and MMF. See
!     http://www.unixwiz.net/techtips/outputdebugstring.html

hObject            HANDLE,AUTO
SYNCHRONIZE        DWORD(100000h) ! 10 0000
szEventName        CSTRING('DBWIN_BUFFER_READY') !case sensitive
RetError           LONG,AUTO
   CODE 	                                                        
   hObject = OpenEvent(SYNCHRONIZE, FALSE, szEventName)    
   IF hObject <> 0
      CloseHandle(hObject)
      RetError = 0                !We are ready
   ELSE
      RetError = GetLastError() 
                                          ! probably 2 = File Not Found,
                                          !  i.e. the Event name does not exist because there is no debugger
      IF RetError = 0 
         RetError = -1            ! no handle and no error, then say -1
      END          
   END
   RETURN RetError

#2

Mark, would it make sense to add this as a function call in centralised caller. That is, I have a procedure called DebugView that does the call to outputdebugstring. Is there an overhead to call this every time? That way I send when the user opens and not if he closes it.


#3

Hi Chris,

I check to see if there is an OutputDebugString Viewer running at program launch
When a viewer is not present, then I suppress the calls to OutputDebugString as they have some performance impact.

Note: I also add a menu pick to the frame’s menu, to check again for the viewer, which allows you to launch a viewer after the program is running, and have the program start sending messages.


#4

I did some performance testing on this back in January. I found that 100,000 ODS calls added slightly less than 5 seconds to a LOOP that contained nothing else but the ODS call and longvar += 1. Interestingly, the delay we see in debugview is not the delay your program experiences. IE: your code may be done making 100000 calls to ODS in 5 seconds, but it could take 10-15-20 seconds for all 100000 lines to be displayed in debugview.


#5

I think the performance issues are based on whether something is listening at all. Not that you’re waiting for the listener to finish listening.


#6

I havent seen that it matters that a viewer is active. I mentioned the delay in DBV because during high volume logging, it appears that things are much slower. It turns out that the app has been done with those calls for a long while. Filtering them out of DBV eliminates much of the delay since it isnt doing the work to format / display / scroll them.