Examining the Macro Recorder Code When 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:
- EnvDTE
- Microsoft.Vsa
- Office
- System
- System.Windows.Forms
- VSLangProj
- VsMacroHierarchyLib
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 Project To 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.
 When the New Macro Project pops up, name the new project Utilities as Figure 16.8 shows.
 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.
 Next, right-click the VSMacros module and select Edit. You're now in the Macros IDE, as Figure 16.10 demonstrates.
 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 Object When 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.
Table 16.1. Properties of the Document Object
|
ActiveWindow |
Returns the current active window, or the topmost window if no others are active; returns Nothing if no windows are open |
Collection |
Returns the Documents collection |
DTE |
Returns the top-level extensibility object |
Extender |
Returns the requested extender object if it's available for this object |
ExtenderCATID |
Returns the extension category ID (CATID) for the object |
ExtenderNames |
Returns a list of available extenders for the object |
FullName |
Returns the full path and filename of a document |
Kind |
Returns a GUID string indicating the kind or type of the object |
Name |
Returns the filename of the object without the path |
Path |
Returns the path, without the filename, for the directory containing the document |
ProjectItem |
Returns the ProjectItem object associated with the given object |
ReadOnly |
Returns whether the document in memory can be edited |
Saved |
Returns True if the object has been saved since last being changed |
Selection |
Returns the current selection in the active window associated with this document (or the topmost window of the document if none is active) |
Windows |
Returns a Windows collection containing the windows that display in the object |
Table 16.2. Methods of the Document Object
|
Activate |
Moves the focus to the current item and makes it active |
Close |
Closes the open document and optionally saves it |
NewWindow |
Creates a new window in which to view the document |
Object |
Returns an interface or object that can be accessed by name at runtime |
Redo |
Re-executes the last action that was undone by the Undo method or the user |
Save |
Saves the document |
SaveAll |
Saves all documents currently open in the environment |
Undo |
Reverses the action last performed by the user in the document |
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.
Table 16.3. Methods of the Documents Collection
|
CloseAll |
Closes all open documents in the environment and optionally saves them |
Item |
Returns an indexed member of a collection |
SaveAll |
Saves all documents currently open in the environment |
Working with the TextSelection Object The 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.
Table 16.4. Properties of the TextSelection Object
|
ActivePoint |
Returns the current endpoint of the selection |
AnchorPoint |
Returns the origin point of the selection |
BottomPoint |
Returns the point at the end of the selection |
DTE |
Returns the top-level extensibility object |
IsActiveEndGreater |
Indicates whether the active point is equal to the bottom point |
IsEmpty |
Indicates whether the anchor point is equal to the active point |
Mode |
Sets or returns a value determining whether dragging the mouse selects in stream mode or block mode |
Parent |
Returns the parent object; in this case, the TextDocument object |
Text |
Returns the selected text |
TextPane |
Returns the text pane that contains the selection |
TextRanges |
Returns a TextRanges collection with one TextRange object for each line or partial line in the selection |
TopPoint |
Returns the top end of the selection |
Table 16.5. Methods of the TextSelection Object
|
ChangeCase |
Changes the case of the selected text. |
CharLeft |
Moves the object the specified number of characters to the left. |
CharRight |
Moves the object the specified number of characters to the right. The default is one character. |
ClearBookmark |
Clears any unnamed bookmarks on the current line. |
Collapse |
Collapses the selection to the active point. |
Copy |
Copies the selection to the clipboard. |
Cut |
Copies the selected text to the clipboard and deletes it from its original location. |
Delete |
Deletes the selected text. |
DeleteLeft |
Deletes a specified number of characters to the left of the active point. |
DeleteWhitespace |
Deletes white space horizontally or vertically around the current location. |
DestructiveInsert |
Inserts text that overwrites the existing text. |
EndOfDocument |
Moves the object to the end of the document. |
EndOfLine |
Moves the object to the end of the current line. |
FindPattern |
Searches for the given pattern from the active point to the end of the document. |
FindText |
Searches for the given text from the active point to the end of the document. |
GoToLine |
Moves to the beginning of the indicated line and selects the line if requested. |
Indent |
Indents the selected lines by the given number of indentation levels. |
Insert |
Inserts the given string at the specified location. |
InsertFromFile |
Inserts the contents of the specified file at the current location. |
LineDown |
Moves the selected line down a specified number of lines. |
LineUp |
Moves the selected line up a specified number of lines. |
MoveToAbsoluteOffset |
Moves the active point to the given 1-based absolute character offset. |
MoveToDisplayColumn |
Moves the active point to the indicated display column. |
MoveToLineAndOffset |
Moves the active point to the given position. |
MoveToPoint |
Moves the active point to the given position. |
NewLine |
Inserts a line break at the active point. |
NextBookmark |
Moves to the location of the next bookmark in the document. |
OutlineSection |
Creates an outlining section based on the current selection. |
PadToColumn |
Fills the current line with white space to the given column. |
PageDown |
Moves the active point a specified number of pages down in the document, scrolling the view. |
PageUp |
Moves the active point a specified number of pages up in the document, scrolling the view. |
Paste |
Inserts the clipboard contents at the current location. |
PreviousBookmark |
Moves to the location of the previous bookmark in the document. |
ReplacePattern |
Searches for the given pattern in the selection and replaces it with new text. |
ReplaceText |
Searches for the given pattern in the selection and replaces it with new text. |
SelectAll |
Selects the document. |
SelectLine |
Selects the line containing the active point. |
SetBookmark |
Sets an unnamed bookmark on the current line. |
SmartFormat |
Formats the indicated line of text based on the current language. |
StartOfDocument |
Moves the object to the beginning of the document. |
StartOfLine |
Moves the object to the beginning of the current line. |
SwapAnchor |
Exchanges the positions of the active point and the anchor point. |
Tabify |
Converts spaces to tabs in the selection according to your tab settings. |
UnIndent |
Removes indents from the selected text by the number of indentation levels given. |
Untabify |
Converts tabs to spaces in the selection according to the user's tab settings. |
WordLeft |
Moves the object the specified number of words to the left. |
WordRight |
Moves the object the specified number of words to the right. The default is one word. |
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.
 The next step is to make your macros more accessible by creating a toolbar for them.
|