Command Implementation
To implement a command in a VSPackage, you must perform the following tasks:
In the .vsct file, set up a command group and then add the command to it. For more information, see Visual Studio Command Table (.Vsct) Files'
Register the command with Visual Studio.
Implement the command.
The following sections explain how to register and implement commands.
Registering Commands with Visual Studio
If your command is to appear on a menu, you must add the ProvideMenuResourceAttribute to your VSPackage, and use as a value either the name of the menu or its resource ID.
[ProvideMenuResource("Menus.ctmenu", 1)]
...
public sealed class MyPackage : Package
{.. ..}
In addition, you must register the command with the OleMenuCommandService. You can get this service by using the GetService method if your VSPackage is derived from Package.
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
// Create the command for the menu item.
CommandID menuCommandID = new CommandID(guidCommandGroup, myCommandID);
MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
mcs.AddCommand( menuItem );
}
Implementing Commands
There are a number of ways to implement commands. If you want a static menu command, which is a command that always appears the same way and on the same menu, create the command by using MenuCommand as shown in the examples in the previous section. To create a static command, you must provide an event handler that is responsible for executing the command. Because the command is always enabled and visible, you do not have to provide its status to Visual Studio. If you want to change the status of a command depending on certain conditions, you can create the command as an instance of the OleMenuCommand class and, in its constructor, provide an event handler to execute the command and a query-status handler to notify Visual Studio when the status of the command changes. You can also implement IOleCommandTarget as part of a command class or, you can implement IVsHierarchy if you are providing a command as part of a project. The two interfaces and the OleMenuCommand class all have methods that notify Visual Studio of a change in the status of a command, and other methods that provide the execution of the command.
When a command is added to the command service, it becomes one of a chain of commands. When you implement the status notification and execution methods for the command, take care to provide only for that particular command and to pass all other cases on to the other commands in the chain. If you fail to pass the command on (usually by returning OLECMDERR_E_NOTSUPPORTED), Visual Studio may stop working properly.
Query Status Methods
If you are implementing either the QueryStatus method or the QueryStatusCommand method, check for the GUID of the command set to which the command belongs and the ID of the command. Follow these guidelines:
If the GUID is not recognized, your implementation of either method must return OLECMDERR_E_UNKNOWNGROUP.
If your implementation of either method recognizes the GUID but has not actually implemented the command, then the method should return OLECMDERR_E_NOTSUPPORTED.
If your implementation of either method recognizes both the GUID and the command, then the method should set the command-flags field of every command (in the prgCmds parameter) by using the following flags:
OLECMDF_SUPPORTED if the command is supported.
OLECMDF_INVISIBLE if the command should not be visible.
OLECMDF_LATCHED if the command is toggled on and appears to have been checked.
OLECMDF_ENABLED if the command is enabled.
OLECMDF_DEFHIDEONCTXTMENU if the command should be hidden if it appears on a shortcut menu.
OLECMDF_NINCHED if the command is a menu controller and is not enabled, but its drop-down menu list is not empty and is still available. (This flag is rarely used.)
If the command was defined in the .vsct file with the TextChanges flag, set the following parameters:
Set the rgwz element of the pCmdText parameter to the new text of the command.
Set the cwActual element of the pCmdText parameter to the size of the command string.
Also make sure that the current context is not an automation function, unless your command is specifically intended to handle macros or other automation functions.
To indicate that you support a particular command, return S_OK. For all other commands, return OLECMDERR_E_NOTSUPPORTED.
In the following example, the query-status method first makes sure that the context is not an automation function, then finds the correct command-set GUID and command ID. The command itself is set to be enabled and supported. No other commands are supported.
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider))
{
if (pguidCmdGroup == VSConstants.VSStd2K && cCmds > 0)
{
// make the Right command visible
if ((uint)prgCmds[0].cmdID == (uint)VSConstants.VSStd2KCmdID.RIGHT)
{
prgCmds[0].cmdf = (int)Microsoft.VisualStudio.OLE.Interop.Constants.MSOCMDF_ENABLED | (int)Microsoft.VisualStudio.OLE.Interop.Constants.MSOCMDF_SUPPORTED;
return VSConstants.S_OK;
}
}
return Constants.OLECMDERR_E_NOTSUPPORTED;
}
}
Execution Methods
Implementation of the execute method resembles implementation of the query-status method. First, make sure that the context is not an automation function. Then test for both the GUID and the command ID. If the GUID or command ID is not recognized, return OLECMDERR_E_NOTSUPPORTED.
To handle the command, execute it and return S_OK if the execution succeeds. Your command is responsible for error detection and notification; therefore, return an error code if the execution fails. The following example demonstrates how the execution method should be implemented.
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider))
{
if (pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
{
if (nCmdID ==(uint) uint)VSConstants.VSStd2KCmdID.RIGHT)
{
//execute the command
return VSConstants.S_OK;
}
}
}
return Constants.OLECMDERR_E_NOTSUPPORTED;
}