Capture OutputDebugString output

Introduction

The OutputDebugString Windows API call allows applications to produce output which can be collected by an independent debugger process reading from a pipe. The OutputDebugString function itself is exposed by the win32api module in pywin32, and is simple enough to use. Capturing the messages which applications produce using this call requires a specific set of pipes and buffers.

Update: For a useful application of this see Ken McFadden's LogDbgView class

A thread on python-list started by Dan Brotherston led to some experimentation and eventually to the solution below, reproduced with Dan's permission although slightly modified by me. The crucial thing turned out to be creating the mmap buffer with ACCESS_WRITE (although we're not quite sure why).

#
# Original code by Dan Brotherston
#
import sys
import mmap
import struct
import win32event

buffer_ready = win32event.CreateEvent (
  None, 0, 0,
  "DBWIN_BUFFER_READY"
)
data_ready = win32event.CreateEvent (
  None, 0, 0, 
  "DBWIN_DATA_READY"
)
buffer = mmap.mmap (0, 4096, "DBWIN_BUFFER", mmap.ACCESS_WRITE)

while True:
  #
  # Signal that we're ready to accept debug output
  #
  win32event.SetEvent (buffer_ready)
  if win32event.WaitForSingleObject (data_ready, win32event.INFINITE) == win32event.WAIT_OBJECT_0:
    buffer.seek (0)
    #
    # The first DWORD is the process id which generated the output
    #
    process_id, = struct.unpack ("L", buffer.read (4))
    data = buffer.read (4092)
    if "\0" in data:
      string = data[:data.index ("\0")]
    else:
      string = data
    
    print "Process %d: %s" % (process_id, string)

To see it in action, run this snippet which will keep spawning processes to send debug output

import os, time

for i in range (10):
  os.system (
    'python -c "import os;import win32api;win32api.OutputDebugString ("""From %d""" % os.getpid ())"'
  )
  time.sleep (0.5)