Working with Macros


The macros you build will use the automation object model to access and automate the different parts of the IDE. In this section, we'll demonstrate how you can use macros to automate some simple tasks, and we'll talk a bit about the automation object model as it applies to documents and windows in the IDE. We'll also discuss events and provide some simple examples to help you get going right away.

Manipulating Documents and Text

Some of the most useful tasks you can perform with macros involve working with text in documents. You might want to search for text, change a selection in some way, or just insert text into a document. The Document object in the DTE provides a good deal of functionality that makes it easy to manipulate text in code documents.

Macros are often run on the document with the current focus. To get the currently active document in the IDE, use the DTE.ActiveDocument property, which returns a Document object. (Recall that a Visual Studio document is an editor or a designer window that opens to the center of the IDE.) If the document is an editor, it has an associated TextDocument object.

The TextDocument object has three properties of interest for programmers who want to manipulate text inside the object. The StartPoint property returns a TextPoint object that points to the beginning of the document. The EndPoint property returns a TextPoint object that points to the end of the document. And finally, the Selection property returns a TextSelection object that offers a number of properties and methods you can use on selected text.

The TextPoint object provides location information for the editing functionality inside a document. You create a TextPoint in a document whenever you want to insert or manipulate text in the document or when you want to get some information about a particular document. TextPoint objects aren't dependent on text selection, and you can use multiple TextPoint objects in a single document.

Let's look at a couple of examples that use the objects we've mentioned. You should become familiar with this code because much of the macro automation code you'll write will depend on it.

First, let's get the ActiveDocument, create a couple of EditPoint objects, and then add some text to the ActiveDocument by using that information:

 Sub CommentWholeDoc()     Dim td As TextDocument = ActiveDocument.Object     Dim sp As TextPoint     Dim ep As TextPoint     sp = td.StartPoint.CreateEditPoint()     ep = td.EndPoint.CreateEditPoint()     sp.Insert("/* ")     ep.Insert(" */") End Sub 

Running this sample on a Microsoft Visual C#® or a Microsoft Visual C++® code document will comment out the entire document. The macro isn't very practical, but it does show you how to put those parts together. You can use IntelliSense to make your way through the objects created so that you can experiment with some of the other functionality.

Let's take a look at a second, more useful, example that inserts text into a document based on a selection. The following example wraps selected text with whatever text we want in a document. Here we'll declare ts as a TextSelection object and assign it the current selection using DTE.ActiveDocument.Selection:

 Sub HTMLComment()     Dim ts As TextSelection = DTE.ActiveDocument.Selection     Dim ep As TextPoint     ep = ts.BottomPoint.CreateEditPoint()     ts.Insert("<!--", vsInsertFlags.vsInsertFlagsInsertAtStart)     ep.Insert(" -->")     ts.Collapse() End Sub 

This macro uses the TextSelection Insert method to insert text at the beginning of the Selection object. The Insert method takes two arguments. The first argument is the string that you want to insert into the selection. The second argument is a vsInsertFlags constant that defines where the insertion is to take place. The Insert call in the example uses vsInsertFlagsAtStart. To close the tag, we use an Insert with a TextPoint because the insertion point changes after the first insert. If we just wanted to add text to the end of a selection, we could just use vsInsertFlagsInsertAtEnd. Table 5-2 lists these constants.

Table 5-2: vsInsertFlags Constants

Constant

Description

vsInsertFlagsCollapseToStart

Collapses the insertion point from the end of the selection to the current TextPoint

vsInsertFlagsCollapseToEnd

Collapses the insertion point from the beginning of the selection to the current TextPoint

vsInsertFlagsContainNewText

Replaces the current selection

vsInsertFlagsInsertAtStart

Inserts the text before the start point of the selection

vsInsertFlagsInsertAtEnd

Inserts text just after the end point of the selection

With a Selection, a TextPoint, and the methods available through the DTE, you should have a good basis for the types of operations you can perform on source code by using macros.

Moving Windows

Windows in Visual Studio are controlled through the Window object, which is part of the DTE.Windows collection. The Window object provides functionality based on the window type. Specifically, the CommandWindow, OutputWindow, TaskList, TextWindow, and ToolBox derive from the Window object.

Of the window objects, OutputWindow is among the most practical for macro writing. You can use it to display and hold messages in much the same way you would use printf or Console.Write in a console application or in the same way that you use MsgBox or MessageBox.Show in a Microsoft Windows®–based application.

To use the OutputWindow object to display messages, you must create a new method that takes a string argument. You can then call the method with the argument in the same way you use the MsgBox method to display a message. The following example is a method named MsgWin. It takes only a string as an argument. You can use this method in place of MsgBox when you want to see a bit of text information quickly.

 Sub MsgWin(ByVal msg As String)     Dim win As Window = DTE.Windows.Item(Constants.vsWindowKindOutput)     Dim cwin As Window =         DTE.Windows.Item(Constants.vsWindowKindCommandWindow)     Dim ow As OutputWindow = win.Object     Dim owp As OutputWindowPane     Dim cwp As CommandWindow = cwin.Object     Dim i As Integer     Dim exists As Boolean = False     ' Check to see if we're running in the Command Window. If so,     ' we'll send our output there. If not, we'll send it to a Command     ' window.     If (DTE.ActiveWindow Is cwin) Then         cwp.OutputString(msg + vbCrLf)     Else         ' Determine if the output pane name exists. If it does, we need         ' to send our message there, or we end up with multiple windows of         ' the same name.         For i = 1 To ow.OutputWindowPanes.Count             If ow.OutputWindowPanes().Item(i).Name() = "MsgWin Output" Then                 exists = True                 Exit For             End If         Next         ' If our output pane exists, we'll use that to output the string,         ' otherwise, we'll add it to the list.         If exists Then             owp = ow.OutputWindowPanes().Item(i)         Else             owp = ow.OutputWindowPanes.Add("MsgWin Output")         End If         ' Here we set the Output window to visible, activate the pane,         ' and send the string to the pane.         win.Visible = True         owp.Activate()         owp.OutputString(msg + vbCrLf)     End If End Sub 

To use the MsgWin macro, you must call it from another method. For this example, we've created a method that lists all the currently open windows in the IDE:

 Sub MsgWinTest()     Dim wins As Windows = DTE.Windows()     Dim i As Integer     For i = 1 To wins.Count         MsgWin(wins.Item(i).Caption.ToString())     Next End Sub 

Figure 5-6 shows what the Visual Studio IDE looks like after it has been invoked from the MsgWinText macro in the IDE.

image from book
Figure 5-6: The MsgBox Output window in the IDE

You can do a lot of things with this basic MsgWin macro to improve it. It would be pretty trivial to overload the MsgWin method to allow for such actions as clearing the output pane or adding a heading to the list. For example, to create an overload for the MsgWin function that clears the output pane, you can make the method look something like this:

 Sub MsgWin(ByVal msg As String, ByVal clr As Boolean)         §         ' If clr is True then we'll clear the output pane.         If clr = True Then             owp.Clear()         End If         ' Here we set the Output window to visible, activate the pane,         ' and then send the string to the pane.         win.Visible = True         owp.Activate() owp.OutputString(msg + vbCrLf)     End If End Sub 

Macro Events

One of the most powerful features of macros in the IDE is an event model that lets you fire macros based on events that take place in the IDE. You can use events to fire macros that create logs, reset tests, or manipulate different parts of the IDE in the ways we've already talked about in this chapter. In this short section, we'll show you how to create event handlers for different events in the IDE. Using this information and the detailed information about the different parts of the automation API discussed throughout the rest of the book, you should have a good idea of how to take advantage of events in your own projects.

The easiest way to get to the event handlers for a macros project is through the Project Explorer window in the Macros IDE. Expand a project, and you'll see an EnvironmentEvents module listed. Open that file, and you'll see a block of code that's been generated automatically by the IDE. Here's the important part of the block (the attributes have been removed to make this fit the page):

 Public WithEvents DTEEvents As EnvDTE.DTEEvents Public WithEvents DocumentEvents As EnvDTE.DocumentEvents Public WithEvents WindowEvents As EnvDTE.WindowEvents Public WithEvents TaskListEvents As EnvDTE.TaskListEvents Public WithEvents FindEvents As EnvDTE.FindEvents Public WithEvents OutputWindowEvents As EnvDTE.OutputWindowEvents Public WithEvents SelectionEvents As EnvDTE.SelectionEvents Public WithEvents BuildEvents As EnvDTE.BuildEvents Public WithEvents SolutionEvents As EnvDTE.SolutionEvents Public WithEvents SolutionItemsEvents As EnvDTE.ProjectItemsEvents Public WithEvents MiscFilesEvents As EnvDTE.ProjectItemsEvents Public WithEvents DebuggerEvents As EnvDTE.DebuggerEvents 

As you can see from this code, there are a lot of event types you can take advantage of in the IDE. In fact, you can use all the DTE events, even though they're not included by default. You can add these other events to this list to get to the events that you're interested in. To create a new event handler, you select the event type you want to handle from the class name list at the top of the code window. You can see how this looks in Figure 5-7.

image from book
Figure 5-7: Selecting the event type you want to handle from the class name list

After you select an event type, the method name list in the upper-right portion of the code pane will list the events you can handle, as shown in Figure 5-8.

image from book
Figure 5-8: Selecting the event you want to handle from the method name list

Select the event you want from the list, and your event handler will be generated automatically. From this generated event handler, you can call a method that you've created in the project, or you can add your event-handling functionality directly to the event-handler code. In this example, we'll call the MsgWin function that we worked through earlier to display a message that indicates that the build has completed.

 Private _ Sub BuildEvents_OnBuildDone(ByVal Scope _    As EnvDTE.vsBuildScope, _    ByVal Action As EnvDTE.vsBuildAction) _    Handles BuildEvents.OnBuildDone         MsgWin("Build is done!") End Sub 

As you can imagine, these events open up all sorts of possibilities for automation and customization in the IDE. One thing you should keep in mind when working with events is that all the code in a single macro project shares the same event module. This means that if you want to create different event handlers for the same event, you'll need to create the other event handlers in other projects.

image from book
Event Security

As you can imagine, executing event code in a powerful macros facility such as the one in Visual Studio has some potential security implications. The first time you load a macro project that contains event-handling code, you see a dialog box that looks like this:

image from book

You should be sure you know where your macros come from when you load macro projects. If you're not sure of the event-handling code in the project, click Disable Event Handling Code in the Warning dialog box and review the code in the module before you use it.

image from book




Working with Microsoft Visual Studio 2005
Working with Microsoft Visual Studio 2005
ISBN: 0735623155
EAN: 2147483647
Year: 2006
Pages: 100

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net