The Windows Collection

 < Free Open Study > 

Cloning a Procedure

One of the most useful features that an add-in can provide is the capability to clone objects, including procedures. In this section, you will enhance your add-in once again, with probably the most useful tool yet! You will use the add-in that you have been building throughout the book thus far.

First, you need to add another menu item to the TreeView. Load up the MyAddinTest1 solution and open the menu form (Form1.vb). Right-click the TreeView control and select Properties from the pop-up menu. The property window should be displayed for the TreeView control. Click the Nodes property and then click the ellipsis to open the TreeNode Editor. Click the top-level node (Smart Desktop) of the TreeView. Finally, click the AddChild button and type Clone Procedure into the Label box. Click the OK button to close the designer. If you open the TreeView by clicking the plus sign (+) on the top-level node, you will see that you have added your new menu item.

Next, you need to add a handler for the new menu option. To do so, go to the code for Form1.vb and add the code in Listing 5-12 to the tvMenu_AfterSelect event handler. Add the two boldface lines just before the Case Else statement in the event handler.

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

You now need to add two new methods to the Connect class (Connect.vb). The first is named CloneProcedure, which is shown in Listing 5-13. When the add-in user selects a procedure to clone, the CloneProcedure method will retrieve the selected procedure from the active document. CloneProcedure will call GetCodeFromWindow to get the selected block from the active window. After performing a cursory test to ensure that the user has selected a procedure, it calls a public Display function of a new form that you have yet to build. This form will display the selected procedure, and allow the user to change the name of the procedure and elect to either paste the new procedure to the current window or copy the new procedure to the Clipboard.

Listing 5-13: CloneProcedure

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 = 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

You can actually call a function in a form, pass it some data, have it manipulate the data, and have it return the resulting data to the calling code. What this amounts to is logically calling a form! This is accomplished by the code that appears in bold in Listing 5-13. If the Display Function of the CloneProc form returns an empty string, it means that the user elected to copy the new procedure to the Clipboard. If there is something in the string, the user has elected to paste the new procedure to the end of the current document. This is accomplished by acall to AddMethodToEndOfDocument, passing the new procedure that has been returned in the string rs.

Next, you add the AddMethodToEndOfDocument method to the Connect class. This method was developed earlier and shown in Listing 5-11. The purpose of this method is to paste the new procedure at the end of current document (module).

Finally, you add a new form to the add-in project. You create the form, create a scrolling TextBox, and place two command buttons on the TextBox. Listing 5-14 contains the complete code for the form.

Listing 5-14: CloneProc Form Code

start example
 Option Strict On Public Class CloneProc     Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code "     Public Sub New()         MyBase.New()         'This call is required by the Windows Form Designer.         InitializeComponent()         'Add any initialization after the InitializeComponent() call     End Sub     'Form overrides dispose to clean up the component list.     Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)         If disposing Then             If Not (components Is Nothing) Then                 components.Dispose()             End If         End If         MyBase.Dispose(disposing)     End Sub     'Required by the Windows Form Designer     Private components As System.ComponentModel.IContainer     'NOTE: The following procedure is required by the Windows Form Designer     'It can be modified using the Windows Form Designer.     'Do not modify it using the code editor.     Friend WithEvents txtProcToClone As System.Windows.Forms.TextBox     Friend WithEvents btnPasteToModule As System.Windows.Forms.Button     Friend WithEvents btnCopyToClipboard As System.Windows.Forms.Button     <System.Diagnostics.DebuggerStepThrough()> _     Private Sub InitializeComponent()         Me.txtProcToClone = New System.Windows.Forms.TextBox()         Me.btnPasteToModule = New System.Windows.Forms.Button()         Me.btnCopyToClipboard = New System.Windows.Forms.Button()         Me.SuspendLayout()         '         'txtProcToClone         '         Me.txtProcToClone.Multiline = True         Me.txtProcToClone.Name = "txtProcToClone"         Me.txtProcToClone.ScrollBars = System.Windows.Forms.ScrollBars.Both         Me.txtProcToClone.Size = New System.Drawing.Size(512, 229)         Me.txtProcToClone.TabIndex = 0         Me.txtProcToClone.Text = ""         '         'btnPasteToModule         '         Me.btnPasteToModule.Location = New System.Drawing.Point(389, 240)         Me.btnPasteToModule.Name = "btnPasteToModule"         Me.btnPasteToModule.Size = New System.Drawing.Size(115, 32)         Me.btnPasteToModule.TabIndex = 1         Me.btnPasteToModule.Text = "&Paste To Module"         '         'btnCopyToClipboard         '         Me.btnCopyToClipboard.Location = New System.Drawing.Point(263, 240)         Me.btnCopyToClipboard.Name = "btnCopyToClipboard"         Me.btnCopyToClipboard.Size = New System.Drawing.Size(115, 32)         Me.btnCopyToClipboard.TabIndex = 2         Me.btnCopyToClipboard.Text = "&Copy To Clipboard"         'Label1         '         Me.Label1.Location = New System.Drawing.Point(16, 240)         Me.Label1.Name = "Label1"         Me.Label1.Size = New System.Drawing.Size(192, 24)         Me.Label1.TabIndex = 3         Me.Label1.Text = _             "Change the name of the Method and click the desired button."         '         'CloneProc         '         Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)         Me.ClientSize = New System.Drawing.Size(514, 277)         Me.Controls.AddRange(New System.Windows.Forms.Control() _          {Me.btnCopyToClipboard, Me.btnPasteToModule, Me.txtProcToClone})         Me.Name = "CloneProc"         Me.Text = "CloneProc"         Me.TopMost = True         Me.ResumeLayout(False)     End Sub #End Region     Dim sTextSave As String     Dim sOrigType As String     Dim sOrigName As String     Dim bFormLoading As Boolean     Dim mbWait As Boolean     Public Function Display(ByVal sText As String) As String         Dim sTemp As String         Dim sWord As String         Dim i As Integer         sTextSave = sText         ' get the "Sub Name("         sTemp = Microsoft.VisualBasic.Left(sText, InStr(sText, "(") - 1)         If InStr(sTemp, "Sub") > 0 Then             sOrigType = "Sub"         Else             sOrigType = "Function"         End If         ' loop to get proc orig name         ' when loop terminates, sOrigName is the name         Do While Len(Trim$(sTemp)) > 0             sWord = Connect.GetToken(sTemp, "_")             If Trim$(sWord) <> "" Then                 sOrigName = sWord             Else                 Exit Do             End If         Loop             Me.Show()             mbWait = True             Do While mbWait             System.Windows.Forms.Application.DoEvents()         Loop         sTemp = sTextSave         Return sTemp         Return sTextSave         End Function     Private Sub UpdateFunctionReturns()         ' If the procedure is a function, get the         ' name and propagate it through the function         ' also propagate any changes from the sub to a         ' function and vice versa through the proc.         Dim sWord As String         Dim NextWord As String         Dim sTemp As String         Dim nL As Integer         Dim sTemp2 As String         Dim i As Integer         Dim sNewName As String         Dim sNewType As String         Dim sLine As String         Dim sTempLine As String         Dim bFoundProcType As Boolean         sTemp = Me.txtProcToClone.Text         sTemp2 = ""         nL = Connect.MLCount(sTemp, 0)         For i = 1 To nL             sLine = Connect.MemoLine(sTemp, 0, i)             ' if Proc Def Line get new name, assumming it was changed             If Not bFoundProcType And _                 (InStr(sLine, "Sub ") > 0 Or _                 InStr(sLine, "Function ") > 0) _                 Then                 ' loop to get proc new name and new type                 ' when loop terminates, sNewName is the name                 bFoundProcType = True                 sTempLine = sLine                 Do While Trim$(sTempLine) <> ""                     sWord = Connect.GetToken(sTempLine, "")                 If sWord = "Sub" Then                     sNewType = "Sub"                     Exit Do                 ElseIf sWord = "Function" Then                     sNewType = "Function"                     Exit Do                 End If             Loop             sNewName = Connect.GetToken(sTempLine, "_")         ElseIf bFoundProcType Then             ' if the type changed, we must substitute the new type             ' for the old type and change any functions name returns             ' if new type is a function             sLine = Replace(sLine, sOrigType, sNewType)             sLine = Replace(sLine, sOrigName, sNewName)         End If GetNextLine:         ' write the output string         sTemp2 = sTemp2 & sLine & vbCrLf         Next         Me.txtProcToClone.Text = sTemp2     End Sub     Private Sub CloneProc_Load(ByVal sender As System.Object, ByVal e As _            System.EventArgs) Handles MyBase.Load         Me.txtProcToClone.Text = sTextSave     End Sub     Private Sub btnCopyToClipboard_Click(ByVal sender As System.Object, _           ByVal e As _           System.EventArgs) _           Handles btnCopyToClipboard.Click         Dim datobj As New System.Windows.Forms.DataObject()         UpdateFunctionReturns()         datobj.SetData(System.Windows.Forms.DataFormats.Text, txtProcToClone.Text)         mbWait = False     End Sub     Private Sub btnPasteToModule_Click(ByVal sender As System.Object, ByVal e As _            System.EventArgs) Handles btnPasteToModule.Click         UpdateFunctionReturns()         sTextSave = Me.txtProcToClone.Text         mbWait = False     End Sub     Protected Overrides Sub Finalize()         MyBase.Finalize()     End Sub     Private Sub CloneProc_Closed(ByVal sender As Object, _             ByVal e As System.EventArgs) Handles MyBase.Closed         sTextSave = ""         mbWait = False     End Sub End Class 
end example

Two major methods of interest are in the form in Listing 5-14. The first is the Display function. This function facilitates the "calling" of the form from the CloneProcedure method of the Connect class. This function puts the passed parameter, in this case a procedure to be cloned, into the module-level variable sTextSave. The contents of sTextSave then gets placed into the TextBox of the form in the CloneProc_Load event. It then sets a Boolean, mbWait, to True. Finally, the method shows the form and loops in a DoEvents loop, waiting on mbWait to be changed to False. This Boolean will be set to false by either of the button handler events.

The second major method of interest is UpdateFunctionReturns. Once the user has changed the name of the procedure in the TextBox and one of the two buttons is clicked, the Display function breaks out of the wait loop. At that point, it calls the UpdateFunctionReturns method. This method loops through each line of code in the cloned procedure, replacing any occurrence of the original name of the procedure with the new name. You can even change the procedure from a Sub to a Function or vice versa.

After you add the new form and all of the new code previously described to the project, you run the add-in, as I have illustrated in previous chapters. In the second, or client, version of Visual Studio, select the WindowsApplication1 project. Next, select the procedure named MNZ in total, as shown in Figure 5-6.

click to expand
Figure 5-6: Selecting the procedure to be cloned

Now, click the Clone Procedure node of the TreeView in the add-in's menu form. This will cause the CloneProc form to be loaded with the selected procedure displayed in its text box, as shown in Figure 5-7.

click to expand
Figure 5-7: CloneProc form

Then change the name of the procedure from MNZ to MakeNullZero. Finally, click the Paste to Module button. The new procedure will be added to the end of the module as shown in Figure 5-8.

click to expand
Figure 5-8: Cloned procedure

The new functionality enhances your add-in with a very useful feature. Of course, you can use your imagination and add to the functionality of the UpdateFunctionReturns method so that it will make adjustments to the return value in case the user changes from a Function to Sub, for example.

 < 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 © 2008-2017.
If you may any questions please contact us: