Using Visual Studio .NET Macros
by Matthew MacDonald12/09/2002
Now that the .NET mania is finally settling down and developers are starting to adapt to life with the platform, it's a good time to consider a few less-revolutionary (but very practical) details that can simply your programming life. One of these is the often-overlooked macro engine and extensibility model that's built into Visual Studio .NET. This model provides almost 200 objects that give you unprecedented control over the IDE. This includes the ability to access and manipulate the current project hierarchy, the collection of open windows, and the integrated debugger. Using this model, you can build everything from simple keystroke recordings to advanced add-ins that present their own user interface and interact with the IDE. In this article, we'll look at how you might use macros to automate common code-generation tasks, such as building property procedures for your classes.
|
Related Reading
Mastering Visual Studio .NET |
Macro Basics
Macros are only one of the extensibility tools provided by Visual Studio .NET, but they are easy to develop quickly, and they have surprising clout. Unlike most other Microsoft products, Visual Studio .NET macros are built out of full .NET code, which means they can use any part of the .NET class library. This allows macros to write XML files, display forms, and even contact remote Web services as part of their work. (For information about other types of Visual Studio .NET extensibility, and help choosing which one suits a particular problem, you can consult Microsoft's automation whitepaper here.)
You can create a basic macro simply by recording your actions in the Visual Studio .NET editor. Just follow these steps:
- Select Tools > Macros > Record Temporary Macro from the Visual Studio.NET menu.
- Type in the appropriate keystrokes, which will be recorded.
- Click the stop button on the floating macro toolbar once you're finished.
-
You can now play the macro back using the menu or the convenience hotkey
Ctrl-Shift-P.
To view the code for a recorded macro, select Select Tool > Macros > Macro Explorer. This window (shown below) shows a tree of macro modules, and the macros they contain. Each macro corresponds to a Visual Basic .NET subroutine.
![]() |
To edit the macro you just created, right-click on the TemporaryMacro subroutine in the RecordingModule and select Edit. A separate IDE will load for editing macro code; it closely resembles the ordinary Visual Studio .NET environment, right down to a Project Explorer and dynamic help. Visual Studio only stores one temporary macro at a time, which is overwritten every time you record a new one. To make a temporary macro permanent, you'll need to cut and paste the code into a different subroutine.
As stated earlier, macro code uses ordinary .NET syntax and the class library. However, macro code also has access to a special set of Visual Studio .NET extensibility objects, which you won't recognize. These objects are used to interact with windows, insert and read editor text, and so on. For example, to add a new line into the editor, you would use the following macro code:
' Get the current insertion point (where the cursor is positioned).
Dim TS As TextSelection = DTE.ActiveDocument.Selection
' Move to the end of the line.
TS.EndOfLine()
' Add a new line (the programmatic equivalent of pressing Enter).
TS.NewLine()
' Insert some text.
TS.Insert("Sample Text")
All of these objects are contained in a special EnvDTE namespace, which is
contained in the EnvDTE.dll assembly. This assembly is referenced by default in
all macro projects.
Imports EnvDTE
A good way to start learning about macros is to use the record facility, and then look at the code it generates.
Macros for Property Procedures
Visual Basic 6 included several add-ins that could automate class code, including wizards that would generate a series of property procedures. Unfortunately, Visual Studio .NET has nothing comparable. This problem becomes apparent when developers begin to design a class. Unfortunately, it's far simpler to type the following code statement:
Public MyVar As String
Than to create a full property procedure that ensures proper encapsulation of private data:
Private _MyVar As String
Public Property MyVar As String
Get
Return _MyVar
End Get
Set(ByVal Value As String)
_MyVar = Value
End Set
End Property
The solution, clearly, is to create a macro that generates property procedures
automatically as needed. One approach is to create a straightforward macro that
examines the text at the current insertion point, and uses it to generate a
full property procedure. We'll begin coding this macro by writing a private
function (which will be added to the macro module) that takes a line of text
representing a private variable declaration, and creates a corresponding
property procedure declaration. In this case, the code assumes that private
variables will always start with a leading underscore (_), which will be
trimmed from the name of the property procedure. Depending on your conventions,
the code may need to be adjusted.
Private Function GetInsertion(ByVal text As String) As String
Dim Words() As String = text.Trim.Split()
If Words.Length < 4 Then
' This line is not a valid variable declaration.
Return ""
Else
Dim Insertion As String
Insertion = " Public Property " & Words(1).Trim("_")
Insertion &= " As " & Words(3)
Insertion &= vbNewLine
Insertion &= " Get"
Insertion &= vbNewLine
Insertion &= " Return " & Words(1)
Insertion &= vbNewLine
Insertion &= " End Get"
Insertion &= vbNewLine
Insertion &= " Set(ByVal Value As " & Words(3) & ")"
Insertion &= vbNewLine
Insertion &= " " & Words(1) & " = Value"
Insertion &= vbNewLine
Insertion &= " End Set"
Insertion &= vbNewLine
Insertion &= " End Property"
Insertion &= vbNewLine & vbNewLine
Return Insertion
End If
End Function
The next step is to create a macro that uses this function. The code below selects the current line,
generates a property procedure using GetInsertion(), and adds it after the
current line.
Public Sub ExpandPrivateMembersFromSelection()
Dim TS As TextSelection = DTE.ActiveDocument.Selection
Dim Insertion As String, Line As String
Dim Lines() As String = TS.Text.Split(vbNewLine)
For Each Line In Lines
Insertion &= GetInsertion(Line)
Next
TS.EndOfLine()
TS.NewLine()
TS.Insert(Insertion)
End Sub
The following figure shows this macro in the macro explorer. You can double-click it to run it on the current editor line.
![]() |
It's now easy to extend this macro to work with multiple lines. The
ExpandPrivateMembersFromSelection() macro below passes each selected line to
the GetInsertion() function, and builds up the returned text (any blank lines
will be ignored by GetInsertion() automatically). Then, the full text block is
inserted. For example:
Public Sub ExpandPrivateMembersFromSelection()
Dim TS As TextSelection = DTE.ActiveDocument.Selection
Dim Insertion As String, Line As String
Dim Lines() As String = TS.Text.Split(vbNewLine)
For Each Line In Lines
Insertion &= GetInsertion(Line)
Next
TS.EndOfLine()
TS.NewLine()
TS.Insert(Insertion)
End Sub
Now you simply need to type the following code:
Private _MyVar As String
And run one of the two macros to generate a corresponding property procedure for any basic data type.
At this point, you may be wondering if it's possible to write this code in a language-independent way to support any .NET language. This functionality is called the CodeDOM in the .NET Framework. Using the CodeDOM is a complex operation that is outside of the scope of this article.
Summary
Macros are a powerful tool in for automating repetitive tasks in any application. However, when used correctly, macros can become much more, and help enforce standards, promote good design, and improve consistency across an entire organization. One way is by using add-ins or macros that generate certain code structures in a standardized fashion.
You can download the code for this article at www.prosetech.com.
Matthew MacDonald is a developer, author, and educator in all things Visual Basic and .NET. He's worked with Visual Basic and ASP since their initial versions, and written over a dozen books on the subject, including The Book of VB .NET (No Starch Press) and Visual Basic 2005: A Developer's Notebook (O'Reilly). His web site is http://www.prosetech.com/.
Return to ONDotnet.com



