Microsoft & .NET.NETHappy Breakpoints for Testing!

Happy Breakpoints for Testing! content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

by John Robbins of Wintellect

The other day I was testing a bunch of code for my upcoming book Debugging Microsoft .NET and Windows Applications (Microsoft Press) and found myself wishing there was a way to set breakpoints on all the functions in a particular source file. In order to initially verify that my unit test was actually doing anything worthwhile, I wanted to at least ensure I was executing each method in a particular file.

Since I was working with a new set of code, I was doing the initial testing and scrolling like mad so I could click in the margin next to each function to get that breakpoint set. After I’d scrolled half way through the file, I was cursing at myself thinking that there had to be a better way. After I got done with the initial set of testing, I simply had to take a look at finding a way to automate setting breakpoints for a file no matter what language I was using. At the rate I was going, I was going to wear the bottom off my poor optical mouse scrolling all over the place. Fortunately, the very cool extensibility model with Visual Studio .NET actually made it relatively easy to achieve my goal. Even better was instead of grinding through and doing an Add-In, it was something that was easily accomplished with a macro. The icing on the cake is that with the code at the end of this article, you can set, and more importantly, remove, those function breakpoints without messing up any of your carefully set existing breakpoints!

There’s two pieces of work necessary to achieve the goal. The first is to figure out how to find each function/method in a file. The second part is setting and removing the breakpoints. Finding the particular functions in a source file can be a daunting task involving parsers and all sorts of weird technologies such as FLEX and YACC. If you’ve ever worked on real parsers you know they are extremely hard to do. In fact, since the premise behind .NET is the language independence, there’s no telling how many languages you might have to write parsers for simply to find the function locations. While it would be nice to spend the next five years working on parsers, I just wanted a simple utility!

The good news is that Visual Studio .NET does all the heavy lifting for you and essentially hands you the parse tree for the current document through a very clean interface. If you search the MSDN for “Automation Object Model Chart” you’ll find the chart that shows you a set of very cool objects such as called CodeElement, CodeFunction, CodeClass, and CodeEnum. By enumerating and recursing these elements you’ll get the complete layout of what’s in a particular source file. Keep in mind that the source file enumeration is only available on files that are part of the open project. Given the fact that this works for all languages is such a huge feature I’m sure people will be doing all sorts of very cool tools that we always wished for in the past but didn’t have the time to write a complete parser.

If something as complicated as the parsing is already done for you, having complete access to the Debugger object to set or clear breakpoints is almost anticlimactic. The algorithm for setting breakpoints on all function entry is the following:

Get the code elements for the active document in the project
for each code element
    Is the element a Namespace, Class or Struct?
        Recurse the child elements
    Is the element a function or property?
        Get the line where this element starts
        Set a file and line breakpoint at that location

One thing I want to point out about SetBreakpointsOnAllCurrentDocFunctions is that after you run it, you’ll see the breakpoints set, but they might look like they are in the wrong place. For example, in a .NET program the breakpoint can be sitting on an attribute before the function. That’s perfectly fine as once you start debugging the debugger does the exact right thing and moves the breakpoint down to the first executing line of the function.

After I whipped up the first version of the SetBreakpointsOnAllCurrentDocFunctions macro, it ran just like I expected. However, further testing showed up some problems, not in my code, but in Visual Studio .NET that I need to make you aware of. The worst problem is with C++ header files. For some reason, nearly everything in the file is marked as a function and the starting and ending points for the elements don’t relate too reality in the file. I played around with it quite a bit and considered not processing header files, but since many people do put inline functions, I decided against it. What you’ll see are a bunch of breakpoints on empty lines and in comments but the good news is that you can forget about them because the debugger will ignore them as they can’t be set.

The second issue I found was that some C++ source files are not properly parsed by the environment and might be missing a function or two in the code model. In those cases, there’s nothing you can do to get the actual function unless you want to grind through the file yourself. The good news is that it’s not something you’ll run into very much. For those of you doing primarily .NET development everything lines up perfectly with Visual Basic .NET and C#.

The last issue I ran into was what got me thinking that I needed a way to easily remove any breakpoints put in by SetBreakpointsOnAllCurrentDocFunctions. If you click on the red dot breakpoint marker in the source file, you’ll find that it will never toggle off. You can clear the breakpoint by either right clicking on it and selecting Remove from the context menu or clearing it from the Breakpoint window.

If I was going to be setting all these breakpoints automatically, I simply had to have a way to clear them out. While I could have grabbed the breakpoints collection from the Debugger object and wiped it clear, having a macro remove your carefully placed breakpoints isn’t that useful. In reading about the Breakpoint object, I saw that Microsoft was really thinking ahead and gave us a Tag property where we could squirrel away a user defined string! All I had to do was uniquely identify any breakpoints I set and they’d be a piece of cake to remove. The one worry I had was that the Tag field wouldn’t have been saved between sessions, but a little experimentation proved it was. For the tag, I use the filename as part of it so when you run the RemoveBreakpointsOnAllCurrentDocFunctions macro it only removes the breakpoints put in by SetBreakpointsOnAllCurrentDocFunctions for the active file and leaves any others you set in that file alone.

Armed with SetBreakpointsOnAllCurrentDocFunctions and RemoveBreakpointsOnAllCurrentDocFunctions I’ve found that my testing is going easier because fewer than 200 lines of macro code quickly automate something I was doing manually all the time. Now you can easily find out if all the functions in a file are being called. As you hit each function, clear the breakpoint. At the end of the run, you’ll see exactly which functions haven’t been called. Good luck and crank that code coverage.

About the Author

John Robbins is the co-founder of Wintellect (, a consulting, debugging, and education firm that helps client’s ship better code faster. He is also the author of Debugging Microsoft .NET and Windows Applications (Microsoft Press) as well as the Bugslayer columnist for MSDN Magazine. Before founding Wintellect, John was an architect and product manager at NuMega Technologies for products such as BoundsChecker, TrueTime, and TrueCoverage. Prior to joining the software world, John was a Paratrooper and Green Beret in the U. S. Army.

‘ BreakPoints

‘ John Robbins
– Wintellect –

‘ A module
that will set and clear breakpoints at the entry point of
‘ all
functions in the current source file. 
What’s even cooler is
‘ that this
code will not screw up breakpoints you already have set!

Additionally, when removing breakpoints, it will only remove the

‘ breakpoints
put for the current source file.

‘ There are
some caveats:
‘ 0.  The breakpoints set by the
     macro show up as you’d
expect in the source windows as a red dot
     next to the line where
they were set.  However, you can
click on
     that dot all day long
as it will not clear it.  Either
RemoveBreakpointsOnAllCurrentDocFunctions or clear them from
window.  This seems to be a bug in
the IDE.
‘ 1.  There’s a bug in the CodeModel for C++
header files.  Pretty
     anything in one gets
called a function.  There’s no clean
way to
     double check, short of
parsing the file yourself, if the
     TextPoint values are
real.  If you run this on a header,
     get breakpoints all
over the place.  Fortunately, the
     is smart enough to
ignore them.
‘ 2.  The breakpoints are set at what the
     property says is the
first line.  This can be at the
start of an
     attribute or
something.  Don’t worry, the
debugger does the right
     thing and moves the
breakpoint to the first executable line ‘
     inside the
function.  (Go Microsoft!)  If a .NET method is
     the breakpoint is set
on the end of the function.
‘ 3.  There’s an odd bug you might run into
when debugging this code.
     After setting the
breakpoint, I access it to set the Tag field so
     I can identify which
breakpoints this macro set.  When
     that access seems to
cause a Null Reference exception in some
     cases.  However, if you don’t set breakpoints,
it will run fine.
‘ 4.  In some C++ source files, the CodeModel
occasionally does not
     have a function or two
that’s shown in the code window. 
     you can’t get them,
you can’t set breakpoints on them.
‘ 5.  The active document returned from
DTE.ActiveDocument is odd.
     It’s the last code
document that had focus.  This can
mean you’re
     looking at the Start
Page, but setting breakpoints on something
     hidden.  These macros force you to have the
cursor in a real code
     window before they
will run.

‘ Version 1.0
– August 28, 2002

Imports EnvDTE
Public Module BreakPoints
    Const k_ConstantTagVal As String =
“Wintellect Rocks “
    Public Sub
‘ Get the current source file name doing all
the checking.
CurrDoc As Document =
If (CurrDoc Is Nothing) Then
Exit Sub
End If
‘ Get the source file name and build up the
tag value.
Dim SrcFile As String =
Dim TagValue As String =

‘ While I might have a document, I still need
to check this
‘ is one I can get a code model
Dim FileMod As FileCodeModel = 
If (FileMod Is Nothing) Then
MsgBox(“Unable to get code model from document.”, _
MsgBoxStyle.OKOnly, _
Exit Sub
End If
‘ Everything’s lined up to
ProcessCodeElements(FileMod.CodeElements, SrcFile,
    End Sub
    Private Sub
ProcessCodeElements(ByVal Elems As CodeElements, _
ByVal SrcFile As String,
ByVal TagValue As String)
‘ Look at each item in this
Dim CurrElem As CodeElement
For Each CurrElem In
‘ If I’m looking at a class, struct or
namespace, I need 
‘ to recurse.
If (vsCMElement.vsCMElementNamespace =
CurrElem.Kind) Or _
(vsCMElement.vsCMElementClass = CurrElem.Kind) Or _
(vsCMElement.vsCMElementStruct = CurrElem.Kind) Then
‘ This is kinda odd.  Some CodeElements use a
                ‘ property to
get sub elements while others use 
‘ Members.
Dim SubCodeElems As CodeElements = Nothing
SubCodeElems = CurrElem.Children
SubCodeElems = CurrElem.Members
SubCodeElems = Nothing
End Try
End Try
If (Not
(SubCodeElems Is Nothing)) Then
(SubCodeElems.Count > 0) Then
ProcessCodeElements(SubCodeElems, _
SrcFile, _
End If
End If
            ElseIf (CurrElem.Kind = _
vsCMElement.vsCMElementFunction) Or
(CurrElem.Kind = _
vsCMElement.vsCMElementProperty) Then
‘ Interestingly, Attributed COM component
‘ show up broken out into their
functions.  The
‘ thing is that their StartPoint property is
‘ and throws an exception when
Dim TxtPt As TextPoint
TxtPt = CurrElem.StartPoint
TxtPt = Nothing
End Try
If (Not
(TxtPt Is Nothing)) Then
Dim LineNum As Long =
                    Dim Bps As
‘ Plop in one of my
Bps = DTE.Debugger.Breakpoints.Add(File:=SrcFile, _
‘ Get the BP from the collection and set the
‘ property so I can find the ones I
‘ There’s some sort of bug here.  If you debug
‘ through this with the VSA debugger, it
‘ (0x8004005’s) on accessing the
‘ collection occasionally.  However, if
‘ run it, life is good.
Dim Bp As EnvDTE.Breakpoint
For Each Bp In
Bp.Tag = TagValue
End Try
End If
End If
    End Sub
    Public Sub
‘ This is a much simpler function since I set
the tag value on
‘ the breakpoints, I can remove them simply by
‘ through all BPs and removing
CurrDoc As Document =
If (CurrDoc Is Nothing) Then
Exit Sub
End If
Dim TagValue As String =
Dim CurrBP As EnvDTE.Breakpoint
For Each CurrBP In
If (CurrBP.Tag = TagValue) Then
End If
    End Sub
    Private Function
GetCurrentDocument() As
‘ Check to see if a project or solution is
open.  If not,
‘ can’t get at the code model for the
Dim Projs As System.Array =
If (Projs.Length = 0) Then
MsgBox(“You must have a project open.”, _
MsgBoxStyle.OKOnly, _
GetCurrentDocument = Nothing
Exit Function
End If
‘ Getting the active document is a little
‘ DTE.ActiveDocument will return the active
code document, but
‘ it might not be the real ACTIVE window.  It’s quite 
‘ disconcerting to see macros working on a
document when you’re
‘ looking at the Start Page.  Anyway, I’ll ensure the
‘ document is really the active
Dim CurrWin As Window = DTE.ActiveWindow
CurrWinDoc As Document =
Dim CurrDoc As Document = DTE.ActiveDocument
‘ Gotta play
the game to keep from null ref exceptions in the 
‘ real active doc check
Dim WinDocName As String =
If Not
(CurrWinDoc Is Nothing) Then
WinDocName = CurrWinDoc.Name
End If
Dim DocName As String =
If Not
(CurrDoc Is Nothing) Then
DocName = CurrDoc.Name
End If
If ((CurrWinDoc Is Nothing) And _
(WinDocName <> DocName)) Then
MsgBox(“The active cursor is not in a code document.”, _
MsgBoxStyle.OKOnly, _
GetCurrentDocument = Nothing
Exit Function
End If
‘ While I might have a document, I still need
to check this is
‘ one I can get a code model
Dim FileMod As FileCodeModel = 
If (FileMod Is Nothing) Then
MsgBox(“Unable to get code model from document.”, _
MsgBoxStyle.OKOnly, _
GetCurrentDocument = Nothing
Exit Function
End If
GetCurrentDocument = CurrDoc
    End Function
    Private Function
BuildTagValue(ByVal Doc As Document) As
BuildTagValue = k_ConstantTagVal + Doc.FullName
    End Function

# # #

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories