Automating Repetitive Tasks in Visual Studio

Visual Studio.Net has added an expanded extensibility model and macros to the unified Visual Studio IDE. The macro tools allow you to quickly record repetitive tasks, enhancing productivity. The productivity gain you get depends on the weight of the repetitive tasks. Small automatic tasks, small gains. Bigger tasks, bigger gains.

When you have automated the repetitive task you can open the Macro IDE and customize the macros, tapping into the extensibility model using Visual Basic code. In this article we examine the rudiments of creating, customizing, and employing macros in Visual Studio, for the benefit of our Visual Basic projects.

Creating Macros

An easy way to start a macro is to record the steps close to or identical to the process you want to automate. When you have recorded the macro, open the Macro IDE and customize the macro, adding the fit and finish you need.

Recording and Playing Macros

Macros can be recorded in the Visual Studio IDE by selecting Tools|Macros|Record TemporaryMacro (Ctrl+Shift+R is the shortcut). This displays the macro toolbar as shown in Figure 1. When you have finished recording your steps then click the center—Stop Recording—tool button (shown in Figure 1).

Figure 1: The Visual Studio.Net IDE macro toolbar allows you to automate tasks by recording your interaction with VS.NET.

Figure 2: Recorded macros are temporarily stored in the Project Explorer in the Macros IDE. (The Project Explorer is shown in the figure.)

A recorded macro is temporarily stored in the module RecordModule, shown in the Project Explorer for the Macros IDE figure 2. The temporary macro is saved in a subroutine named TemporaryMacro. To record a macro to display the Breakpoints window, follow these steps:

  1. Select Tools|Macros|Record TemporaryMacro
  2. With the recorder on, select Debug|Windows|Breakpoints
  3. Click the Stop Recording button on the macro tool bar (see figure 1)
  4. Press Alt+F11 to view open the Macro IDE (Alt+F11 is the shortcut for the Tools|Macros|Macros IDE menu option)

The number steps will create a module named RecordingModule, and approximately create the code shown in Listing 1.

Listing 1: A TemporaryMacro subroutine is created after recording a macro.

Option Strict Off
Option Explicit Off
Imports EnvDTE
Imports System.Diagnostics

Public Module RecordingModule

  Sub TemporaryMacro()
    DTE.ExecuteCommand("Debug.Breakpoints")
  End Sub

End Module

To run the temporary macro press Ctrl+Shift+P. This is the shortcut operation for the Tools|Macros|Run TemporaryMacro menu item. If you want to customize the macro then you will need to rename the module and the temporary macro subroutine to something meaningful.

Saving the Temporary Macro

To save your macro, open the Microsoft Visual Studio Macros 7.0 IDE, the Macro IDE. In the macro Project Explorer, select the RecordingModule and from the right-click menu select Rename. Provide a meaningful name for the recording module and a new name for the TemporaryMacro subroutine. A good name for the macro we recorded in the numbered steps might be ViewBreakpoints.

Once you have saved the macro you can run it from the Command Window in the Visual Studio IDE. Open the Command Window (Ctrl+Alt+A) and type Macros.MyMacros.mymodule.ViewBreakpoints, where mymodule is the name you gave the RecordingModule when you renamed it. (When you record a new macro, Visual Studio.Net will create a new RecordingModule automatically.)

Macros is a collection containing all macros. MyMacros is a macro project I created from the Tools|Macros|New Project menu item; mymodule is the new name for the RecordingModule created by default when we record a macro. ViewBreakpoints is the name of the subroutine originally named TemporaryMacro. For the most part you can think of a macro project in the same way you would think about a VB project: the macro project contains modules and code and is defined in a .vsmacros project file. The macro code is Visual Basic.Net code, which you already know or are learning how to write.

The biggest benefit of macros is the extensibility model. There are a lot of classes and tools that make up the extensibility model. In addition, you can add classes and code from the CLR to your macros, as demonstrated by listing 1. Listing 1 imports the System.Diagnostics and the EnvDTE namespaces. System.Diagnostics contains debugging and diagnostics tools. The EnvDTE namespace contains the Common Environment Object Model and the Debugger Object Model. The last section demonstrates how to use the EnvDTE namespace to create several macros that are a bit more useful than our recorded macro.

Customizing the Macro Code

A task you may realistically want to perform is to enable or disable all breakpoints without removing them. You could accomplish this task by open the breakpoints window, selecting each breakpoint in turn, and unchecking the checkbox next to the break point. This would have the effect of disabling or enabling a breakpoint, as the case may be, without removing the breakpoint.

Note: The macros in this section are already supported by selecting the Debug|Disable All Breakpoints (or Debug|Enable All Breakpoints) menu or by typing Debug.EnableAllBreakpoints or Debug.DisableAllBreakpoints in the Command Window. The macros are provided for demonstration purposes, rather than to replace existing functionality.

To create our macros open an existing macro project or create a new macro project from the Tools|Macros|New Project menu. Add a module named Debugger to your macros project. Add the code in listing 2 to the Debugger module. (A synopsis of the code follows the listing.)

Listing 2: Customized macros to enable and disable all breakpoints; the macro also writes the state change to the Output window.

1:  Option Strict Off
2:  Option Explicit Off
3:  
4:  Imports EnvDTE
5:  Imports System.Diagnostics
6:  
7:  Public Module Debugger
8:  
9:    Function GetOutputWindow() As OutputWindow
10:     Return _
11:      DTE.Windows.Item(Constants.vsWindowKindOutput).Object
12:   End Function
13: 
14:   Function GetActivePane() As OutputWindowPane
15:     Return GetOutputWindow.ActivePane
16:   End Function
17: 
18:   Private Sub WriteState(ByVal BreakPoint As Breakpoint)
19:     GetActivePane.OutputString( _
20:       String.Format("Breakpoint ({0}) enabled={1}", _
21:       BreakPoint.Name, BreakPoint.Enabled) & vbCrLf)
22:   End Sub
23: 
24:   Private Sub SetBreakpointState(ByVal Enabled As Boolean)
25: 
26:     Dim Breakpoint As Breakpoint
27:     For Each Breakpoint In DTE.Debugger.Breakpoints
28:       Breakpoint.Enabled = Enabled
29:       WriteState(Breakpoint)
30:     Next
31: 
32:   End Sub
33: 
34:   Sub EnableBreakPoints()
35:     SetBreakpointState(True)
36:   End Sub
37: 
38:   Sub DisableBreakpoints()
39:     SetBreakpointState(False)
40:   End Sub
41: End Module

Option Strict and Option Explicit are Off by default, but they should probably be turned to On as a general rule, to help us find and resolve problems in our code as soon as possible. (However, this is a discussion for another day.) The Debugger module imports the EnvDTE and System.Diagnostics namespaces on lines 4 and 5. Lines 9 through 12 and 14 through 16 define two refactored Query Methods that return an instance of the OutputWindow defined in the Windows collection and an OutputWindowPane. (Just because we are writing macros, doesn.t mean we should not use good techniques like Refactoring.) Line 18 through 22 uses the query method GetActivePane, and employs the Shared method String.Format to write formatted output to the Output Window in the Visual Studio IDE. The Private method SetBreakPointState actually iterates over each Breakpoint (lines 24 through 32) and changes the Enabled property of each breakpoint object. The public interface for our macro module, Debugger, is EnableBreakPoints and DisableBreakpoints. (We can also reuse the query methods GetOutputWindow and GetActivePane in some other context if we need them. These methods were created using the Refactoring Replace Temp with Query Method; read martin Fowler's "Refactoring: Improving the Design of Existing Code" for more on Refactoring.)

Adding a Custom Macro to the Visual Studio IDE Menu

To invoke our macros we can use the Command Window and call the macro directly, as demonstrated: Macros.MyMacros.Debugger.EnableBreakpoints or Macros.MyMacros.Debugger.DisableBreakpoints. MyMacros is the name I gave to the project containing the Debugger module.

Figure 3: The Customize dialog is used for, among other things, adding your custom macros to a toolbar or menu.

Create a menu or toolbar shortcut for your macro by selecting Tools|Customize. With the Customize dialog displayed select the Commands tab. Find the Macros category and click on it (see figure 3). In the Commands list on the right find your custom macro and drag and drop the command onto a toolbar or menu. (If you have used macros in Microsoft Office you probably already know how to do this.) Macros have been around in Office for a while, and their integration into Visual Studio.Net works consistently with the way macros are managed in Office.

There is a tremendous amount of material in the extensibility model. Experiment with the Command Window and macros to gain some experience. When you find yourself performing a repetitive task, consider making that task a macro and making the macro available to your co-workers. You will find dozens of examples in the Samples.vsmacro project which ships with Visual Studio.Net.

About the Author

Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. He is the founder of Software Conceptions, Inc, founded in 1990. Paul Kimmel performs contract software development services in North America and can be contacted at pkimmel@softconcepts.com.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The first phase of API management was about realizing the business value of APIs. This next wave of API management enables the hyper-connected enterprise to drive and scale their businesses as API models become more complex and sophisticated. Today, real world product launches begin with an API program and strategy in mind. This API-first approach to development will only continue to increase, driven by an increasingly interconnected web of devices, organizations, and people. To support this rapid growth, …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds