Summary

 < Free Open Study > 



Error Handling in the Add-in

There appears to be no better place to discuss error handling than in this chapter on debugging. I have already stressed the point of placing error handlers in every method that could possibly encounter an error.

Visual Studio .NET introduces true structured error handling. The error-handling methodology that was used in previous versions of Visual Basic will still work in VB .NET—you just can't mix the new Try/Catch structured handling with the old On Error GoTo ErrHandler construct in the same procedure. Most of my peers decry the evils of the GoTo statement. I certainly understand the shortcomings of GoTo, but I've never shared their total disdain for it. I, along with others, believe there are places for GoTo, albeit not many. VB is missing a "basic" statement, Continue, which allows you to go to the bottom of a For/Next, Do/Loop, and While/Wend loop. Without this statement, which C/C++ and other languages such as Clipper (dBase Compiler) have, GoTo provides the only easy way to get to the bottom of a loop. Sometimes, a loop that is already nested to several levels can only be made more complex by trying to maintain a structured approach for getting to the bottom of it. Well, enough of that! I'm beating a dead horse here. Regardless of your stand on the old syntax, assuming you programmed in earlier versions of VB, the code in this book uses the new structured error-handling code.

Because this book is not meant to explain all of the new things in .NET, I won't go into a lot of detail about the Try/Catch coding construct. There are two ways that I normally use error-handling code. First, I might include the whole procedure's code in a Try/Catch sequence. Listing 4-1 illustrates this approach.

Listing 4-1: Protecting the Whole Procedure

start example
 Public Sub CatchAnyProcedureError()     Dim s As String     Dim I As Integer     Try         For i = 1 to 10             S = s & "a"         Next i         ' add as many lines as needed     Catch e As System.Exception         MsgBox("We encountered an error: " & e.Message)     End Try End Sub 
end example

Obviously, the method in Listing 4-1 does nothing but illustrate how to protect the whole subroutine in case of an error. The second way that I normally use error-handling code is to specifically catch errors in a small section of a method where I might try opening a file and want to take action within the context of that small section of code. The section of code shown in Listing 4-2 illustrates a sequence of code in which an error will be raised if the file name being erased does not exist. Likewise, if the new file cannot be created or written to, an error will be raised. You must always protect code that does file handling.

Listing 4-2: Selective Error Handling

start example
     Private Sub Test2()         Dim count As Integer         Dim fileHandle As Integer         ' might have a code sequence here         '....         '....         For count = 1 To 5             fileHandle = FreeFile()             ' if the file being killed does not exist, an error             ' will be raised.             ' also, if a file can't be opened, ignore and try the next             Try                  Kill("TEST" & count & ".TXT")                 FileOpen(fileHandle, "TEST" & count & ".TXT", OpenMode.Output)                 PrintLine(fileHandle, "This is a sample.")                 FileClose(fileHandle)             Catch e As System.Exception                 ' ignore the error             End Try         Next         ' more code...         '...     End Sub 
end example

Again, the code does not really do anything or make a lot of sense, but it does illustrate the protection of a small block of code within a larger procedure.

Automating Production of Error-Handling Code

Because this book's topic is writing add-ins, let's add more functionality to the test add-in you created and enhanced in Chapters 2 and 3 to automate insertion of error-handling code.

First, you will add a new method to the Connect class named GenLocalErrorTrap, which is shown in Listing 4-3. This new method will retrieve the selected procedure and insert a Try/Catch error-handling construct around all of the executable code in the procedure. It does this by looking for the first line of executable code in the procedure and then inserting the Try statement. It then looks for the End Sub or End Function. Upon finding it, it will insert the Catch statement prior to writing the End statement to the output string. It will then put the code back into the active code window.

Listing 4-3: GenLocalErrorTrap Method

start example
     Shared Sub GenLocalErrorTrap()         Dim sLine As String         Dim sTemp As String         Dim sTemp2 As String         Dim sWord As String         Dim i As Long         Dim nL As Integer         Dim bFound As Boolean         Dim sTempLine As String         Dim sProcType As String         Dim sProcName As String         Dim bFoundDefLine As Boolean         Try             sTemp = GetCodeFromWindow()             sTemp2 = ""             nL = MLCount(sTemp, 0)             bFound = False             For i = 1 To nL                 ' look for the first line of code                 sLine = MemoLine(sTemp, 0, i)                 ' get the procname to make the goto label unique                 If Not bFoundDefLine Then                     If InStr(sLine, "Sub ") > 0 Then                         sProcType = "Sub"                     ElseIf InStr(sLine, "Function ") > 0 Then                         sProcType = "Function"                     Else                         sTemp2 = sTemp2 & sLine & vbCrLf                         GoTo JustOutPutThisLine                     End If                     bFoundDefLine = True                     sTempLine = sLine                     Do While Trim$(sTempLine) <> ""                         sWord = GetToken(sTempLine, "_")                         ' when we find the Proc type, term the loop                         ' and retrieve the name next below                         If sWord = "Sub" Or sWord = "Function" Then Exit Do                         If Trim$(sWord) = "" Then Exit Do                         sProcName = sWord                     Loop                     sProcName = GetToken(sTempLine, "_")                 End If                 If Not bFound Then                     If InStr(sLine, "Sub ") > 0 Or _                        InStr(sLine, "Function ") > 0 Or _                        InStr(sLine, "Global ") > 0 Or _                        InStr(sLine, "Const ") > 0 Or _                        InStr(sLine, "Dim ") > 0 Then                         sTemp2 = sTemp2 & sLine & vbCrLf                     ElseIf Left$(Trim$(sLine), 1) = "'" Then                        sTemp2 = sTemp2 & sLine & vbCrLf                     ElseIf Trim$(sLine) = "" Then                         sTemp2 = sTemp2 & sLine & vbCrLf                     Else                         bFound = True                         sTemp2 = sTemp2 & vbCrLf & " Try" & vbCrLf                         If Trim$(sLine) <> "End " & sProcType Then                             Tsemp2 = sTemp2 & sLine & vbCrLf                         Else                             sTemp2 = sTemp2 & _                             "           Catch e as System.Exception" & vbCrLf                             sTemp2 = sTemp2 &_                                 "     MsgBox(" & Chr(34) & "Error in " & _                                 sProcName & ": " & Chr(34) & " & _                                 e.Message)" & vbCrLf                             sTemp2 = sTemp2 & "     End Try" & vbCrLf                             sTemp2 = sTemp2 & sLine & vbCrLf                         End If                     End If                 Else                     If InStr(sLine, "End " & sProcType) > 0 Then                         sTemp2 = sTemp2 & _                                     " Catch e as System.Exception" & vbCrLf                         sTemp2 = sTemp2 & _                             "         MsgBox(" & Chr(34) & "Error in " & _                             sProcName & ": " & Chr(34) & " & _                             e.Message)" & vbCrLf                         sTemp2 = sTemp2 & "        End Try" & vbCrLf                         sTemp2 = sTemp2 & sLine & vbCrLf                         Exit For                     Else                         sTemp2 = sTemp2 & sLine & vbCrLf                     End If                 End If JustOutPutThisLine:             Next             ' now the proc with err code added is ready to paste             PutCodeBack(sTemp2)             Exit Sub         Catch e As System.Exception             MsgBox("Error in GenLocalErrorTrap: " & e.Message)         End Try     End Sub 
end example

Next, you will insert another supporting method named GetToken, which is shown in Listing 4-4. This is a parsing function that retrieves the next token from a source line. The comments in the code describe how this function is called. You can pass it a delimiter or a set of characters that are not delimiters. This function is another of the library procedures provided with this book's code.

Note 

GetToken consumes the source string, which is passed by reference. This means that as token is returned, the token is removed from the front of the string. Therefore, if you want to maintain the original string, you must save a copy of it before your first call to GetToken.

Listing 4-4: GetToken

start example
     Shared Function GetToken(ByRef srcline As String, _                                ByVal rsNonDelimiters As String, _                                Optional ByVal rsDel As String = "N") _                                As String         '-----         ' If rsDel = "N" then the rsNondelimiters is a list of non delimiters         ' which is added to a list of AN Chars (a-z, A-Z, 0-9), which are         ' always assumed to be non delimiters.         ' If rsDel="D" then rsNonDelimiters is the list of delimiters, anything         ' else in the string is assumed to be non delimiter.         ' Get Next word from srcLine. An alphanumeric and any character         ' found in strDelimtrs is a valid char for the word. i.e. a char         ' which is not alphanumeric and not found in the delimiter string         ' will terminate the word. If space is not a delimiter it must be         ' included in the strNonDelimitrs.         ' Typical call is:         '     srcLine = GetToken(srcLine, " ().!" or         '     srcLine = GetToken(srcLine, " ,")         ' where space and are the delimiters         ' Any non alphanumeric and not in the " ().!" would terminate the string         ' To include " in the set of allowable chars, concatenate         ' chr(34) with the' other non delimiters.         ' If non delimiters are not supplied, don't compare for them         ' and performance is increased...         '-----         Dim n_w As String ' staging area for return string         Dim FC As String ' first char of string         Dim lsTemp As String         Dim lsTemp2 As String         Const AN_DIGITS = "abcdefghijklmnopqrstuvwxyz" & _                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"         Try             n_w = ""             If rsDel = "N" Then                 lsTemp2 = AN_DIGITS & rsNonDelimiters             Else                 lsTemp2 = rsNonDelimiters             End If             Do While Trim$(srcline) <> ""                 FC = Left$(srcline, 1)                 lsTemp = "*" & FC & "*"                 If rsDel = "N" Then                     If Not (lsTemp2 Like lsTemp) Then                         ' save all but first char for next call                         srcline = Mid(srcline, 2)                         If Trim$(n_w) <> "" Then                             GetToken = n_w                             Exit Function                         End If                         Else                             n_w = n_w & FC                             srcline = Mid(srcline, 2)                         End If                     Else                         If (lsTemp2 Like lsTemp) Then                             ' save all but first char for next call                             srcline = Mid(srcline, 2)                             If Trim$(n_w) <> "" Then                                 GetToken = n_w                                 Exit Function                             End If                     Else                             n_w = n_w & FC                             srcline = Mid(srcline, 2)                         End If                 End If             Loop             GetToken = n_w             Exit Function         Catch e As System.Exception             MsgBox("Error in GetToken: " & e.Message)             GetToken = n_w         End Try     End Function 
end example

Next, you add another node to the TreeView named Proc Error Handler, as shown in Figure 4-11. Follow the same procedure for adding a child node to the TreeView that you learned in Chapter 3.


Figure 4-11: Adding the Proc Error Handler node to the TreeView

Finally, add a new Case statement to the AfterSelect event in the frmTreeView. This new code is shown in bold in Listing 4-5.

Listing 4-5: Error Handling in the AfterSelect Event

start example
     Private Sub tvMenu_AfterSelect(ByVal sender As Object, _               ByVal e As System.Windows.Forms.TreeViewEventArgs) _               Handles tvMenu.AfterSelect         Dim i As Integer         Select Case UCase$(e.Node.Text)               Case "SMART DESKTOP" 'ignore root clicks               Case "BLOCK COMMENT"                   Call Connect.BlockComment()               Case "UNCOMMENT"                   Call Connect.BlockUnComment()               Case "BLOCK CHANGE"                   Call Connect.BlockChange()               Case "BLOCK DELETE"                   Call Connect.BlockDelete()               Case "PROC ERROR HANDLER"                   Call Connect.GenLocalErrorTrap()               Case Else                   MsgBox("Please click on a Child Node.", _                                MsgBoxStyle.Information, "Unknown Request")         End Select     End Sub 
end example

Testing the Error Handler Generator

After all of the code has been successfully added to the add-in, press F5 to test the new code. A second version of Visual Studio .NET will start. I have created a standard Windows application (WindowsApplication2) to use in testing the add-in. It has several procedures of dummy code, which you will find in the code for this chapter. Once you have selected the test project, go to the Add-in Manager and connect the add-in. Next, select Tools Smart Desktop. This will cause the add-in menu TreeView form to be loaded. Open the nodes of the TreeView. Finally, select the whole Sub Test, as shown in Figure 4-12, and click the Proc Error Handler TreeView node.

click to expand
Figure 4-12: Select the procedure to receive an error handler.

The error handler will be automatically added to the procedure, as shown in Figure 4-13. A simple exercise that you can try on your own would be to clone the GenLocalErrorTrap method, rename the cloned method, and modify it to block only a selected block of code. You would then add another node to the TreeView menu and add a call to the newly cloned method in the AfterSelect event of the TreeView.

click to expand
Figure 4-13: Error handler placed in Sub Test()

Again, in this enhancement to the add-in, you have been able to add new functionality, or business logic, without having to have any interface to the .NET extensibility model. By building and reusing the same basic library methods (GetCodeFromWindow and PutCodeBack), you are able to concentrate on the creative part of building add-in functionality, which manipulates blocks of code in the text editor of Visual Studio .NET. Believe me, there are unlimited things you can do with the selected code block once you have it extracted into a string. All you have to do is put your thinking cap on (or keep it on). In VBCommander, I have added well over 100 new features to the VB 6.0 IDE. Almost every one of them was created as a result of encountering something repetitive that I needed to automate when operating with blocks of code. Necessity really is the mother of invention.



 < Free Open Study > 



Writing Add-Ins for Visual Studio  .NET
Writing Add-Ins for Visual Studio .NET
ISBN: 1590590260
EAN: 2147483647
Year: 2002
Pages: 172
Authors: Les Smith

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net