Classic VB Corner
How do you track down what's really going on inside your compiled EXEs?
Have you ever had one of those problems that only manifests itself in a compiled
EXE, that you simply cannot reproduce in the Classic Visual Basic IDE? Or even
worse, that only occurs on the client's machines, and not on yours at all? I'd
like to show you the technique I've pretty much switched over to, entirely,
because it works in both the IDE and EXE.
Almost undoubtedly, you've been using Debug.Print ever since you started using
Classic VB. It's often the single most valuable debugging tool in your toolbox,
as you can use it to generate a running stream of status messages without interfering
in any way with the normal course of execution. But just as surely as you've
used this useful tool in the past, you've also wished it wasn't limited to the
Fortunately, Win32 offers us the OutputDebugString
function, which performs almost exactly the same function as Debug.Print
does. This function is incredibly easy to use and can be wrapped up as an almost
functionally equivalent replacement for Debug.Print as such:
Private Declare Sub OutputDebugString Lib "kernel32" _
Alias "OutputDebugStringA" (ByVal lpOutputString As String)
Public Sub DebugOutput(ByVal Data As String, _
Optional ByVal CrLf As Boolean = True)
' Output to the ether... Someone may be listening...
If CrLf Then
One of the nice things about Debug.Print is that you can suppress the linefeed
that follows your output by using a semicolon at the end of the line:
Debug.Print "Trailing semi-colon ";
Debug.Print "suppresses linefeed."
To achieve that same effect with our DebugOutput routine above, I added an
optional parameter that assumes you want the CrLf output but allows you to override
it. Unfortunately, there's no way for us to entirely emulate the DOS legacy
Print command with it's ability to embed successive strings using semicolons
and commas, so you'll need to patch up any implied concatenation. Migrating
such statements from Debug.Print to DebugOutput requires this sort of tweak:
Debug.Print "The value: "; x
DebugOutput "The value: " & CStr(x)
But where does that output go when you're running an EXE? Well, here are two
very handy (and free!) tools I'd like to recommend. Either can read the output
from OutputDebugString. My favorite is DBWin32,
written by Grant Schenck, because it supports all 32-bit Windows platforms.
If you've ever downloaded the SysInternals suite, you may already have DebugView,
which was written by Mark Russinovich and requires at least Windows 2000 to
run. Something I never noticed until writing this column is that the two don't
play nice together -- only run one at a time for best results.
Both utilities allow you to save the results to a text file, but DBWin is a
bit friendlier in this regard, as it operates in an MDI manner, effectively
isolating the output from each process into its own child window. DebugView
does offer you the ability to filter what output it displays, though, so you
can still isolate just what you want. (And, yes, this can be an issue, as Windows
is full of debug code!)
Granted, you can always rig your application so it outputs all the debugging
information to a text file or database. But that's a tremendous overhead to
bear for what should be extremely rare circumstances. Sending this information
off into the ether, though, is nearly harmless from an efficiency perspective,
as it incurs virtually no overhead. And it's there when you need it. Just be
sure that your debugging messages are something you're willing to allow others
to see. Anyone who ever runs tools like DBWin32 or DebugView can see this output.
And now, so can you!
Karl E. Peterson wrote Q&A, Programming Techniques, and various other columns
for VBPJ and VSM from 1995 onward, until Classic VB columns were dropped entirely
in favor of other languages. Similarly, Karl was a Microsoft BASIC MVP from 1994
through 2005, until such community contributions were no longer deemed valuable.
He is the author of VisualStudioMagazine.com's new Classic
VB Corner column. You can contact him through his Web
site if you'd like to suggest future topics for this column.