Chapter 7: Exploring Commands Programmatically


Commands are the most fundamental mechanism of communication between the user and the Microsoft® Visual Studio® integrated development environment (IDE). In this chapter, we'll explore how you can use existing commands as well as create your own commands by using add-ins and macros.

What Is a Command?

If you've written user interface software for the Microsoft Windows® operating system, you're probably familiar with the event-driven programming model. When the user clicks a button on a form, chooses a menu item, or presses a key on the keyboard, your program receives a notification of that user action. If you're programming at the Windows SDK level, such as with the Microsoft Visual C++® programming language, when the user performs this action, your program receives a message detailing what happened. If you're using a language such as Microsoft Visual Basic® or Microsoft Visual C#®, this notification happens in the form of an event handler being called. These notifications are commands issued by the user, and the program carries out this command by performing some action for the user.

Visual Studio uses a method of notification similar to that of Win32® message-passing to inform code as the user interacts with the IDE. However, because of the complexity and number of commands available in the Visual Studio IDE, command routing, or passing a notification to the proper handler of that notification, isn't as simple as receiving a message. For instance, suppose the user chooses File | New | File. Because there are a number of different add-on programs (not to be confused with add-ins), such as Visual C++, Visual Basic, and Visual C#, Visual Studio needs to determine which of these programs handles this menu item choice. When a Win32 program handles a message, one message loop handles that message, but because there are a number of possible handlers of a command in Visual Studio, commands need to be routed to the correct code. Each of these add-on products reserves a globally unique identifier (GUID) to uniquely identify itself, and each command that is available associates itself with the GUID of a particular add-on. When a user executes a command, the GUID for that command is retrieved, the add-on program that handles that GUID is found, and the command is sent to that add-on.

A command also needs another part to identify itself. After all, if every command had just a GUID to identify it, and all the commands that belonged to an add-on had the same GUID, an add-on wouldn't be able to tell the difference between, for instance, the New File command and the New Project command. To disambiguate commands that all have the same GUID, a number, or ID, is assigned to each command in that group. An add-on is responsible for its own commands, so an ID can be assigned without conflicting with commands from a different add-on because the GUID for each add-on is different. When combined, this GUID and ID pair uniquely identifies each individual command.

Note 

A command in Visual Studio exists independently of any user interface elements (such as menu items) for that command. Commands can be created and destroyed, and a user interface element might have never been created for that command. But the opposite won't happen—a user interface element can't be created without having a corresponding command.

Locating Commands

In Visual Studio, all the commands that a user can issue are represented in the object model by a Command object, and the Commands collection contains a list of these objects. As do other collection objects, Command objects allow the use of standard enumeration constructs such as the keywords foreach in Visual C# or For Each in Visual Basic. Using these keywords, we can create a macro to walk the list of all Command objects:

 Sub WalkCommands()     Dim cmd As EnvDTE.Command     For Each cmd In DTE.Commands       'use the EnvDTE.Command object here     Next End Sub 

The Command collection's Item method works a bit differently from the Item methods of other collection objects. Commands.Item accepts as a parameter the familiar numerical index, but it also accepts an additional optional argument. If you're using the numerical indexing method, you should set the second argument to -1. This method has an additional argument because, as mentioned earlier, a GUID and ID pair is used to uniquely identify a command. The GUID, in string format, is passed as the first argument, and the ID of the command is passed as the second argument when you're using the GUID and ID to index the Commands collection. The following macro demonstrates finding the command for opening a file by using the GUID and ID pair:

 Sub FindFileOpenCommand()   Dim cmd As EnvDTE.Command   cmd = DTE.Commands.Item("{}", 222) End Sub 

As you can see, code like this can be complicated to write because you need to find and learn the GUID and ID for every command (which would be hard to do because there can be thousands of them), and then you must type this pair correctly every time, which can be a source of programming errors. To help with finding a Command object, the Commands.Item method accepts another format for indexing the collection, which is easier to remember: the name of a command.

Command Names

Remembering the GUID and ID for every command can be a huge waste of brainpower, so Visual Studio defines an easier-to-remember textual representation for most commands. These names follow a general pattern: the text of the top-level menu on which the primary user interface element for the command is located followed by a period, the text of all submenus combined followed by a period, and finally the text of the menu item. Any non-alphanumeric characters (except for the period separators and underscores) are then removed from this string. So to use the earlier example of finding the Command object for the open file command and combine it with our newly found way of using a command name, a macro such as the following results:

 Sub FindFileOpenCommandByName()     Dim command As EnvDTE.Command     command = DTE.Commands.Item("File.OpenFile") End Sub 

To find the GUID and ID pair of a command, you can use the GUID and ID properties of the Command object. We used these two properties to find the GUID and ID pair used in the FindFileOpenCommand macro shown earlier. This is the macro we used to find them:

 Sub FindGuidIDPair()     Dim guid As String     Dim id As Integer     Dim command As EnvDTE.Command     command = DTE.Commands.Item("File.OpenFile")     guid = command.Guid     id = command.ID     MsgBox(guid + ", " + id.ToString()) End Sub 

You can see the entire list of all available commands from within the Options dialog box on the Environment | Keyboard page. You can also use the object model to find available command names. We'll do this with the EnvDTE.Commands collection in this example macro:

     Sub CreateCommandList()         Dim command As EnvDTE.Command         Dim output As New OutputWindowPaneEx(DTE, "Create Command List")         For Each command In DTE.Commands             If (command.Name <> Nothing) Then                 output.WriteLine(command.Name)             End If         Next     End Sub 

When the macro is run, it places into the Output window the name of each command. If you examine the macro closely enough, you'll notice a special check to verify that the name of the command isn't set to Nothing. This check is done because if a command doesn't have a name set, it returns Nothing if it's using Visual Basic or null if it's using C#. Commands that don't have a name are usually used internally by Visual Studio for private communication, and the user generally shouldn't call them. We advise you not to use these commands because they can lead to unpredictable results.

Executing Commands

The purpose of a command is to provide a way for the user to direct Visual Studio to perform some action. Commands can be invoked in a number of ways, the most common of which is for the user to choose a menu item or click a toolbar button. But commands can also be run in other ways. For example, if you write a macro that conforms to the standard macro notation (it is defined as public, doesn't return a value, and takes no arguments unless the arguments are optional strings), the macros facility detects that macro and creates a command for it. Double-clicking that macro in the Macro Explorer window executes the command associated with that macro, which is handled by the Macros editor. A third way to run a command is to use the DTE.ExecuteCommand method. This method runs a command, given by name, as if the user had chosen the menu item for that command.

To run our File.OpenFile command by using the ExecuteCommand method, we would write code like this:

 Sub RunFileOpenCommand()     DTE.ExecuteCommand("File.OpenFile") End Sub 

When a call is made to the ExecuteCommand method, execution of the macro or add-in waits until the command finishes executing.

A final approach, which is useful for the power user, is to type the name of the command into the Command Window. The Command Window is a text-based window in which you type the names of commands; when the user presses the Enter key, the command is run.

The command name that you type into the Command Window is the same name that is returned from the Command.Name property, and it can be passed to the ExecuteCommand method.

Creating Macro Commands

As mentioned before, macros that follow a special format are automatically turned into commands, and these macro commands are given a named counterpart. The name of a macro command is calculated by combining the string Macros, the name of the macro project, the name of the module or class the macro is implemented in, and finally the name of the macro with each portion separated by a period. Using this format, the TurnOnLineNumbers command in the Samples macro project that is installed with Visual Studio takes on the name Macros.Samples.Utilities.TurnOnLineNumbers. You can enter this name in the Command Window or call it from another macro, like so:

 Sub RunCommand()     DTE.ExecuteCommand("Macros.Samples.Utilities.TurnOnLineNumbers") End Sub 




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