Summary

 < Free Open Study > 



Enhancing the Smart Desktop Add-in

Now you're going to use the new function that I just created in the Smart Desktop add-in that you've been developing thus far in the book. First, use the new procedure in the CloneProcedure feature, so that the developer will not have to select the whole procedure before invoking the add-in. This will make it easier and faster to use and, after all, the primary reason for writing add-ins is to increase the developer's productivity. You can find the code for these new features in MyAddinTest1 in the code for Chapter 8. If you're following along with me, load the project into Visual Studio .NET.

To use this new procedure, perform the following tasks:

  1. Add the new GetWholeProc method to the Connect class.

  2. Change the call from GetCodeFromWindow to GetWholeProc.

  3. Introduce some new features to the add-in that will use the GetWholeProc method.

Enhancing CloneProcedure

Listing 8-8 shows the CloneProcedure method of the Connect class. The only line changed is in bold. The call to GetCodeFromWindow changed to a call to GetWholeProc.

Listing 8-8: The Modified CloneProcedure Method

start example
 Shared Sub CloneProcedure()    Dim s As String    Dim i As Integer    Dim rs As String    Try       ' get selected proc from active window       s = GetWholeProc() ' GetCodeFromWindow()       If InStr(1, s, " Sub ", 0) = 0 And _          InStr(1, s, " Function ", CompareMethod.Binary) = 0 Then          MsgBox("Please select a whole Procedure             to be cloned.", MsgBoxStyle.Exclamation)          Exit Sub       End If       Dim oFrm As New CloneProc()       rs = oFrm.Display(s)       oFrm.Dispose()       If rs <> "" Then          AddMethodToEndOfDocument(rs)       End If    Catch e As System.Exception       'MsgBox("Error: " & e.Message, MsgBoxStyle.Critical, "Clone Procedure")       Exit Sub    End Try End Sub 
end example

Next, you add the new method, GetWholeProc, to the Connect class. Copy it from the macro module into the Connect class and place it at the end of the class. You make two changes to the method when you move it. First, you add the keyword Shared to the function definition line. This will allow it to be seen from anywhere in the project. Second, you substitute the object oVB for DTE in the one line where it is used. Listing 8-9 displays the new method with the changed lines in bold.

Listing 8-9: The GetWholeProc Method Modified for Use in the Add-in

start example
 Shared Function GetWholeProc() As String    Dim ts As TextSelection = oVB.ActiveWindow().Selection    Dim ep As EditPoint = ts.ActivePoint.CreateEditPoint    Dim sLine As String    Dim i As Integer    Try       ' if the user has selected the whole proc,       ' then just return it       ' otherwise select it for them...       If Len(ts.Text) > 0 Then          If (InStr(1, ts.Text, "Sub ", 1) > 0 Or _             InStr(1, ts.Text, "Function ", 1) > 0) And _             (InStr(1, ts.Text, "End Sub", 1) > 0 Or _             InStr(1, ts.Text, "End Function", 1) > 0) _                Then                 Return ts.Text              End If              GoTo SelectTheProc           Else SelectTheProc:              " Get the start of the proc              ep.MoveToPoint(ep.CodeElement(EnvDTE.vsCMElement.                  vsCMElementFunction).GetStartPoint(vsCMPart.vsCMPartWhole))              ' move selection start point to top of proc              ts.MoveToPoint(ep, False)              ' back up to previous line looking for comments              i = 0              Do                 ep.LineUp()                 ts.MoveToPoint(ep, False)                 ts.SelectLine()                 sLine = ts.Text                 If Left(Trim(sLine), 1) <> ""' Then                    ep.LineDown()                    ts.MoveToPoint(ep, False)                    Exit Do                 End If                 i = i + 1              Loop              ' if the count of comment lines > 0 the ts point is set properly              ' else we must move it back to the original              ep.LineDown(i + 1)              ' move to bottom of proc              ep.MoveToPoint(ep.CodeElement(EnvDTE.vsCMElement                  .vsCMElementFunction).GetEndPoint(vsCMPart.vsCMPartWhole))              ' select the proc              ts.MoveToPoint(ep, True)              Return ts.Text           End If        Catch           System.Windows.Forms.MessageBox.Show              ("You must either select the whole           procedure or your cursor must be within           the procedure to be selected.")       Return ""    End Try End Function 
end example

Running the Modified CloneProcedure Feature

Now that you've made all of the changes to use the new and improved method for retrieving a procedure, run the add-in to test the changes. Because you already have the add-in (MyAddinTest1 from the Chapter 8 code) loaded into Visual Studio, simply press F5 to test the add-in. Assuming that you've made the changes correctly and have no compile errors, the second copy (add-in client) of Visual Studio .NET should start automatically. When it does, select Chap 8 Sample Project1 from the code for Chapter 8 as the project to run. When the sample project is loaded into the client copy of Visual Studio, open the Add-in Manager dialog box, check both boxes for MyFirstAddin1, and click OK to close the dialog box. This will connect the add-in.

From the Tools menu, select the Smart Desktop menu option. It should be the top menu item on the Tools menu. This will cause the add-in's UI form to appear. Open the TreeView. If Form1.vb (code window) is not already open in the client copy of Visual Studio .NET, open it and place the cursor anywhere in the TestMacroProcedureSelecting method. Next, click the CloneProcedure node in the TreeView. The code for the selected procedure will be retrieved and displayed in the Clone Procedure form, as shown in Figure 8-11.

click to expand
Figure 8-11: Clone procedure display form

At this point, you're going to change the name of the procedure in the CloneProc form to NewTestProc. Finally, click the PasteToModule button on the form. This causes the form to paste the cloned procedure back to the client code window. The cloned procedure is shown in Figure 8-12.

click to expand
Figure 8-12: New cloned procedure

To close the test, disconnect the add-in by deselecting the add-in in the Add-in Manager dialog box. Next, return to the copy of Visual Studio where the add-in is running and click the Stop Debugging button. This will automatically close the client instance of Visual Studio.

Documenting a Procedure

In this section, I introduce one additional feature for the Smart Desktop add-in that will use the GetWholeProc method. This feature can retrieve the comments that are immediately before and following a procedure definition line. It takes those comments, extracts the parameters, and applies a document template to the extracted data. It formalizes the programmer-supplied comments, adds some additional data, and creates a formal-looking documentation template. It then puts the procedure back into the module.

Obviously, many of the data parameters and the template itself are hardcoded in this add-in. In a real add-in, the template would be read from a file, which could be customized. The user name and company name would be retrieved from the registry.

The code in Listing 8-10 does the work of reading through the captured procedure and applying the formal document template to the procedure. I don't explain this code in detail, mainly due to its length and because it's very straight-forward in what it does. At a high level, it does the following things:

  • Extracts comment lines before and following the procedure definition line

  • Extracts the parameters from the procedure definition line

  • Extracts the return value if the procedure is a function

  • Substitutes live values for keywords found in the template, such as Copyright, Created By, Created Date, and so forth

  • Concatenates all the template data and places it into the procedure

  • Returns the procedure to the module

Listing 8-10: DocTemplate Method

start example
 Shared Sub DocTemplate()    ' Apply a formal template to the captured procedure    Dim i As Long    Dim iPtr As Integer    Dim nL As Integer    Dim bParameters As Boolean    Dim bPurpose As Boolean    Dim sOut As String    Dim sLine As String    Dim bFoundSub As Boolean    Dim sDocTemplate As String    Dim sWord As String    Dim sTempParams As String    Dim cComStr As String    Dim sPar As String    Dim sRetVal As String    Dim sProcToCopy As String    Dim sProcType As String    Dim j As Integer    Dim k As Integer    Const sPurpose = "Purpose:"    Const sParameters = "Parameters:"    Const sDateCreated = "Date Created:"    Const sAuthor = "Author:"    Const sUserName = "Les Smith"    Const sCopyright = "Copyright:"    Const sCompanyName = "HHI Software, Inc."    Const sReturns = "Returns:"    Dim s As String    Try       ' create the doc template       ' In a production add-in this would be read from a file       ' so that the file could be customized...       s = "'***************************************" & vbCrLf       s = s & "'* Name: ProcName" & vbCrLf       s = s & "'* Purpose:" & vbCrLf       s = s & "'*" & vbCrLf       s = s & "'* " & vbCrLf       s = s & "'* Parameters:" & vbCrLf       s = s & "'*" & vbCrLf       s = s & "'* Returns:" & vbCrLf       s = s & "'*" & vbCrLf       s = s & "'* Author: " & vbCrLf       s = s & "'* Date Created:" & vbCrLf       s = s & "'* CopyRight: " & vbCrLf       s = s & "'* Date Last Changed: " & vbCrLf       s = s & "'***************************************" & vbCrLf       sDocTemplate = s       ' if user selected the text prior to clicking the       ' button, get that code       sProcToCopy = ""       sProcToCopy = GetWholeProc()       sOut = ""       sDocTemplate = ""       bFoundSub = False       ' find out some stuff about the template       bPurpose = (InStr(1, sDocTemplate, sPurpose, 1) > 1)       bParameters = (InStr(1, sDocTemplate, sParameters, 1) > 1)       nL = MLCount(sProcToCopy, 0)       cComStr = ""       For i = 1 To nL          sLine = MemoLine(sProcToCopy, 0, i)          If Not bFoundSub Then             If InStr(sLine, "Sub ") > 0 Or _                InStr(sLine, "Function ") > 0 Then                sOut = sOut & sLine & vbCrLf                bFoundSub = True                ' get sub name                Do While Trim$(sLine) <> ""                   sWord = GetToken(sLine, "")                   If InStr("Sub_Function", sWord) > 0 Then Exit Do                   sProcType = sWord                Loop                ' get sub name                sWord = GetToken(sLine, "_")                'get parameters if applicable                If bParameters Then                   sRetVal = ""                   sTempParams = ""                   j = CountOccurrences(",", sLine)                   For k = 1 To j                      ' the next parm                      sPar = Left$(sLine, InStr(sLine, ",") - 1)                      ' remove it from sline                      sLine = Mid$(sLine, InStr(sLine, ",") + 1)                      sTempParams = sTempParams & "'* " & _                                     Trim(sPar) & vbCrLf                      Next k                      ' get last parm                      k = InStr(sLine, ")") - 1                      If k > 0 Then                         sPar = Left$(sLine, InStr(sLine, ")") - 1)                         sTempParams = sTempParams & "'* " & _                                        Trim(sPar) & vbCrLf                      End If                      sLine = Mid$(sLine, InStr(sLine, ")"))                      sPar = Trim$(GetToken(sLine, " _"))                      If Left$(sPar, 3) = "As " Then                         sRetVal = Mid$(sPar, 4)                      End If                   End If                   ' now get any comments after the proc def line                   Do While i <= nL                      i = i + 1                      sLine = MemoLine(sProcToCopy, 0, i)                      ' if this is a comment line let's uncomment it and                      ' put in cComStr, if a blank, skip it...                      If Left$(Trim$(sLine), 2) = "'*" Then                         If InStr(sLine, "***") > 1 Or _                            InStr(sLine, "--") > 1 Or _                            InStr(sLine, "$$$") > 1 Or _                            InStr(sLine, "___") > 1 Then                         Else                            sLine = Trim$(sLine)                            sLine = Mid$(sLine, 3)                            sLine = Trim$(sLine)                            cComStr = cComStr & "'* " & sLine & vbCrLf                         End If                      ElseIf Left$(Trim$(sLine), 1) = ""' Then                         If InStr(sLine, "***") > 1 Or _                            InStr(sLine, "--") > 1 Or _                            InStr(sLine, "$$$") > 1 Or _                            InStr(sLine, "___") > 1 Then                         Else                            sLine = Trim$(sLine)                            sLine = Mid$(sLine, 2)                            sLine = Trim$(sLine)                            cComStr = cComStr & "'* " & sLine & vbCrLf                         End If                      ElseIf Trim$(sLine) = "" Then                         ' discard blank lines before Sub/Function                      Else                         Exit Do                      End If                   Loop                   If Trim$(cComStr) <> "" Then                      ' strip the last crlf so we don't get a blank line                      iPtr = InStrRev(cComStr, vbCrLf)                      If iPtr > 0 Then                         cComStr = Left$(cComStr, iPtr - 1)                      End If                   End If                   If Trim$(sTempParams) <> "" Then                      ' strip the last crlf so we don't get a blank line                      iPtr = InStrRev(sTempParams, vbCrLf)                      If iPtr > 0 Then                         sTempParams = Left$(sTempParams, iPtr - 1)                      End If                   End If                   ' substitute into the template                   sDocTemplate = Replace(sDocTemplate, _                                           "ProcName", sWord)                   sDocTemplate = Replace(sDocTemplate, _                                           sCopyright, _                                           sCopyright & " " & _                                           sCompanyName)                   sDocTemplate = Replace(sDocTemplate, _                                           sDateCreated, _                                           sDateCreated & " " & _                                           TodaysDate)                   sDocTemplate = Replace(sDocTemplate, _                                           sAuthor, _                                           sAuthor & " " & _                                           sUserName)                   If bPurpose And Trim$(cComStr) <> "" Then                      sDocTemplate = Replace(sDocTemplate, _                                              sPurpose, _                                              sPurpose & " " & _                                              vbCrLf & cComStr)                   End If                   If bParameters And Trim$(sTempParams) <> "" Then                      sDocTemplate = Replace(sDocTemplate, _                                              sParameters, _                                              sParameters & " " & _                                              vbCrLf & sTempParams)                   End If                   If sRetVal <> "" Then                      sDocTemplate = Replace(sDocTemplate, _                                              sReturns, _                                              sReturns & " " & sRetVal)                   ElseIf sProcType = "Sub" Then                      sDocTemplate = Replace(sDocTemplate, sReturns, "")                   Else                      sDocTemplate = Replace(sDocTemplate, _                                              sReturns, _                                              sReturns & _                                              " Return Value not specified")                   End If                   sOut = sOut & sDocTemplate                   sOut = sOut & sLine & vbCrLf                Else                   ' we have not found the proc def line yet                   ' if this is a comment line let's uncomment it and                   ' put in cComStr, if a blank, skip it...                   If Left$(Trim$(sLine), 2) = "'*" Then                      If InStr(sLine, "***") > 1 Or _                         InStr(sLine, "--") > 1 Or _                         InStr(sLine, "$$$") > 1 Or _                         InStr(sLine, "___") > 1 Then                      Else                         sLine = Trim$(sLine)                         sLine = Mid$(sLine, 3)                         sLine = Trim$(sLine)                         cComStr = cComStr & "'* " & sLine & vbCrLf                      End If                   ElseIf Left$(Trim$(sLine), 1) = ""' Then                      If InStr(sLine, "***") > 1 Or _                         InStr(sLine, "--") > 1 Or _                         InStr(sLine, "$$$") > 1 Or _                         InStr(sLine, "___") > 1 Then                      Else                         sLine = Trim$(sLine)                         sLine = Mid$(sLine, 2)                         sLine = Trim$(sLine)                         cComStr = cComStr & "'* " & sLine & vbCrLf                      End If                   ElseIf Trim$(sLine) = "" Then                      ' discard blank lines before Sub/Function                   Else                      sOut = sOut & sLine & vbCrLf                   End If                End If             Else                sOut = sOut & sLine & vbCrLf             End If          Next          ' paste the code back to the window          PutCodeBack(sOut)       Exit Sub    Catch e As System.Exception    End Try End Sub 
end example

In addition to adding this code to the Connect class, you should add a new node to the TreeView in Form1 and name the node Document Procedure. You'll see the new node when you execute the add-in. I'm sure that by now you're familiar with how to add a node to the TreeView, so I won't go through that process.

Listing 8-11 shows a helper function called by DocTemplate. It simply counts occurrences of an expression in a string.

Listing 8-11: CountOccurrences Helper Method

start example
 Shared Function CountOccurrences(ByVal rsExp As String, _                                     ByVal rsStr As Object) As Long    ' Returns the number of occurrences of rsExp (expression)    ' found in rsStr (string)    ' Returns 0 of no occurrences found.    Dim pPos As Integer    Dim lPos As Integer    Dim nPos As Integer    Dim nFirst As Integer    Dim lCnt As Integer    Try       pPos = 0 ' previous find       lPos = 0 ' return position of right char       nPos = 1 ' position of next right most char       nFirst = 1       lCnt = 0       ' loop thru every char in string until we       ' find the last occurrence       Do          lPos = InStr(nPos, rsStr, rsExp, 1)          If lPos > 0 Then             nPos = lPos + 1             pPos = lPos             lCnt = lCnt + 1          Else             Exit Do          End If       Loop       Return lCnt    Catch e As System.Exception    End Try End Function 
end example

Listing 8-12 shows the code added to the TreeView event handler in Form1.vb. The new code is in boldface. It calls the DocTemplate method of the Connect class to retrieve and document the selected procedure.

Listing 8-12: AfterSelect Event of TreeView

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 "CLONE PROCEDURE"          Call Connect.CloneProcedure()       Case "DOCUMENT PROCEDURE"          Call Connect.DocTemplate()       Case Else          MsgBox("Please click on a Child Node.", _             MsgBoxStyle.Information, "Unknown              Request")    End Select End Sub 
end example

Now I have shown all of the code that has been added to retrieve and document the selected procedure. To run the add-in, follow the normal procedure of debugging: Press F5. When the second copy of the Visual Studio opens, connect the add-in by going to the Add-in Manager and checking both boxes representing MyAddinTest1.

You should open Chap 8 Sample Project1 and open the Form1.vb code module. Place the cursor anywhere in the TestMacroProcedureSelecting procedure. Display the add-in's TreeView menu form and select the Document Procedure node. Listing 8-13 shows the procedure before it has been documented.

Listing 8-13: Procedure Before Being Documented

start example
 ' Comment for TestMacroCommenting ' Comment Line 2 Sub TestMacroProcedureSelecting()    Dim s As String    Dim i As Integer    Dim l As Long    s = "String"    l = 12    i = 231 End Sub 
end example

After the code has been documented and placed back into the module, it will appear as shown in Figure 8-13.

click to expand
Figure 8-13: Documented code



 < 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