Examining the Macro Recorder CodeWhen using macros and add-ins, the EnvDTE COM object is what gives you the properties, methods, and events that enable you work to with the objects in the Visual Studio .NET IDE. Using the properties, methods, and events of the EnvDTE object, you can create your own macro code or modify the code generated by the macro recorder. If you look at the References node of a project in the Macros IDE, you'll notice that the following objects are referenced:
Most of those objects are COM objects that are also used in other Microsoft applications. You can see that the macro and extensibility that is being used in Visual Studio .NET is giving you some of the same functionality that you have in Office. When you looked at the code generated for the TryCatchBlock macro, the first item in the module was the Imports statement that imported the EnvDTE namespace. The EnvDTE namespace has the properties, methods, and events that you use to manipulate the Visual Studio .NET IDE. The code that did the actual typing of the Try/Catch block was using the ActiveDocument property of the DTE object. The DTE object is the design time environment object of the current Visual Studio .NET IDE. All the objects you work with are under DTE in the object hierarchy. The remaining code in the macro you recorded uses the DTE.ActiveDocument.Selection property to retrieve the selected area of the topmost window in the IDE. Using methods such as LineUp, LineDown, and Text, the text that you typed can be repeated by this macro. You use two classes in the DTE object to accomplish most of your macro work: the Document object and the TextSelection object. Before you get into the objects of the EnvDTE object, you must create a new macro project to which you can add the code you write for the rest of today. Creating a New Macro ProjectTo create a new macro project, close the Macros IDE and return to the LearnMacro Visual Studio .NET project. From the Macro Explorer, right-click the topmost node and select New Macro Project, as Figure 16.7 demonstrates. Figure 16.7. The New Macro Project menu.
When the New Macro Project pops up, name the new project Utilities as Figure 16.8 shows. Figure 16.8. The Add New Macro Project dialog box.
After the new macro project is added to the Macro Explorer, right-click on the default Module1 in the Utilities project. Select Rename from the contextual menu and rename the module to VSMacros, as shown in Figure 16.9. Figure 16.9. Renaming the Module1 module to VSMacros.
Next, right-click the VSMacros module and select Edit. You're now in the Macros IDE, as Figure 16.10 demonstrates. Figure 16.10. The Utilities project in the Macros IDE.
In the next section, you're going to learn about the Document and TextSelection objects and add code to the VSMacros module. Working with the Document ObjectWhen you refer to the ActiveDocument in a macro, the EnvDTE returns a Document object for the ActiveDocument. Using the properties, methods, and events of the returned Document object enables you to manipulate the IDE. To get an idea of what the Document object gives you, examine Tables 16.1 and 16.2, which respectively present the properties and methods of the Document object.
An example of using the Document object properties to retrieve information about the document in the active code window is presented in Listing 16.3. Add this code to the VSMacros module as the GetDocumentInfo subprocedure. Listing 16.3 Using the ActiveDocument Property to Retrieve Document Properties
Sub GetDocumentInfo() If (DTE.ActiveDocument.ReadOnly) Then MsgBox("This document is Read Only") Else MsgBox("This document is Writable") End If MsgBox("Document name = " & DTE.ActiveDocument.Name) MsgBox("Document full name = " & DTE.ActiveDocument.FullName) MsgBox("Document path = " & DTE.ActiveDocument.Path) End Sub
Remember that the ActiveDocument property actually returns a Document object. To modify this to make your coding less wordy, you can create a variable of type Document and reference the object using a variable. Listing 16.4 shows the altered code to use the Document object. Add the code in Listing 16.4 to your VSMacros module as the GetDocumentInfo2 subprocedure. Listing 16.4 Using the Document Object to Retrieve Document Properties
Sub GetDocumentInfo2() ' Create a Document variable Dim doc As Document If (doc.ReadOnly) Then MsgBox("This document is Read Only") Else MsgBox("This document is Writable") End If MsgBox("Document name = " & doc.Name) MsgBox("Document full name = " & doc.FullName) MsgBox("Document path = " & doc.Path) End Sub
By creating the Document variable, you still have the nice features of auto-complete and auto-list members; you just don't have to type in DTE.ActiveDocument each time you want to reference the document in the active window. The Document object also is a member of the Documents collection. Because Visual Studio .NET enables you to have many windows open, you can write macros that use the Save and Close methods of the Document object while iterating through the Documents collection of the Windows property of the Document object. The code in Listing 16.5 is a useful snippet that saves and closes all the open windows in the IDE. Add the code in Listing 16.5 to your VSMacros module. Listing 16.5 Saving and Closing a Document Using the Methods of the Document Object
Sub CloseAllWindows() Dim doc As Document For Each doc In DTE.Windows.DTE.Documents doc.Save() doc.Close() Next End Sub
By iterating through the Documents collection, you can use the Save and Close methods to take care of your open windows. This is cool because as your projects become larger, you have a bunch of tabs across the top of your designer. When you close a project, the state of the open windows is remembered for the next time you open the project. By closing all the windows, the project will have no windows open the next time you start it, which makes the startup time shorter. The Documents collection also has a few methods that alleviate having to use the Save and Close methods on each open document. Table 16.3 lists the methods of the Documents collection.
Working with the TextSelection ObjectThe TextSelection object is the second most useful object when working with macros and the IDE. The TextSelection object directly reflects editor commands in the Visual Studio .NET IDE. Table 16.4 lists the properties of the TextSelection object and Table 16.5 lists its methods. Using the TextSelection object, you can modify the TryCatchBlock macro you created earlier. Listing 16.6 shows how to use the TextSelection object to create a better Try/Catch macro. Add the code in Listing 16.6 to your VSMacros module. Listing 16.6 Adding the Try/Catch Block with Streamlined Code to the VSMacros Module
Sub TryCatchBlock_vb() Dim txt As TextSelection = _ DTE.ActiveDocument.Selection With txt .Text = "Try" .NewLine(3) .Text = "Catch ex as Exception" .NewLine(2) .Text = "Finally" .NewLine(2) .LineUp(False, 7) End With End Sub
Sub TryCatchBlock_cs() Dim txt As TextSelection = _ DTE.ActiveDocument.Selection With txt txt.Text = "try" .NewLine() .Text = "{" .NewLine(2) .Text = "}" .NewLine() .Text = "catch (System.Exception ex)" .NewLine() .Text = "{" .NewLine(2) .Text = "}" .LineUp(False, 5) End With End Sub
In Listing 16.6, you're creating a TextSelection variable based on the ActiveDocument.Selection property. Then, using straightforward Visual Basic .NET code, you're doing exactly what the Macro Recorder did earlier. You can see that the code you write is much cleaner than what the Macro Recorder generates. They both accomplish the same thing though: They add a Try/Catch block to your code window without you having to do it manually! To test the code, select Close and Return from the File menu. You're now back at the Visual Studio .NET IDE, and you can double-click on your macros to test them. Your Macro Explorer should look like Figure 16.11 at this point. Figure 16.11. The Macro Explorer with the Utilities project.
The next step is to make your macros more accessible by creating a toolbar for them. |