How to: Create and Handle Commands in VSPackages (C#)
Nota
Beginning with Visual Studio 2008 SDK, use XML Command Table (.vsct) files instead of command table configuration (.ctc) files to define how menus and commands appear in your VSPackages. For more information, see XML-Based Command Table Configuration (.vsct) Files.
Commands must be added to the shell using the Command Table Architecture format. See How VSPackages Add User Interface Elements for information about the Command Table Architecture file. For the user to execute a VSPackage's commands, the commands that a VSPackage makes available to the shell need to be visible and enabled. When commands are created in the .ctc file, they are visible and enabled by default. Setting some creation flags can change this default behavior, for example, VSPackage developers may choose to hide or show, enable or disable, or even change the labels of commands as the VSPackage code executes. Finally, if the user executes a command, the VSPackage handles it.
The procedures outlined here further discuss command creation and handling from both unmanaged code and managed code that uses the managed package framework (MPF) classes. The procedures covered are:
Creating a command.
Handling the new command.
Implementing the QueryStatus(Guid%, UInt32, [], IntPtr) method.
Implementing the Exec method.
The following walkthroughs show how to implement commands in both managed (Visual C#) and unmanaged (Visual C++) code.
Creating a command
To add a command to the command table
Define a GUID:ID pair to represent the new command (for example, GUIDCmd:CmdID). The ctc.exe compiler expects a GUID data type with this format:
#define guidCmd { 0xBC8DA515, 0x5743, 0x4FEB, { 0xA9, 0x29, 0x29, 0x38, 0x24, 0x9C, 0xBA, 0x26 } }
The pair definition continues with a colon and finally a number. The GUID:ID pair must be unique; it cannot be used by any other command.
Select a priority for the new command. The priority of the new command determines its position relative to all other commands within the menu or command group. A low priority value places the command closer to the top of the menu while a higher priority value places the command towards the end. For example, a priority of 0xFFFF places the command at or near the end of the group.
Create a new line in the BUTTONS_BEGIN – BUTTONS_END section of the Command Table Configuration (.Ctc) Files.
Set the Command ID field to the GUID:ID of the new command (for this example use GUIDCmd:CmdID).
Set the Group ID field to either the GUID:ID pair of the command's primary parent group of the command button or a placeholder.
A placeholder is used when a command does not use a primary parent group, but is assigned to groups only through entries in the CMDPLACEMENT_SECTION – CMDPLACEMENT_END section.
In this case, by convention, the placeholder is the command's own GUID:ID pair, GUIDCmd:CmdID.
Set the Priority field to the desired priority.
Set the Icon ID field to the GUID:ID of an image in a bitmap resource.
Nota
If the command has no bitmap associated with it, use the GUID:ID pair guidOfficeIcon:msotcidNoIcon, defined in vsshlids.h.
Set the Button Type field to BUTTON.
Set the Flags field as appropriate.
For more information on defining a command, see BUTTONS_BEGIN – BUTTONS_END.
Add the command to a menu by assigning groups that contain the command to the appropriate menu.
Once the command has been created, the QueryStatus and Exec methods of the VSPackage must be updated to handle the new command.
Handling the new command
For code that uses the IOleCommandTarget interface directly for command handling, it is necessary to implement the IOleCommandTarget interface and its methods. The two most important methods are the QueryStatus and Exec methods.
For managed code that uses the MPF, the IOleCommandTarget is hidden behind the idea of event handlers. See "To handle the new command using MPF" procedure.
To handle the new command within the VSPackage
The VSPackage must implement both the QueryStatus and Exec methods of the IOleCommandTarget interface.
If the VSPackage implements a project hierarchy, the QueryStatusCommand and ExecCommand methods of the IVsUIHierarchy interface should be implemented instead.
- Note Both the QueryStatus and Exec methods are designed to receive a single command set GUID and an array of command IDs as input. It is preferred that a VSPackage fully support this concept of multiple IDs in one call. However, as long as the VSPackage is not called from other VSPackages, it is safe to assume that the command array only contains a single command ID. Since the QueryStatus and Exec methods are executed in a well-defined order, this is a safe assumption. See Command Routing in VSPackages for an explanation of routing issues.
To handle the new command using MPF
Create a CommandID object with the GUID:ID pair of the command to handle.
Instantiate an OleMenuCommand object that specifies the method that handles the command along with the CommandID.
This new menu object is then passed to the AddCommand method in the IMenuCommandService interface.
Implement the method that handles the command.
Implementing the QueryStatus method
For code that uses the IOleCommandTarget interface directly for command handling, the VSPackage's implementation of the QueryStatus(Guid%, UInt32, [], IntPtr) method must do the following to handle commands (commands whose GUID:ID pair matches the GUID:ID pair used in the BUTTONS_BEGIN – BUTTONS_END section of the command table.
A different approach is required for managed code that uses the MPF classes. See "To implement QueryStatus in the MPF" procedure.
To implement the QueryStatus method
Return S_OK for valid commands.
Set the cmdf element of the prgCmds parameter.
The value of the cmdf element is the logical union of values from the OLECMDF enumeration, combined with the logical OR (|) operator.
Select the enumerations used based on the status of the command:
If the command is supported:
prgCmds[0].cmdf = OLECMDF_SUPPORTED;
If the command should be invisible at the moment:
prgCmds[0].cmdf |= OLECMDF_INVISIBLE;
If the command is toggled on and appears to have been clicked:
prgCmds[0].cmdf |= OLECMDF_LATCHED;
In the case of processing commands hosted on a menu of type MENUCONTROLLERLATCHED, the first command marked with the OLECMDF_LATCHED flag is the default command displayed by the menu on start up. For details, see the discussion of MENUCONTROLLER menu types under MENUS_BEGIN – MENUS_END.
If the command is currently enabled:
prgCmds[0].cmdf |= OLECMDF_ENABLED;
If the command is part of a context menu and is hidden by default:
prgCmds[0] cmdf |= OLECMDF_DEFHIDEONCTXMENU
If the command uses the TEXTCHANGES flag, set the rgwz element of the pCmdText parameter to the new text of the command and set the cwActual element of the pCmdText parameter to the size of the command string.
For error conditions, the QueryStatus method must handle the following error cases:
If the GUID is unknown or not supported, return OLECMDERR_E_UNKNOWNGROUP.
If the GUID is known but the command ID is unknown or not supported, return OLECMDERR_E_NOTSUPPORTED.
To implement QueryStatus using the MPF classes
Add a new EventHandler object to the BeforeQueryStatus event in the OleMenuCommand object created to handle the command. The EventHandler object is given the name of a method which is called when the menu command's status is queried.
Implement the query status handler method for the command. The object sender parameter can be cast to an OleMenuCommand object which is used to set the various attributes of the menu command, including the text. The following table shows the properties on the MenuCommand class (which the MPF class OleMenuCommand derives from) that correspond to the OLECMDF flags.
MenuCommand Property
OLECMDF flag
Checked = true
Visible = false
Enabled = true
To change the text of a menu command, use the Text property on the OleMenuCommand object.
The MPF automatically handles the case of unsupported or unknown groups; unless a command has been added to the OleMenuCommandService using the AddCommand method, the command is not supported.
Implementing the Exec method
For code that uses the IOleCommandTarget interface directly for command handling, the VSPackage's implementation of the Exec method must return specific error codes, depending on whether the command is supported and whether the command was handled successfully.
For managed code that uses the MPF, the event handler passed to the OleMenuCommand constructor is called whenever the command is selected. The MPF automatically handles the case of unsupported or unknown groups, so the following procedure does not apply.
To implement the Exec method
If the command GUID is unknown, return OLECMDERR_E_UNKNOWNGROUP.
If the GUID is known but the command ID is unknown, return OLECMDERR_E_NOTSUPPORTED.
If the GUID and command ID match the GUID:ID pair used in the BUTTONS_BEGIN – BUTTONS_END section of the command table, execute the code associated with the command and return S_OK.