Macros: The Duct Tape of Visual Studio .NET
The macros facility of Visual Studio .NET uses Visual Basic .NET as its macro language. This fit has a much better feel to it than the Visual Basic Scripting Edition (VBScript) facility built into Microsoft Visual C++ 6.0. The Visual Basic .NET language can take full advantage of the .NET Framework and its own automation object model, so it offers an extremely powerful and compelling set of features that you can use to automate tasks in the IDE. In fact, you can convert any macro into a Visual Basic .NETbased add-in that you can compile and share with other developers.
As we mentioned in Chapter 1, Visual Studio .NET macros are saved into files with a .vsmacros extension. These macros are stored in the VSMacros71 folder in your default Visual Studio .NET projects folder. You can specify the Visual Studio .NET projects folder in the Options dialog box, on the Projects and Solutions page in the Environment folder. By default, this path is My Documents\Visual Studio Projects. Macros are stored in the VSMacros71 subfolder.
Visual Studio .NET macros are usually created in one of two ways. You can record a macro in the IDE (Ctrl+Shift+R); the code generated during the recording session will be stored in the MyMacros.RecordingModule.TemporaryMacro method. Alternatively, you can open the Macros IDE (Alt+F11) and create a new method by writing it from scratch. One of the best things about macros is that they're designed to automate functionality in the Visual Studio .NET IDE. This means you can often simply record a macro, copy the generated code to a new method, and use that as the basis for your own automation project. You can also use this technique to get code for the add-ins you create for Visual Studio .NET.
Visual Studio .NET macros are accessed in the IDE just like any other named command. You can enter the name of the macro in the Command Window (Ctrl+Alt+A), you can add the macro to a toolbar or a menu, you can assign the macro a keystroke shortcut, you can run the macro by double-clicking it in Macro Explorer, and you can run the macro directly from the Macros IDE.
Note
When you run a macro by double-clicking it in the Macro Explorer window, the focus returns to the last active window. As a result, you can set the active document, open Macro Explorer, double-click the macro and have it affect the last active document.
We consider macros the duct tape of Visual Studio .NETin the best sense of the term. Duct tape is made of an extremely strong material and can help you accomplish tasks quickly and easily. We would describe macros in the same way: they're extremely powerful tools in the IDE that you don't have to spend a ton of time thinking about. You can create your macro to perform your task and then tuck it away. If the macro is sufficiently important and powerful, you can turn it into a full blown add-in and then polish that code to your heart's content.
Recording Visual Studio .NET Macros
To record a Visual Studio .NET macro, first press the Ctrl+Shift+R keyboard shortcut. This combination brings up the Recorder toolbar and creates a macros module named RecordingModule if one doesn't already exist. You can see the Recorder toolbar in Figure 4-1. Notice that you can pause, stop, or even cancel the recording session that you've started.
Figure 4-1. The Recorder toolbar
The easiest way to get going with macros is to record a simple macro that you might want to use repeatedly. For example, let's say you want to find the word Connects in your code files. You would normally use the Find or Find In Files command for this purpose. But by using one of these commands in the context of a macro, you can gain more flexibility and use the macro in later sessions.
Here are the steps for recording the macro we have in mind:
Press Ctrl+Shift+R to start the macro recorder.
Press Ctrl+F to open the Find dialog box.
Type Connect in the Find What box.
Click Find Next.
Press Ctrl+Shift+R to stop recording.
We now have a TemporaryMacro method saved in the module RecordingModule. You can see that macro in Figure 4-2.
Figure 4-2. The Macro Explorer window
Here's the listing that's generated by the preceding series of steps. Notice that mouse movements and keystrokes (such as Tab for navigating to the Replace dialog box) aren't recorded. Visual Studio .NET limits macro recording to actual named commands that are called during the recording session.
Imports EnvDTE
Imports System.Diagnostics
Public Module RecordingModule
Sub TemporaryMacro()
DTE.ExecuteCommand("Edit.Find")
DTE.Find.FindWhat = "Connect"
DTE.Windows.Item("Connect.cpp").Activate()
DTE.Find.FindWhat = "Connect"
DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument
DTE.Find.MatchCase = False
DTE.Find.MatchWholeWord = False
DTE.Find.Backwards = False
DTE.Find.MatchInHiddenText = False
DTE.Find.PatternSyntax = _
vsFindPatternSyntax.vsFindPatternSyntaxLiteral
DTE.Find.Action = vsFindAction.vsFindActionFind
DTE.Find.Execute()
End Sub
End Module
To play back this macro, press Ctrl+Shift+P, which is simply a shortcut to the Macros.Macros.RecordingModule.TemporaryMacro command. You should see the Find dialog box open with the first instance of the word you're searching for selected. In our case, this is the first instance of Connect in a file named Connect.cpp.
Take a look at the line DTE.Windows.Item("Connect.cpp").Activate(). If Connect.cpp isn't already open, this line will bring it into focus in the IDE, so this macro won't be very useful if you want to save it for use with a number of different files or projects. Commenting out or removing this line from the listing will cause the macro to work with the currently active document.
To save the recorded macro, you can either rename TemporaryMacro to something else in Macro Explorer or you can copy and paste the recorded code into another macro module or method.
Macro Commands
Macro Explorer lets you manage your macros from inside the Visual Studio .NET IDE. You can access the commands related to macros in the IDE from the Macros submenu of the Tools menu or through the shortcut menus within Macro Explorer.
Macros are divided into projects containing modules, which in turn contain methods. Projects are represented hierarchically in Macro Explorer below the Macro icon. Right-clicking the Macro icon brings up the shortcut menu containing commands for creating and loading macro projects. You can access the same functionality as named commands in the Command Window. Table 4-1 lists the macro commands related to macro projects.
Command | Description |
---|---|
Tools.LoadMacroProject | Brings up the Add Macro Project dialog box, where you can select a macro project file. |
Tools.NewMacroProject | Brings up the New Macro Project dialog box, where you can save your macros into specific projects. |
Tools.MacrosIDE | Brings up the Macros IDE. This command is mapped to Alt+F11. |
You can navigate to Macro Explorer by pressing Alt+F8. Most commands available from the shortcut menus in Macro Explorer are also available from the Command Window (because the items in Macro Explorer lose focus when you change to the Command Window). You can rename a macro project by right-clicking on the project in Macro Explorer and then clicking Rename. Doing so will allow you to edit the name of the macro project in place. You can delete a macro project by choosing Delete from the shortcut menu. The same basic shortcut menu items are available for renaming and deleting modules and methods from within Macro Explorer.
Table 4-2 lists a few of the commands available from within a particular macro project.
Command | Description |
---|---|
Tools.Newmodule | Brings up the New Module dialog box, where you can create a new module from within Macro Explorer |
Tools.Newmacro | When enabled, this command brings up the Macros IDE with a new macro method |
Tools.Edit | Brings up the Macros IDE open to the currently selected project or module |
By right-clicking on a macro in Macro Explorer, you can bring up a shortcut menu that lets you work with the macro directly. The Run command executes the Tools.Run command on the currently selected macro. The Rename command allows you to edit the name of the macro in place. The change you make to the name is reflected in the method name in the Macros IDE. The Delete command deletes the currently selected macro. And finally, the Edit command opens the current macro in the Macros IDE.
Macro Explorer is a powerful tool for organizing the macros you've created. You'll find that you can do quite a bit in Macro Explorer without having to go to the Macros IDE. For example, you can record a macro, rename that macro to save it, and even add that same macro to a toolbar or a menu in the IDE, all without having to go to the Macros IDE. You'd probably find it limiting not to use the IDE, but it is possible. To really get the most out of Visual Studio .NET macros, you'll want to be able to create and edit them from within the Macros IDE.
Editing Macros in the Macros IDE
Working with the Macros IDE is similar to working in Visual Studio .NET. Many of the same shortcuts work in the Macros IDE. The Macros IDE editor features IntelliSense, and the Help system for macros is integrated right into the IDE.
One difference you'll notice right away is that all your loaded macro projects show up in the Project Explorer window. Visual Studio .NET ships with an extremely useful set of macros out of the box. You can see these macros if you expand the Samples project in Project Explorer in the Macros IDE (as shown in Figure 4-3).
Figure 4-3. The Samples project in the Macros IDE
The memory space for macro projects is separated, so if you want to utilize functionality between different macros or if you want to take advantage of a common set of environmental events, you must keep the macros that you write inside the same project. If you want to access functionality from another macro project, you simply copy the macros you want to access into the project you're working on. For example, you can copy modules from the Samples project into your own project to take advantage of the functionality exposed by those macros.
To create a new macro project, you need to start from the Visual Studio .NET IDE. You can use the New Macro Project command on the shortcut menu in Macro Explorer or you can enter Tools.NewMacroProject into the Command Window to open the New Macro Project dialog box (shown in Figure 4-4). Enter a name and location for your project, and then click OK. Pressing Alt+F11 will toggle you back to the Macros IDE, where you can work on the code in the new project.
Figure 4-4. The New Macro Project dialog box
If you take a look at the new macro project created in Project Explorer, you'll notice that a number of features are added to your project by default. The References folder works similarly to the References folder in the Visual Studio .NET IDE. Two new modules are added to get your macros up and running. The EnvironmentEvents module contains generated code that gives you access to the events in the IDE. The Module1 module provides a place where you can start writing code.
Lab: Navigating Between IDEsTo shift from the Macros IDE to the Visual Studio .NET IDE, you can click the Visual Studio button on the Macros IDE toolbar. There's no such button on any of the default Visual Studio .NET toolbars, so you'll need to add one if you want to get back to the Macros IDE in the same way. To do so, right-click on a toolbar in the Visual Studio .NET IDE and click Customize. On the Commands tab, find the Macros IDE command in the Tools category and drag it to the toolbar you want to use it from. The button will have the same infinity image used in the Macros IDE. This makes it easy to navigate between the two IDEs while you work on your macros. If you'll be doing a lot of macro development, a better solution is to run your machine with two monitors, keeping the Macros IDE in one screen and Visual Studio .NET in the other. |
Adding a reference to a macro project is slightly different from adding one to a standard Visual Basic .NET project. If you look at the Add Reference dialog box that's used in the Macros IDE Project Explorer (shown in Figure 4-5), you'll notice that it doesn't offer a way to add custom assemblies.
Figure 4-5. Add Reference dialog box
To add references to your own assemblies, you must copy them to the C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\PublicAssemblies folder. You can then add your own reference to the assembly from the Add Reference dialog box. Using assemblies, you can write your macro functionality in any language you want and then access that functionality from a fairly simple macro. You can also write assemblies that call to unmanaged code and assemblies that act as COM wrappers to access COM functionality from within your macros.
Let's go over a few examples built from a new project.
A Simple Macro
Earlier in the book, we touched on the behavior of the File.NewFile command in Visual Studio .NET. Some programmers haven't been pleased that this command displays a dialog box by default, forcing them to resort to the mouse or to a series of keystrokes to get an empty file up and running. But the solution is simple: you just create a macro that does exactly what you want and then assign that macro an alias in the Command Window. The following code is all you really need to create a new text file in the IDE:
Imports EnvDTE
Imports System.Diagnostics
Public Module NewFile
Sub NewTextFile()
DTE.ItemOperations.NewFile("General\Text File")
End Sub
End Module
As you can see, this macro has been created in a module named NewFile. It consists of a single method, NewTextFile. The single line of code in this macro simply creates a new file of the type Text File in the General folder of the New File dialog box. We'll talk about the NewFile method that creates the new text file in a minute. What's important right now is that we have a macro that will add just the functionality we want to the IDE. To make this macro a tool we're willing to spend some time with, we'll want to make the macro as easy to get to as possible.
To get to a macro you want to execute, you've got a few choices. One approach is to run the macro from Macro Explorer in the Visual Studio .NET IDE. This works fine, but it's probably not the optimal solution for a macro that you're planning to use often. The second choice is to create an alias for the macro in the Command Window. This is probably the best choice for a command that you want to use while you're typing. To alias this command, you can type the alias command followed by the name of the macro. IntelliSense will kick in when you start to type a macro, so the whole alias line might look something like this:
>alias nf Macros.InsideVSNET.Chapter04.NewFile.NewTextFile
Now you've got a new command you can use from the Command Window: nf. To create a new text file, you can simply press Ctrl+Alt+A and then type nf to get your new file. Of course, if you want to take it a step further, you can assign the macro a keystroke shortcut from the Options dialog box. In keeping with the Ctrl+, initial chord introduced earlier in the book, Ctrl+,,Ctrl+N might make a good shortcut. Finally, you can add a button to the toolbar that initiates the macro (as described in Chapter 3).
The Imports statement in this sample is important. The API associated with the Visual Studio .NET automation object model is contained in the EnvDTE namespace. The automation object model is discussed in depth in Chapter 5 through Chapter 12. Here we simply want to familiarize you with this object model and get you up and running with some of the more common functionality that you'll use in your macro projects. Most of the subjects covered in the chapters that comprise Part II of the book apply to both macros and add-ins. In fact, you can use macros to quickly test add-in functionality that you're writing. You'll save time because you normally test an add-in by compiling the add-in and loading a second instance of the IDE. Using a macro, you can get to the automation object model, write and test your routines, and then add them to your add-in projects.