Try again

200512270453934121.gif

博客园 首页 联系 管理

Chapter 10. The Visual Studio Automation Object Model

IN THIS CHAPTER

Visual Studio is built to be "extensible." It ships with its own API to enable you, the developer, to control many of the pieces of the IDE.

The API is called the Visual Studio automation object model, and understanding its capabilities is the key to unlocking your ability to program and control the IDE itself by writing code in the form of macros and add-ins (discussed in Chapter 11, "Writing Macros, Add-Ins, and Wizards").

In this chapter, we discuss the layout and structure of the automation object model. We map the various objects in the object model to their IDE counterparts, delve into the various ways to interact with these objects through managed code, and, we hope, start to see a glimpse of the possibilities in terms of Visual Studio customization.

To drive home the object model concepts and place them in context, we have provided various code snippets and listings, nearly 100% of which are written in Visual Basic. The reason is that Visual Basic is the language of macros (other languages are not supported), and macros are by far the easiest and quickest way to reach out and touch elements of the IDE. As such, macros are a perfect vehicle for exploring and understanding the object model. In Chapter 11, we'll move beyond the object model and work to understand how to use, write, and run macros and add-ins (add-ins don't suffer from the Visual Basic limitation, so we'll switch gears and provide a majority of our add-in code using C#).

Don't worry too much about the mechanics of writing an add-in or macro at this point; concentrate instead on understanding the automation objects and how they are referenced and used. For the ambitious, know that the code listings here can be pasted directly into the Macros IDE Editor and run as is.

An Overview of the Automation Object Model

The automation object model is a structured class library with a top-level root object called DTE (or DTE2; more on this in a bit), which stands for Development Tools Environment. By referencing the assembly that implements the DTE/DTE2 object, you can instance this root object and use its members and child classes to access the IDE components.

Object Model Versions

The automation object model is actually implemented across two different, complementary primary interoperable assemblies: EnvDTE and EnvDTE80. EnvDTE is the original automation assembly distributed with previous versions of Visual Studio .NET. EnvDTE80 is a new library distributed with Visual Studio 2005. Visual Studio 2005 provides enhanced automation functionality. Because of this, Microsoft was faced with a common design decision: Replace or upgrade the current EnvDTE and risk introducing incompatibilities with current macros and add-ins, or ship a new assembly that could be leveraged in cases in which the new functionality was desired (existing code would still target the previous, unchanged library).

The latter path was chosen, and thus EnvDTE80 (80 represents version 8.0) represents the latest automation functions, while EnvDTE provides the base level of functionality and backward compatibility.

Within the EnvDTE80 assembly, you will find types that supersede their predecessors from the EnvDTE assembly. In these cases, the type name has been appended with a 2 to indicate the revised version. Thus, we have DTE and DTE2, Solution and Solution2, and so on.

Table 10.1 provides a side-by-side listing of some of the most important types implemented in EnvDTE and EnvDTE80. This type list is incomplete; it should be considered for reference only. This table is useful, however, for identifying some of the newly minted types in the new automation assembly; in the next section, we'll see how these types can be organized into broad Visual Studio automation categories and how they map onto physical IDE constructs.

Table 10.1. EnvDTE and EnvDTE80 Types

EnvDTE Type

EnvDTE80 Type

Description

AddIn

Represents a VS add-in.

Breakpoint

Breakpoint2

Returns the debugger object.

BuildDependencies

For the selected project, represents a collection of BuildDependency objects.

BuildDependency

For the selected project, represents the projects that it depends on for a successful build.

BuildEvents

Exposes a list of events relevant to a solution build.

Command

Represents a command action in the IDE.

Commands

Commands2

Returns a collection of all commands supported in the IDE.

CommandWindow

Represents the command window.

Configuration

Represents a project's configuration properties.

Debugger

Debugger2

Represents the Visual Studio debugger.

DebuggerEvents

Exposes events from the debugger.

Document

Represents an open document in the IDE.

Documents

Returns a collection of all open documents in the IDE.

DTE

DTE2

Represents the IDE; this is the top-level root object for the automation object model.

EditPoint

EditPoint2

Represents a text operation point within a document.

Events

Events2

Exposes all automation events.

Find

Find2

Represents the Find capability for text searches in the IDE.

HTMLWindow

Represents an HTML window.

OutputWindow

Represents the output window.

Program

(Process2)

Represents a program running within the IDE; useful for examining processes and threads within the program. EnvDTE80 functionality is provided by the Process2 object.

Project

Represents a project loaded in the IDE.

ProjectItem

Represents an item contained within a given project.

ProjectItems

Returns a collection of all items contained within a project.

Property

Represents a generic property for an object (this can be used across a variety of objects in the automation library).

SelectedItem

Represents projects or project items that are currently selected in the IDE.

Solution

Solution2

Represents the solution currently loaded in Visual Studio.

SourceControl

SourceControl2

Represents the source control system of record within Visual Studio.

TaskItem

Represents an item in the task list window.

TaskItems

TaskItems2

Returns a collection of all items in the task list window.

TaskList

Represents the task list window.

TexTDocument

Represents a text file open in the IDE.

TextPane

TextPane2

Represents a pane within an open text editor window.

TextWindow

Represents a text window.

ToolBox

Represents the Toolbox window.

ToolBoxItem

ToolBoxItem2

Represents an item within the Toolbox window.

ToolBoxTab

ToolBoxTab2

Represents a tab of items on the Toolbox window.

Window

Window2

Represents, generically, any window within the IDE.

Windows

Windows2

Returns a collection of all windows within the IDE.


Automation Categories

Because any automation effort with Visual Studio starts with the object model, you should understand first how it maps onto the IDE constructs and determine the exact capabilities that it exposes.

In general, you can think of the object model classes as being organized into categories that directly speak to these IDE concepts:

  • Solutions and projects

  • Windows and command bars (toolbars and menu bars)

  • Documents

  • Commands

  • Debugger

  • Events

Each of the objects in these categories touches a different piece of the IDE, and access to each object is always through the root-level DTE2 object.

The DTE/DTE2 Root Object

The DTE/DTE2 object represents the tip of the API tree. You can think of it as representing Visual Studio itself, with the objects under it mapping to the various constituent parts of the IDE.

As mentioned previously, DTE2 is the object used with Visual Studio 2005, with DTE providing compatibility with previous versions. In this chapter, unless we specifically need to differentiate between their capabilities, we will generically refer to the DTE and DTE2 objects as simply DTE.

The DTE properties are used to gain a reference to a specific IDE object (or collection of objects). Methods on the object are used to execute commands in the IDE, launch wizards, or close the IDE.

Table 10.2 shows the major properties and methods defined on the DTE2 object; they have been organized within the six object categories itemized in the preceding section.

Table 10.2. DTE2 Properties and Methods for IDE Access

Category

Property

Description

Commands

Commands

Returns a collection of Command objects; in general, a command is an action that can be carried out within the IDE such as opening or saving a file.

Debugger

Debugger

Returns the debugger object.

Documents

ActiveDocument

Returns a Document object representing the currently active document.

Documents

Documents

Returns a collection of Document objects representing all open documents.

Event Notification

Events

Returns the Events object for handling event notifications.

Solutions and Projects

ActiveSolutionProjects

Returns a collection of the Project objects representing the projects that are currently selected within the Solution Explorer.

Solutions and Projects

Solution

Returns the Solution object for the currently loaded solution.

Windows and Command Bars

ActiveWindow

Returns a Window object representing the window within the IDE that currently has focus.

Windows and Command Bars

CommandBars

Returns a collection of CommandBar objects representing all the toolbars and menu bars.

Windows and Command Bars

MainWindow

Returns a Window object representing the IDE window itself.

Windows and Command Bars

StatusBar

Returns a StatusBar object representing Visual Studio's status bar.

Windows and Command Bars

ToolWindows

Returns a ToolWindows instance, which in turns provides access to a few of the most prominent tool windows: the command window, error list, output window, Solution Explorer, task list, and Toolbox.

Windows and Command Bars

WindowConfigurations

Returns a collection of WindowConfiguration objects; these objects represent the various window layouts in use by Visual Studio.

Commands

ExecuteCommand

Executes an environment command.

--

LaunchWizard

Starts the identified wizard with the given parameters.

--

Quit

Closes Visual Studio.


Note

The mechanics of referencing and instancing a DTE object change slightly depending on whether you are writing an add-in or a macro, so we'll cover the specifics in the macro and add-in sections in Chapter 11.


In summary, the DTE object is a tool for directly interacting with certain IDE components and providing access to the deeper layers of the API with its property collections. If you move one level down in the API, you find the major objects that form the keystone for automation.

Solution and Project Objects

The Solution object represents the currently loaded solution. The individual projects within the solution are available via Project objects returned within the Solution.Projects collection. Items within a project are accessed in a similar fashion through the Project.ProjectItems collection.

As you can see from Figure 10.1, this hierarchy exactly mirrors the solution/project hierarchy that we first discussed in Chapter 4, "Solutions and Projects."

Figure 10.1. Mapping the solution/project hierarchy.


There are some mismatches heresolution folders, for instance, are treated as projectsbut for the most part, the object model tree closely resembles the solution project tree that you are used to.

The Solution object and Solution2 object members allow you to interact with the current solution to perform common tasks such as

  • Determining the number of projects in the solution (Count property)

  • Adding a project to the solution based on a project file (AddFromFile method)

  • Creating a new solution or closing the current one (Create and Close methods)

  • Saving the solution (SaveAs method)

  • Removing a project from the solution (Remove method)

You can also directly retrieve a reference to any of the projects within the currently loaded solution by iterating over the Solution.Projects collection. As an example of interacting with the Solution and Project objects, this Visual Basic code snippet removes the first project from the current solution:

Dim sol As Solution = DTE.Solution
Dim proj As Project = sol.Projects.Item(1)

If proj.Saved Then
             sol.Remove(proj)
Else
      ...
End If


Table 10.3 provides the combined list of the most commonly used properties and methods implemented by Solution2.

Table 10.3. Primary Solution/Solution2 Object Members

Property

Description

AddIns

Returns a collection of AddIn objects associated with the current solution.

Count

Returns a count of the projects within the solution.

DTE

Provides a reference back to the parent DTE object.

FullName

Provides the full path and name of the solution file.

IsOpen

Indicates whether a solution is open.

Projects

Returns a collection of Project objects representing all the projects within the solution.

Properties

Returns a collection of Property objects that expose all the solution's properties.

Saved

Indicates whether the solution has been saved since the last modification.

SolutionBuild

Returns a reference to a SolutionBuild object. This is the entry point to the build automation objects applicable for the current solution.


Method

Description

AddFromFile

Adds a project to the solution using an existing project file.

AddFromTemplate

Takes an existing project, clones it, and adds it to the solution.

AddSolutionFolder

Creates a new solution folder in the solution.

Close

Closes the solution.

Create

Creates an empty solution.

FindProjectItem

Initiates a search for a given item in one of the solution's projects.

Item

Returns a Project instance.

Open

Opens a solution (using a specific view).

Remove

Removes a project from the solution.

SaveAs

Saves the solution.


Controlling Projects in a Solution

One of the things that the Solution object is good for is retrieving references to the various projects that belong to the solution. Each Project object has its own set of useful members for interacting with the projects and their items. By using these members, you can interact with the projects in various, expected ways, such as renaming a project, deleting a project, and saving a project.

See Table 10.4 for a summary of the most common Project members.

Table 10.4. Primary Project Object Members

Property

Description

AddIns

Returns a collection of AddIn objects associated with the current solution.

Count

Returns a count of the project within the solution.

DTE

Provides a reference back to the parent DTE object.

FullName

Provides the full path and name of the solution file.

IsOpen

Indicates whether a solution is open.

Projects

Returns a collection of Project objects representing all the projects within the solution.

Properties

Returns a collection of Property objects that expose all the solution's properties.

Saved

Indicates whether the solution has been saved since the last modification.

SolutionBuild

Returns a reference to a SolutionBuild object. This is the entry point to the build automation objects applicable for the current solution.


Method

Description

AddFromFile

Adds a project to the solution using an existing project file.

AddFromTemplate

Takes an existing project, clones it, and adds it to the solution.

AddSolutionFolder

Creates a new solution folder in the solution.

Close

Closes the solution.

Create

Creates an empty solution.

FindProjectItem

Initiates a search for a given item in one of the solution's projects.

Item

Returns a Project instance.


=350>

Property

Description

Open

Opens a solution (using a specific view).

Remove

Removes a project from the solution.

SaveAs

Saves the solution.


Accessing Code Within a Project

Beyond the basic project attributes and items, one of the cooler things that can be accessed via a Project instance is the actual code within the project's source files. Through the CodeModel property, you can access an entire line of proxy objects representing the code constructs within a project. For instance, the CodeClass interface allows you to examine and edit the code for a given class in a given project.

Note

Support for the different CodeModel entities varies from language to language. The MSDN documentation for each CodeModel type clearly indicates the source language support for that element.


After grabbing a CodeModel reference from a Project instance, you can access its CodeElements collection (which is, not surprisingly, a collection of CodeElement objects). A CodeElement is nothing more than a generic representation of a certain code structure within a project. The CodeElement object is generic, but it provides a property, Kind. This property is used to determine the exact native type of the code object contained within the CodeElement.

The CodeElement.Kind property is an enumeration (of type vsCMElement) that identifies the specific type of code construct lurking within the CodeElement object. Using the Kind property, you can first determine the true nature of the code element and then cast the CodeElement object to its strong type. Here is a snippet of C# code that does just that:

if (element.Kind == vsCMElement.vsCMElementClass)
            CodeClass myClass = (CodeClass)element;


For a better grasp of the code model hierarchy, consider the C# code presented in Listing 10.1; this is a "shell" solution that merely implements a namespace, a class within that namespace, and a function within the class.

Listing 10.1. A Simple Namespace and Class Implementation

using System;
using System.Collections.Generic;
using System.Text;

namespace MyNamespace
{
   class MyClass
   {
       public string SumInt(int x, int y)
       {
           return x + y;
       }
   }
}

If you map the code in Listing 10.1 to the code object model, you would end up with the structure you see in Figure 10.2.

Figure 10.2. Simple code model object hierarchy.


To get an idea of the complete depth of the code model tree that can be accessed through the CodeElements collection, consult Table 10.5; this table shows all the possible vsCMElement values, the type they are used to represent, and a brief description of the type.

=200> =150> =150>
Table 10.5. Mapping the vsCMElement Enumeration Values

Enumeration Value

Type

Description

vsCMElementAssignmentStmt

An assignment statement

vsCMElementAttribute

An attribute

vsCMElementClass

CodeClass

A class

vsCMElementDeclareDecl

A declaration

vsCMElementDefineStmt

A define statement

vsCMElementDelegate

CodeDelegate

A delegate

vsCMElementEnum

CodeEnum

An enumeration

vsCMElementEvent

CodeEvent

An event

vsCMElementEventsDeclaration

An event declaration

vsCMElementFunction

CodeFunction

A function

vsCMElementFunctionInvokeStmt

A statement invoking a function

vsCMElementIDLCoClass

An IDL co-class

vsCMElementIDLImport

An IDL import statement

vsCMElementIDLImportLib

An IDL import library

vsCMElementIDLLibrary

An IDL library

vsCMElementImplementsStmt

An implements statement

vsCMElementImportStmt

CodeImport

An import statement

vsCMElementIncludeStmt

An include statement

vsCMElementInheritsStmt

An inherits statement

vsCMElementInterface

CodeInterface

An interface

vsCMElementLocalDeclStmt

A local declaration statement

vsCMElementMacro

A macro

vsCMElementMap

A map

vsCMElementMapEntry

A map entry

vsCMElementModule

A module

vsCMElementNamespace

CodeNamespace

A namespace

vsCMElementOptionStmt

An option statement

vsCMElementOther

CodeElement

A code element not otherwise identified in this enum

vsCMElementParameter

CodeParameter

A parameter

vsCMElementProperty

CodeProperty

A property

vsCMElementPropertySetStmt

A property set statement

vsCMElementStruct

CodeStruct

A structure

vsCMElementTypeDef

A type definition

vsCMElementUDTDecl

A user-defined type

vsCMElementUnion

A union

vsCMElementUsingStmt

CodeImport

A using statement

vsCMElementVariable

A variable

vsCMElementVBAttributeGroup

A Visual Basic attribute group

vsCMElementVBAttributeStmt

A Visual Basic attribute statement

vsCMElementVCBase

A Visual C++ base


Windows

The visible, content portion of Visual Studio is represented by Window objects. Window objects are instances of open windows within the IDE such as the Solution Explorer, the task list window, an open code editor window, and so on. Even the IDE itself is represented by a Window object.

Any given window is either a document window or a tool window. Document windows host documents that are editable by the Text Editor. Tool windows contain controls that display information relevant to the current context of the IDE; the Solution Explorer and task list windows are examples of tool windows, and a VB source code file open in an editor is an example of a document window.

Referencing Windows

If you need to retrieve an instance of a specific window, you have a few different options, each optimal for a given situation. For starters, the main IDE window is always available directly from the DTE object:

Dim IDE As Window
IDE = DTE.MainWindow


Obviously, if you need to perform a specific action against the IDE window, this is your quickest route.

The DTE.ActiveWindow property also provides direct and quick access to a Window object, in this case the currently active window:

Dim CurrentWindow As Window
CurrentWindow = DTE.ActiveWindow


The tool windows within the IDEthat is, the command window, the error list window, the output window, the Solution Explorer, the task list window, and the Toolboxalso have a direct way to retrieve their object model instances: You use the DTE.ToolWindows property. This property returns a ToolWindows object that exposes a separate property for each of the tool windows.

This Visual Basic code grabs a reference to the task list window and closes it:

Dim taskwin As Window

taskwin = DTE.ToolWindows.TaskList
taskwin.Close()


And finally, the fourth way to access an IDE window is through the DTE.Windows collection; this collection holds an entry for each IDE window. You can access a window from the collection by using either an integer representing the window's position within the collection, or by providing an object or string that represents the window you are trying to retrieve.

The following code grabs a handle to the Solution Explorer window:

Dim windows As Windows2 = DTE.Windows
Dim window As Window = windows.Item(Constants.vsWindowKindSolutionExplorer)


Interacting with Windows

Table 10.6 itemizes the properties and methods available on each Window object.

=150> =350>
Table 10.6. Window Object Members

Property

Description

AutoHides

A Boolean flag indicating whether the window can be hidden (applies only to tool windows).

Caption

The title/caption of the window.

Collection

The Windows collection that the current Window object belongs to.

CommandBars

A CommandBars collection of the command bars implemented by the window.

ContextAttributes

A collection of ContextAttribute objects; they are used to associate the current context of the window with the Dynamic Help window.

Document

If the Window object is hosting a document, this returns a reference to the document.

DTE

A reference to the root DTE object.

Height

The height of the window in pixels.

IsFloating

A Boolean flag indicating whether the window is floating or docked.

Left

The distance, in pixels, between the window's left edge and its container's left edge.

Linkable

A Boolean flag indicating whether the window can be docked with other windows.

LinkedWindowFrame

Returns a reference to the Window object that is acting as the frame for a docked window.

LinkedWindows

A collection of Window objects representing the windows that are linked together within the same frame.

Object

Returns an object proxy that represents the window and can be referenced by name.

ObjectKind

A GUID indicating the type of the object returned from Window.Object.

Project

A Project instance representing the project containing the Window object.

ProjectItem

A ProjectItem instance representing the project item containing the Window object.

Selection

Returns an object representing the currently selected item in the window (for document windows, this might be text; for tool windows, this might be an item in a list, and so on).

Top

The distance, in pixels, between the window's top edge and its parent's top edge.

Visible

A Boolean flag indicating whether the window is visible or hidden.

Width

The width of the window in pixels.

WindowState

Gets or sets the current state of the window (via a vsWindowState enum value: vsWindowStateMaximize, vsWindowStateMinimize, vsWindowStateNormal).


=150> =350>

Method

Description

Activate

Gives the window focus.

Close

Closes the window; you can indicate, with a vsSaveChanges enum value, whether the window's hosted document should be saved or not saved, or whether the IDE should prompt the user to make that decision.

SetSelectionContainer

Passes an array of objects to the Properties window when the Window object has focus. This property is mainly used for custom tool windows where you need to control what is displayed in the Properties window.

SetTabPicture

Specifies an object to use as a tab image; this image is displayed whenever the window is part of a tab group within the IDE.


Beyond the basics (such as using the Height and Width properties to query or affect a window's dimensions, or setting focus to the window with the SetFocus method), a few properties deserve special mention:

  • The Document property gives you a way to programmatically interact with the document that the window is hosting (if any).

  • The Project and ProjectItem properties serve to bridge the Window portion of the API with the Project/Solution portion; in a similar vein as the Document property, you can use these properties to interact with the project that is related to the window, or the project item (such as the VB code file, text file, resource file, and so on).

  • If you are dealing with a tool window, the SetTabPicture method provides a way to set the tab icon that is displayed when the tool window is part of a group of tabbed windows (for instance, the Toolbox window displays a wrench and hammer picture on its tab when part of a tabbed group).

  • Again, specifically for tool windows only, the SetSelectionContainer can be used to supply one or more objects for display within the Properties window. This capability is useful if you have a custom window where you need to control what is displayed in the Properties window when the window has focus (all the standard VS windows already do this for you).

Listing 10.2 contains a simple macro illustrating the use of the Window object; in this example, each window is queried to determine its type, and then a summary of each window is output in a simple message box.

Listing 10.2. VB Macro for Querying the Windows Collection

Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Windows.Forms


Public Module MacroExamples

    Public Sub InventoryWindows()
        ' Get collection of all open windows
        Dim windows As Windows2 = DTE.Windows

        ' Count the nbr of open windows
        Dim windowCount As Integer = windows.Count

        ' Local vars for looping and holding window and string
        ' results
        Dim idx As Integer
        Dim results As String
        Dim window As Window2

        results = windowCount.ToString + " windows open..." + vbCrLf

        ' Iterate the collection of windows
        For idx = 1 To windowCount

            window = windows.Item(idx)
            Dim title As String = window.Caption

            ' If the window is hosting a document, a valid Document
            ' object will be returned through Window.Document
            If Not (window.Document Is Nothing) Then
                ' Write this out as a document window
                Dim docName As String = window.Document.Name
                results = results + "Window '" + title + "' is a document window"
                    + vbCrLf
            Else
                ' If no document was present, this is a tool window
                ' (tool windows don't host documents)
                results = results + "Window '" + title + "' is a tool window"
                    + vbCrLf
            End If
        Next

        ' Show the results
        MessageBox.Show(results, "Window Documents", MessageBoxButtons.OK, _
            MessageBoxIcon.Information)

    End Sub

End Module

Note

If you want to embed your own custom control inside a tool window, you have to write an add-in and use the Windows.CreateToolWindow method. We cover this scenario in Chapter 11.


Text Windows and Window Panes

Text windows have their own specific object abstraction in addition to the generic Window object: The TextWindow object is used to represent text editor windows. To obtain a reference to a window's TextWindow object, you retrieve the Window object's value and assign it into a TextWindow type:

Dim textWindow As TextWindow
textWindow = DTE.ActiveWindow.Object


The TextWindow object doesn't provide much functionality over and above the functionality found in the Window type; its real value is the access it provides to window panes.

Text editor windows in Visual Studio can be split into two panes; with a text editor open, simply select Split from the Window menu to create a new pane within the window. The TextWindow.ActivePane property returns a TextPane object representing the currently active pane in the window, and the TextWindow.Panes property provides access to all the panes within a text window:

' Get pane instance from collection
Dim newPane As TextPane2
newPane = textWindow.Panes.Item(1)

' Get currently active pane
Dim currPane As TextPane2
currPane = textWindow.ActivePane


One of the more useful things you can do with the TextPane object is to scroll the client area of the pane (for example, the visible portion of the document within the pane) so that a specific range of text is visible. This is done via the TextPane.TryToShow method.

Here is the definition for the method:

Function TryToShow(Point As TextPoint, Optional How As vsPaneShowHow, _
    PointOrCount As Object)


The TextPoint parameter represents the specific location within the text document that you want visible in the text pane (we discuss TextPoint objects in depth in a later section of this chapter; see "Editing Text Documents"). The vsPaneShowHow value specifies how the pane should behave when scrolling to the indicated location:

  • vsPaneShowHow.vsPaneShowCentered will cause the pane to center the text/text selection in the middle of the pane (horizontally and vertically).

  • vsPaneShowHow.vsPaneShowTop will place the text point at the top of the viewable region in the pane.

  • vsPaneShowHow.vsPaneShowAsIs will show the text point as is with no changes in horizontal or vertical orientation within the viewable region in the pane.

The last parameter, the PointOrCount object, is used to specify the end of the text area that you want displayed. If you provide an integer here, this represents a count of characters past the original text point; if you provide another text point, then the selection is considered to be that text that resides between the two text points.

The TextPane object is also used to access the Incremental Search feature for a specific window pane. Listing 10.3 shows an example of this feature in action.

Listing 10.3. Controlling Incremental Search

Imports EnvDTE
Imports EnvDTE80
Imports Microsoft.VisualStudio.CommandBars
Imports System.Diagnostics
Imports System.Windows.Forms


Public Module MacroExamples

    Public Sub IncrementalSearch()
        ' Grab references to the active window;
        ' we assume, for this example, that the window
        ' is a text window.
        Dim window As Window2 = DTE.ActiveWindow
        ' Grab a TextWindow instance that maps to our
        ' active window
        Dim txtWindow As TextWindow = window.Object

        ' Get the active pane from the text window
        Dim pane As TextPane2 = txtWindow.ActivePane

        'Using the active pane, get an IncrementalSearch object
        ' for the pane
        Dim search As IncrementalSearch = pane.IncrementalSearch

        ' Try to find our IMessageMapper interface by looking
        ' for the string "IM"
        ' Configure the search:
        '   search forward in the document
        '   append the chars that we are searching for
        '   quit the search
        search.StartForward()
        search.AppendCharAndSearch(AscW("I"))
        search.AppendCharAndSearch(AscW("M"))

        ' To remove us from incremental search mode,
        ' we can call IncrementalSearch.Exit()...
        'search.Exit()

    End Sub
End Module

The Tool Window Types

In addition to having a Window object abstraction, each default tool window in the IDEthe command window, output window, Toolbox window, and task list windowis also represented by a discrete type that exposes methods and properties unique to that tool window. Table 10.7 lists the default tool windows and their underlying type in the automation object model.

=150> =350>
Table 10.7. Tool Windows and Their Types

Tool Window

Type

Command Window

CommandWindow

Output Window

OutputWindow

Task List Window

TaskList

Toolbox Window

ToolBox


To reference one of these objects, you first start with its Window representation and then cast its Window.Object value to the matching type. For instance, this VB snippet starts with a Window reference to the task list window and then uses that Window object to obtain a reference to the TaskList object:

Dim windows As Windows = DTE.Windows
Dim twindow As Window = _
    DTE.Windows.Item(EnvDTE.Constants.vsWindowKindTaskList)


Tasks and the Task List Window

The TaskList object enables you to access the items currently displayed in the task list window; each item in the window is represented by its own TaskItem object. The TaskItem object exposes methods and properties that allow you to manipulate the task items. For instance, you can mark an item as complete, get or set the line number associated with the task, and change the priority of the task.

You remove tasks from the list by using the TaskItem.Delete method and add them by using the TaskItems.Add method. The Add method allows you to specify the task category, subcategory, description, priority, icon, and so on:

Dim tlist As TaskList = CType(twindow.Object, TaskList)

tlist.TaskItems.Add("Best Practices", "Coding Style", _
   "Use of brace indenting is inconsistent", _
   vsTaskPriority.vsTaskPriorityMedium, _
   vsTaskIcon.vsTaskIconUser, True, _
   "S:\ContosoCommonFramework\Contoso.Fx.Common\Class1.cs", _
   7, True, True)


Table 10.8 provides an inventory of the TaskItem members.

=150> =350>
Table 10.8. TaskItem Members

Property

Description

Category

The category of the task.

Checked

A Boolean flag indicating whether the task is marked as completed (a check mark appears in the check box next to the task).

Collection

The TaskList collection that the current TaskItem object belongs to.

Description

The description of the task.

Displayed

A Boolean flag indicating whether the task is currently visible in the task list window.

DTE

A reference to the root DTE object.

FileName

The name of the file associated with the task (if any).

IsSettable

By passing in a vsTaskListColumn enum value to this property, you can determine whether that column is editable or not.

Line

The line number associated with the task.

Priority

A vsTaskPriority value indicating the task's priority level. Possible values include vsTaskPriorityHigh, vsTaskPriorityMedium, and vsTaskPriorityLow.

SubCategory

The subcategory of the task.

LinkedWindows

A collection of Window objects representing the windows that are linked together within the same frame.

Object

Returns an object proxy that represents the Window and can be referenced by name.

ObjectKind

A GUID indicating the type of the object returned from Window.Object.

Project

A Project instance representing the project containing the Window object.

ProjectItem

A ProjectItem instance representing the project item containing the Window object.

Selection

Returns an object representing the currently selected item in the Window (for document windows, this might be text; for tool windows, this might be an item in a list, and so on).

Top

The distance, in pixels, between the window's top edge and its parent's top edge.

Visible

A Boolean flag indicating whether the window is visible or hidden.

Width

The width of the window in pixels.

WindowState

Gets or sets the current state of the window (via a vsWindowState enum value: vsWindowStateMaximize, vsWindowStateMinimize, vsWindowStateNormal).


=150> =350>

Method

Description

Delete

Removes the task from the task list window.

Navigate

Causes the IDE to navigate to the location (for example, file and line) associated to the task.

Select

Selects or moves the focus to the task within the task list window.


Listing 10.4 contains a short VB macro demonstrating the use of the TaskList, TaskItems, and TaskItem objects to iterate the tasks and toggle their completed status.

Listing 10.4. Toggling Task Item Completion

Imports EnvDTE
Imports EnvDTE80
Imports Microsoft.VisualStudio.CommandBars
Imports System.Diagnostics
Imports System.Windows.Forms


Public Module MacroExamples

    Public Sub ToggleAllTasks()
        ' Reference the windows collection
        Dim windows As Windows = DTE.Windows

        ' Pluck the task list window from the collection
        Dim twindow As Window = _
            DTE.Windows.Item(EnvDTE.Constants.vsWindowKindTaskList)

        ' Convert the window object to a TaskList instance by
        ' casting its Object property
        Dim tlist As TaskList = CType(twindow.Object, TaskList)

        ' Iterate all of the task items in the task list
        For Each task As TaskItem In tlist.TaskItems
            ' Toggle the "completed" check mark on each item
            task.Checked = Not task.Checked
        Next


    End Sub
End Module

The ToolBox

Four objects are used to programmatically interface with the Toolbox:

  • ToolBoxAn object representing the Toolbox itself

  • ToolBoxTabsA collection representing the tab panes on the Toolbox

  • ToolBoxItemsA collection representing the items within a tab on the Toolbox

  • ToolBoxItemA discrete item displayed within a Toolbox tab

Figure 10.3 illustrates the Toolbox object hierarchy.

Figure 10.3. ToolBox object hierarchy.


These objects are used primarily to add, remove, or alter the items hosted by the Toolbox. For instance, you can easily add a custom tab to the Toolbox by using the ToolBoxTabs collection:

Dim tBox As ToolBox
Dim myTab As ToolBoxTab
tBox = DTE.Windows.Item(Constants.vsWindowKindToolbox).Object
myTab = tBox.ToolBoxTabs.Add("My TBox Tab")


You can also add items to any tab with the ToolBoxItems.Add method, which accepts a name for the item to add, a "data" object representing the item, and a vsToolBoxItem-Format enum, which specifies the format of the item. The Add method uses the vsToolBoxItemFormat to determine how to interpret the "data" object value. For instance, if you wanted to add a .NET control to the tab created in the previous code snippet, you could accomplish that with just one line of code:

tlBoxTab.ToolBoxItems.Add("ContosoControl", _
        "C:\Contoso\Controls\CalendarControl.dll", _
        vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent)


Notice that the item, in this case, is represented by a path to the assembly that implements the control and that it has an item format of vsToolBoxItemFormatDotNET-Component.

Listing 10.5 contains a VB function that adds a tab to the Toolbox, adds a control and a text fragment to the tab, and then removes the tab.

Listing 10.5. Adding and Removing Items in the Toolbox Window

Imports EnvDTE
Imports EnvDTE80
Imports Microsoft.VisualStudio.CommandBars
Imports System.Diagnostics
Imports System.Windows.Forms


    Public Sub AddAToolBoxTab()
        Dim toolBox As ToolBox
        Dim tabs As ToolBoxTabs
        Dim tab As ToolBoxTab
        Dim tabItems As ToolBoxItems
        Dim win As Window

        Try
            ' Get a reference to the toolbox
            win = DTE.Windows.Item(Constants.vsWindowKindToolbox)
            toolBox = win.Object
            ' Get a reference to the toolbox tabs collection
            tabs = toolBox.ToolBoxTabs

            ' Add a new tab to the ToolBox
            tab = tabs.Add("New ToolBox Tab")

            ' Make the added tab the active tab
            tab.Activate()

            tabItems = tab.ToolBoxItems

            With tabItems
                ' Add a piece of text to the toolbox.
                ' Clicking on the text will add it to
                ' the active document...
                .Add("Code Comment", _
                    "This is some text to add to the toolbox", _
                    vsToolBoxItemFormat.vsToolBoxItemFormatText)

                'Now add a control to the toolbox.
                'When adding a control, you need to specify
                'the path to the assembly; you can add all
                'classes from the assembly (shown below)
                'or just one of the classes (see MSDN
                'docs for that syntax)
                .Add("My Login Control", _
                    "C:\MyComponents\Contoso\LoginControl.dll", _
                    vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent)

                'For demonstration purposes, let's remove
                'the items that we had just added, and then
                'remove the newly created tab...

                'Put up a messagebox to confirm the deletes
                MessageBox.Show("Click OK to delete the tab and added items.", _
                    "Delete Toolbox Tab Items", MessageBoxButtons.OK, _
                    MessageBoxIcon.Information)

                'Delete the tab
                tab.Delete()

            End With

        Catch ex As Exception
            MsgBox("Error: " & ex.ToString())
        End Try

    End Sub

Executing Commands in the Command Window

The command window is a tool window used to execute IDE commands or aliases. IDE commands are essentially ways to tell the IDE to perform some action. Some commands map directly to menu items (such as File Open), whereas others don't have menu equivalents.

The CommandWindow object permits you to programmatically pipe commands into the command window and execute them. You can also output a text string (for informational purposes) to the window and clear its current content:

' Get a reference to the command window
Dim cmdWindow As CommandWindow = _
   DTE.Windows.Item(Constants.vsWindowKindCommandWindow).Object

' Display some text in the command window
cmdWindow.OutputString("Hello, World!")

' Clear the command window
cmdWindow.Clear()


Listing 10.6 shows how to programmatically execute commands in the CommandWindow object.

Listing 10.6. Executing Commands in the Command Window

Imports EnvDTE
Imports EnvDTE80
Imports Microsoft.VisualStudio.CommandBars
Imports System.Diagnostics
Imports System.Windows.Forms

Public Module MacroExamples

    Public Sub ExecCommandWindow()
        Dim cmdWindow As CommandWindow = _
            DTE.Windows.Item(Constants.vsWindowKindCommandWindow).Object
        ' Display some text in the command window
        cmdWindow.OutputString("Executing command from the automation OM...")

        ' Send some command strings to the command window and execute
        ' them...

        ' This command will start logging all input/output in the
        ' command window to the specified file
        cmdWindow.SendInput("Tools.LogCommandWindowOutput cmdwindow.log", True)

        ' Open a file in a code editor:
        '   1. We use an alias, 'of', for the File.OpenFile command
        '   2. This command takes quote-delimited parameters (in this case,
        '      the name of the editor to load the file in)
        Dim cmd As String = "of "
        cmd = cmd & """C:\Contoso\ContosoCommonFramework\Integration\Integration.cs"""
        cmd = cmd & "/e:""CSharp Editor"""

        cmdWindow.SendInput(cmd, True)

        cmdWindow.SendInput("Edit.Find MessageTrxId", True)

        ' Turn off logging
        cmdWindow.SendInput("Tools.LogCommandWindowOutput /off", True)

    End Sub
End Module

Output Window

The output window displays messages generated from a variety of different sources in the IDE. A prime example is the messages generated by the compiler when a project is being built. For a deeper look at the functionality provided by the output window, see Chapter 9, "Debugging with Visual Studio 2005."

The output window is controlled through three objects:

  • OutputWindow is the root object representing the output window.

  • OutputWindowPanes is a collection of OutputWindowPane objects.

  • OutputWindowPane represents one of the current panes within the output window.

Using these objects, you can add or remove panes from the output window, output text to any one of the panes, and respond to events transpiring in the window.

The following VB code fragment retrieves a reference to the output window and writes a test string in the Build pane:

Dim outWindow As OutputWindow = _
DTE.Windows.Item(Constants.vsWindowKindOutput).Object

Dim pane As OutputWindowPane = _
      outWindow.OutputWindowPanes.Item("Build")

pane.OutputString("test")


Using the OutputWindowPane object, you can also add items simultaneously to a specific output pane and the task list window. The OutputWindowPane.OutputTaskItemString method writes text into the output window and simultaneously adds that text as a task to the task list window:

Dim output As String = "Exception handler not found"
Dim task As String = "Add exception handler"
pane.OutputTaskItemString(output, _
   vsTaskPriority.vsTaskPriorityMedium,  "", vsTaskIcon.vsTaskIconNone, _
   "", 0, task, True)


Because most of the output window actions are conducted against a specific pane, most of the useful methods are concentrated in the OutputWindowPane object. For your reference, the OutputWindowPane members are itemized in Table 10.9.

=150> =350>
Table 10.9. OutputWindowPane Members

Property

Description

Collection

The OutputWindowPanes collection that the current OutputWindowPane object belongs to

DTE

A reference to the root DTE object

Guid

The GUID for the output window pane

Name

The name of the output window pane

Textdocument

A Textdocument object representing the window pane's content


=150> =350>

Method

Description

Activate

Moves the focus to the output window

Clear

Clears the contents of the window pane

ForceItemsToTaskList

Writes all task items not yet written to the task list window

OutputString

Writes a string to the output window pane

OutputTaskItemString

Writes a string to the output window pane and simultaneously adds a task to the task list window


Listing 10.7 demonstrates controlling the output window by adding a new pane to the window, writing text into that pane, and then clearing its content.

Listing 10.7. Writing to the Output Window

Imports EnvDTE
Imports EnvDTE80
Imports Microsoft.VisualStudio.CommandBars
Imports System.Diagnostics
Imports System.Windows.Forms


Public Module MacroExamples

    Public Sub WriteToOutputWindow()

        ' Grab a reference to the output window
        Dim outWindow As OutputWindow = _
            DTE.Windows.Item(Constants.vsWindowKindOutput).Object

        ' Create a new pane in the output window
        Dim pane As OutputWindowPane = _
            outWindow.OutputWindowPanes.Add("New Pane")

        pane.OutputString("Text in the 'New Pane'")

        pane.Clear()

    End Sub
End Module

Linked Windows

Tool windows can be positioned in a variety of ways within the IDE: You can float tool windows around within the overall IDE container; you can dock a tool window to one of the sides of the IDE; you can join windows together, pin and unpin them; and so on (see the section "Managing the Many Windows of the IDE" in Chapter 2, "A Quick Tour of the IDE," for an introduction to window layout).

A linked window refers to two or more tool windows that have been aggregated together. Figure 10.4 shows one common example of this: The Toolbox and Solution Explorer and the Data Sources window have all been joined together in a common frame. Each window that is part of the frame can be viewed by clicking on its tab.

Figure 10.4. Linked windows.


By joining together two or more tool windows, you actually create an additional window objectcalled a linked window or window framethat functions as the container for its hosted tool windows and is available as a part of the DTE.Windows collection.

By using the Window.LinkedWindows and Window.WindowFrame properties and the Windows2.CreateLinkedWindowFrame method, you can programmatically link and unlink any available tool windows. The Visual Basic code in Listing 10.8 demonstrates this process by doing the following:

  1. You grab the window objects for the Toolbox window and the Solution Explorer window.

  2. You programmatically join these two windows together, effectively creating the linked window that you see in Figure 10.4.

  3. After joining the windows together, you get a reference to the newly created linked window and use its LinkedWindows property to unlink the windows that were previously just linked together.

Listing 10.8. Linking and Unlinking Tool Windows

Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Windows.Forms

Public Module MacroExamples

    Public Sub LinkUnLink()
        Dim windows As Windows2 = DTE.Windows

        ' Grab references to the solution explorer and the toolbox
        Dim solExplorer As Window2 = _
            windows.Item(Constants.vsWindowKindSolutionExplorer)
        Dim toolbox As Window2 = windows.Item(Constants.vsWindowKindToolbox)

        ' Use the Windows2 collection to create a linked window/window
        ' frame to hold the toolbox and solution explorer windows
        Dim windowFrame As Window2
        windowFrame = windows.CreateLinkedWindowFrame(solExplorer, _
            toolbox, vsLinkedWindowType.vsLinkedWindowTypeTabbed)

        ' At this point, we have created a linked window with two tabbed
        ' "interior" windows: the solution explorer, and the toolbox...

        MessageBox.Show("Press OK to Unlink the windows", "LinkUnLink", _
            MessageBoxButtons.OK, MessageBoxIcon.None)

        ' To unlink the windows:
        '   -- Use the window frame's
        '   -- Remove the window objects from this collection

        windowFrame.LinkedWindows.Remove(toolbox)
        windowFrame.LinkedWindows.Remove(solExplorer)

    End Sub
End Module


Command Bars

A command bar is a menu bar or toolbar; from an object model perspective, these are represented by CommandBar objects. Because menu bars and toolbars are hosted within a window, you reference specific CommandBar objects via the Window object, through the Window.CommandBars property. In turn, every CommandBar plays host to controls such as buttons, drop-downs, and so on. Figure 10.5 shows the Solution Explorer tool window with its command bar highlighted.

Figure 10.5. The Solution Explorer tool window and its command bar.


Note that there are six buttons hosted on the command bar.

Note

Unlike the Windows collection, which holds only an instance of each open window, the CommandBars collection holds instances for every single registered command bar, regardless of whether the command bar is currently being shown in the window.


The VB code in Listing 10.9 queries the CommandBar object for the Solution Explorer window and prints out the CommandBar objects that it finds.

Listing 10.9. Querying the CommandBar Object

Imports EnvDTE
Imports EnvDTE80
Imports Microsoft.VisualStudio.CommandBars
Imports System.Diagnostics
Imports System.Windows.Forms


Public Module MacroExamples

    Public Sub QueryCommandBar()
        Dim windows As Windows2 = DTE.Windows

        ' Grab reference to the solution explorer
        Dim solExplorer As Window2 = _
            windows.Item(Constants.vsWindowKindSolutionExplorer)

        ' Retrieve the solution explorer's command bar object
        Dim cmdBar As CommandBar = CType(solExplorer.CommandBars(1), CommandBar)

        ' Start building our output string
        Dim output As String = "Command bar contains: " + vbCrLf
        ' Get a reference to the controls hosted in the
        ' command bar
        Dim controls As CommandBarControls = cmdBar.Controls

        ' Count integer
        Dim i As Integer = 1

        ' Iterate the controls in the command bar
        For Each control As CommandBarControl In controls

            If control.Enabled Then

                output = output + i.ToString() + " " + _
                    control.Type.ToString() + _
                    ": " + control.Caption + vbCrLf

                i = i + 1

            End If

        Next

        MessageBox.Show(output, "Solution Explorer Command Bar", _
            MessageBoxButtons.OK)

    End Sub
End Module

Correlate the results in Figure 10.6 with Figure 10.4: Six buttons are visible on the tool window, and the code has found six items in the CommandBarControls collection (which is returned through the CommandBar.Controls property). Removing the following check against the Enabled property would result in many more controls produced in the message box:

If control.Enabled Then


Figure 10.6. Controls found in the command bar.


Notice in Listing 10.9 that you have to explicitly cast the object returned from the Window.CommandBars property: this is, interestingly, not a strongly typed property, and it returns an Object instead of an actual CommandBars instance.

Tip

Use the CommandBar.Type property to determine whether a command bar is a toolbar or a menu bar. A value of MsoBarType.msoBarTypeNormal indicates that the command bar is a toolbar, whereas a value of MsoBarType.msoBarTypeMenu indicates that the command bar is a menu bar.


The CommandBar object properties and methods are documented in Table 10.10.

=150> =350>
Table 10.10. CommandBar Members

Property

Description

AdaptiveMenu

For menu bars, this Boolean flag indicates whether the command bar has adaptive menus enabled. (Adaptive menus, sometimes referred to as personalized menus, are menus that alter their drop-down content based on projected or actual usage by the user; the intent is to display only those commands that are useful on the menu and hide the other nonessential commands.)

Application

An object representing the parent application to the command bar.

BuiltIn

Boolean flag used to distinguish between built-in and custom command bars.

Context

A string indicating where the CommandBar is saved (the format and expected content of this string are dictated by the hosting application).

Controls

A CommandBarControls collection containing CommandBarControl objects; each of these objects represents a control displayed by the command bar.

Creator

An integer value that identifies the application hosting the CommandBar.

Enabled

A Boolean flag indicating whether the command bar is enabled.

Height

The height of the command bar in pixels.

Index

The index of the command bar in the command bar collection.

Left

The distance, in pixels, between the left side of the command bar and the left edge of its parent container.

Name

The name of the command bar.

NameLocal

The localized name of the command bar.

Parent

An object that is the parent of the command bar.

Position

An MsoBarPosition enum value used to get or set the position of the command bar (for example, MsoBarPosition.msoBarTop).

Protection

An MsoBarProtection enum value that identifies the protection employed against used modification (for example, MsoBarProtection.msoBarNoMove).

RowIndex

An integer representing the docking row of the command bar.

Top

The distance, in pixels, between the top of the command bar and the top edge of its parent container.

Type

The type of the command bar (as an MsobarType enum value; for example, MsoBarType.msoBarTypeNormal).

Visible

A Boolean flag indicating whether the command bar is currently visible.

Width

The width of the command bar in pixels.


=150> =350>

Method

Description

Delete

Removes the command bar from its parent collection.

FindControl

Enables you to retrieve a reference to a control hosted by the command bar that fits various parameters such as its type, ID, tag, and visibility.

Reset

Resets one of the built-in command bars to its default configuration.

ShowPopup

Displays a pop-up representing a command bar.


Note

Previous versions of Visual Studio actually relied on a Microsoft Office assembly for the CommandBar object definition (Microsoft.Office.Core). Visual Studio 2005 provides its own implementation of the CommandBar object that is defined in the Microsoft.VisualStudio.CommandBars namespace, although you will find some types that carry their nomenclature over from the MS Office assembly, such as the various MsoXXX enums.


Command Objects

Every action that is possible to execute through the menus and toolbars in Visual Studio is generically referred to as a command. For example, pasting text into a window is a command, as is building a project, toggling a breakpoint, and closing a window.

For each command supported in the IDE, there is a corresponding Command object; the DTE.Commands collection holds all the valid Command object instances. Each command is keyed by a name that categorizes, describes, and uniquely identifies the command. The "paste" command, for instance, is available via the string key "Edit.Paste". If you wanted to retrieve the Command object mapping to the paste command, you would pull from the Commands collection using that string key:

Dim commands As Commands2 = DTE.Commands
Dim cmd As Command = commands.Item("Edit.Paste")

You can query a command's name via its Name property:

' name would = "Edit.Paste"
Dim name As String = cmd.Name

Table 10.14 contains the members declared on the Command interface.

=150> =350>
Table 10.14. Command Members

Property

Description

Bindings

The keystrokes that can be used to invoke the command

Collection

The Commands collection that the Command object belongs to

DTE

A reference to the root-level DTE object

GUID

A GUID that identifies the command's group

ID

An integer that identifies the command within its group

IsAvailable

A Boolean flag that indicates whether the command is currently enabled

LocalizedName

The localized name of the command

Name

The name of the command


=150> =350>

Method

Description

AddControl

Creates a control for the command that can be hosted in a command bar

Delete

Removes a named command that was previously added with the Commands.AddNamedCommand method


The list of all available commands is extremely long (nearly 3,000 total), and it is therefore impossible to cover every one of them here, or even a large portion of them. To get an idea, however, of the specific commands available, you can visit the dialog box used to customize the Visual Studio toolbars. If you select the Customize option from the View, Toolbars menu, and then click on the Commands tab, you can investigate all the various commands by category (see Figure 10.9). Another alternative would be to programmatically iterate the DTE.Commands collection and view them that way. In fact, in the following chapter, we use this as one scenario for showcasing add-in development.

Figure 10.9. Using the Customize dialog box to view commands.


So, although we can't cover all the commands, you can learn how to perform common tasks with the Command objects such as executing a command, checking on a command's current status, and even adding your own commands to the command library.

Executing a Command

Commands can be executed in two different ways. The DTE object has an ExecuteCommand method that you can use to trigger a command based on its name:

DTE.ExecuteCommand("Window.CloseDocumentWindow")

The Commands collection is also a vehicle for launching commands through its Raise method. Instead of using the command's name, the Raise method uses its GUID and ID to identify the command:

Dim commands As Commands2 = DTE.Commands
Dim cmd As Command = commands.Item("Window.CloseDocumentWindow")
Dim customIn, customOut As Object

commands.Raise(cmd.Guid, cmd.ID, customin, customout)

Some commands accept arguments. The Shell command is one example. It is used to launch an external application into the shell environment and thus takes the application filename as one of its parameters. You can launch this command by using the ExecuteCommand method like this:

Dim commands As Commands2 = DTE.Commands
Dim cmd As Command = commands.Item("Tools.Shell")
Dim arg1 = "MyApp.exe "

DTE.ExecuteCommand(cmd.Name, arg1)

The Raise method also works with arguments: The last two parameters provided to the Raise method are used to specify an array of arguments to be used by the command and an array of output values returned from the command.

Mapping Key Bindings

Most commands can be invoked by a keyboard shortcut in addition to a menu entry or button on a command bar. You can set these keyboard shortcuts on a per-command basis by using the Command.Bindings property. This property returns or accepts a SafeArray (essentially an array of objects) that contains each shortcut as an element of the array.

Key bindings are represented as strings with the following format:

"[scopename]::[modifier+][key]".

Scopename is used to refer to the scope where the shortcut is valid, such as Text Editor or Global. The modifier token is used to specify the key modifier such as "ctrl+", "alt+", or "shift+" (modifiers are not required). And the key is the keyboard key that will be pressed (in conjunction with the modifier if present) to invoke the command.

To add a binding to an existing command, you first need to retrieve the current array of binding values, add your binding string to the array, and then assign the whole array back into the Bindings property like this:

Dim commands As Commands2 = DTE.Commands
Dim cmd As Command = _
     commands.Item("File.SaveSelectedItems")

Dim bindings() As Object

bindings = cmd.Bindings

' Increase the array size by 1 to hold the new binding
ReDim Preserve bindings(bindings.GetUpperBound(0) + 1)

' Assign the new binding into the array
bindings(bindings.GetUpperBound(0)) = "Global::Shift+F2"

' Assign the array back to the command object
cmd.Bindings = bindings

Note

You can create your own named commands that can be launched from a command bar in the IDE (or from the command window for that matter). The Command object itself is added to the Commands collection by calling Commands.AddNamedCommand. The code that will run when the command is executed will have to be implemented by an add-in. We'll cover this scenario in Chapter 11.


Debugger Objects

The automation object model provides a Debugger object that allows you to control the Visual Studio debugger. A Debugger instance can be obtained through the DTE.Debugger property:

Dim debugger As Debugger
debugger = DTE.Debugger

With a valid Debugger object, you can

  • Set breakpoints

  • Start and stop the debugger for a given process

  • Control the various execution stepping actions supported by the debugger such as Step Into, Step Over, and Step Out

  • Issue the Run to Cursor command to the debugger

  • Query the debugger for its current mode (for example, break mode, design mode, or run mode)

The following code starts the debugger if it isn't already started:

Dim debugger As Debugger2
debugger = DTE.Debugger

If debugger.CurrentMode <> dbgDebugMode.dbgRunMode Then
    debugger.Go()
End If

Automation Events

If your macro or add-in needs to be notified when a certain event occurs, various event objects are supported in all the automation object categories previously discussed. There are events for windows, events for editors, events for projects, and so on. For every event supported by the IDE, a corresponding class in the automation model allows you to hook the event and take action if the event is raised. The event objects tree is rooted in the DTE.Events property, as depicted in Figure 10.10.

Figure 10.10. Event types.


Because events are handled differently depending on whether you are working with code in an add-in or code in a macro, we will wait until the next chapter to cover the details of handling events. The basic premise, however, is fairly simple: You obtain a reference to the event object that you are interested in and then write an event handler that responds to one of that object's published events.

This code, for instance, is how you might handle the "build complete" event from inside a Visual Basic add-in:

Dim WithEvents bldevents As BuildEvents
bldevents = DTE.Events.BuildEvents

After instantiating a BuildEvents object, you now have to write the actual event handler:

Private Sub bldevents_OnBuildDone(ByVal Scope As EnvDTE.vsBuildScope, _
     ByVal Action As EnvDTE.vsBuildAction) Handles bldevents.OnBuildDone
        ' Code to handle the event goes here
    End Sub

Summary

The Visual Studio automation object model is a deep and wide API that exposes many of the IDE components to managed code running as a macro or an add-in. In this chapter, we documented how this API is organized and described its capabilities in terms of controlling the Visual Studio debugger, editors, windows, tool windows, solutions, and projects.

We also discussed the eventing model exposed by the API and looked at the API's capabilities with regards to accessing the underlying code structure for a project, issuing commands inside the IDE, and editing text documents programmatically.

Using the methods and properties expressed on the automation objects, you can automate common tasks in the IDE and extend Visual Studio in ways that address your specific development tool needs.

In the next chapter, we will directly build on the concepts discussed here and specifically walk you through the process of building add-ins and writing macros that talk to the automation objects.

posted on 2007-08-29 15:15  共同学习,共同进步  阅读(2293)  评论(1编辑  收藏  举报