Click here to Skip to main content
15,923,168 members
Articles / Programming Languages / Visual Basic
Article

Highlight VS.NET code position from exception while debugging

Rate me:
Please Sign up or sign in to vote.
1.95/5 (5 votes)
14 Apr 2004CPOL 33.9K   9  
This snippets provide a way to extract line number information from an exception's stack trace and highlighting the line in source code when the debugger is attached. I copied it out from a large project and it won't therefore be usable 'as is', but the essentials could easily be reused.

Intention

In our commercial apps, there's a specially designed Windows Forms dialog in use to display runtime error messages (like 'file not found' and the like) to the user. However, when debugging, this dialog shows up like it would in the release version, but is enhanced with a list of the exceptions that occurred. Each exception can be clicked on, and on doing so, the corresponding source code position will immediately be found and highlighted in the IDE on behalf of the file name and line number information contained in the exception's message text and stack trace details. This proved extremely useful. The essentials are shown below.

Object containing the exception information:

VB
Public Class cdoErrStackframe
    Public Filename As String
    Public LineNumber As Integer
    Public ColumnNumber As Integer
    Public FunctionName As String
VB
Public Sub New(ByVal frX As StackFrame)
    With frX
        Filename = .GetFileName
        LineNumber = .GetFileLineNumber
        ColumnNumber = .GetFileColumnNumber
        FunctionName = .GetMethod.Name
    End With
End Sub
VB.NET
Public Sub New(ByVal sFilename As String, ByVal sFunctionName_
                        As String, ByVal iLinenumber As Integer)
    Filename = sFilename
    LineNumber = iLinenumber
    ColumnNumber = 1
    FunctionName = sFunctionName
End Sub
VB.NET
    Public Overrides Function ToString() As String
        Dim fName As String
        fName = Mid(Filename, Filename.LastIndexOf("\") + 2)
        fName = Left(fName, fName.LastIndexOf("."))
        Return fName & "::" & FunctionName & "() -- " & LineNumber
    End Function
End Class

This snippet shows a way to extract the necessary information from the exception to a string output. It is sure to be version-dependant, but works fine ;-)

VB.NET
Friend Function VisualizeError(ByVal errX As cdoError,_
    ByVal Cascade As cdoErrors) As cdoSrv.cdoErrorResults
    Dim frmX As New frmMsg
    Dim errC As cdoError
    'displays a single error; if the cascade is defined
    'it will be displayed except its last entry
    With frmX
        .Text = errX.Title
        .lblMsg.Text = errX.Msg
        .lblExplanation.Text = errX.Details
        .lblRemedy.Text = errX.Remedy
        If Not (Cascade Is Nothing) Then
            For I As Integer = 0 To Cascade.ErrorList.Count - 2
                errC = Cascade.ErrorList.Item(I)
                .lstCascade.Items.Add(errC)
            Next
        End If
        'visualize the stack trace if necessary
        If errX.fromException And Debugger.IsAttached Then
         Try
          Dim sf As New System.Diagnostics.StackTrace(True)
          For J As Integer = 0 To sf.FrameCount - 1
           If Not (sf.GetFrame(J).GetFileName Is Nothing) Then
            If sf.GetFrame(J).GetFileName.IndexOf("cdoErrors.vb") <= 0 Then
             .lstStack.Items.Add(New cdoErrStackframe(sf.GetFrame(J)))
            End If
           End If
          Next
          'secondly attach the entry points extracted from
          'the exception stack trace string
          'as they stand in errx.details (which, in fact,
          'contains the result of exception.tostring)
          Dim sX As String = errX.Details
          Dim sY(0) As String
          Dim sFilename As String, sFunction As String, iLine As Integer
          For I As Integer = 0 To Len(sX) - 1
           If sX.Substring(i).StartsWith("   at") Then
            ReDim Preserve sY(UBound(sY) + 1)
            sY(UBound(sY)) = sX.Substring(I + Len("   at"))
            If sY(UBound(sY)).IndexOf(vbLf) > 0 Then
              sY(UBound(sY)) = Trim(Left(sY(UBound(sY)),_
              sY(UBound(sY)).IndexOf(vbLf) - 1))
            Else sY(UBound(sY)) = Trim(sY(UBound(sY)))
           End If
          Next
          For I As Integer = UBound(sY) To 1 Step -1
           If sY(i).IndexOf("vb:line") > 0 Then
            sFunction = sY(I).Substring(0, sY(i).IndexOf("("))
            If sFunction.IndexOf(".") > 0 Then
              sFunction = sFunction.Substring(sFunction.LastIndexOf(".") + 1)
            sFilename = sY(i).Substring(sY(i).IndexOf(" in ") + Len(" in "))
            If sFilename.IndexOf(":line") > 0 Then
              sFilename = sFilename.Substring(0, sFilename.LastIndexOf(":"))
            iLine = CInt(sY(i).Substring(sY(i).LastIndexOf(":line ")_
                    + Len(":line ")))
            .lstStack.Items.Add(New _
                   cdoErrStackframe(sFilename, sFunction, iLine))
           End If
          Next
         Catch ex As Exception
           'ignore this
         End Try
           .lstStack.Visible = CBool(.lstStack.Items.Count > 0)
        End If
        'display and wait for the user to react
        .DoLayout(errX)
        .ShowDialog()
        'if there was a validation, then try to focus the control
        Try
            errX.ValidatedControl.Focus()
        Catch ex As Exception
            'ignore this
        End Try
        'clear the collection now
        Clear()
        Return .Result
    End With
End Function

Navigation essentials (shows how to get the IDE to open a file and highlight a certain line in source code):

VB.NET
 Private Sub lstStack_DoubleClick(ByVal sender_
As Object, ByVal e As System.EventArgs) Handles lstStack.DoubleClick
     'dive into the code
     If lstStack.SelectedItem Is Nothing Then Return
     Try
      If Not Debugger.IsAttached Then Return
      With CType(lstStack.SelectedItem, cdoErrStackframe)
       Dim DTE As EnvDTE.DTE
       DTE = _
        System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE")
       Dim itmX As EnvDTE.ProjectItem = _
                          DTE.Solution.FindProjectItem(.Filename)
       itmX.Open(EnvDTE.Constants.vsViewKindCode).Activate()
       Dim objSel As EnvDTE.TextSelection_
                          = DTE.ActiveDocument.Selection
       objSel.StartOfDocument()
       objSel.MoveToLineAndOffset(.LineNumber,_
                                   .ColumnNumber)
       objSel.SelectLine()
      End With
     Catch ex As Exception
         'can't do anything about that, dead end
         Beep()
     End Try
 End Sub

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO en-software GmbH
Austria Austria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --