| Author: |
Carlos J. Quintero (Microsoft MVP) |
Applies to: |
Microsoft Visual Studio 2005 |
| Date: |
April 2010 |
|
Microsoft Visual Studio 2008 |
| Updated: |
March 2013 |
|
Microsoft Visual Studio 2010 |
| |
|
|
Microsoft Visual Studio 2012 |
Introduction
This article discusses a problem that happens when an add-in tries to add a
button to the toolbar of a toolwindow of Visual Studio, such
as to the Solution Explorer toolbar (not to confuse with its context menu).
More Information
Some Visual Studio toolwindows have a toolbar (apart from a context menu for
their contents). Until Visual Studio 2005 it was not possible for an add-in to
get access to the toolbar of a toolwindow to add buttons to it, but the new
EnvDTE80.dll assembly introduced in Visual Studio 2005 provided a new
EnvDTE80.Window2 class (that represents a toolwindow) with a new CommandBars
property that didn't exist in the EnvDTE.Window class. Since with this property
it is possible to get the CommandBar that represents the toolbar, in theory it
would be possible to add CommandBarControls (CommandBarButtons or
CommandBarPopups) to it, as described in the article
HOWTO: Adding buttons, commandbars and toolbars
to Visual Studio .NET from an add-in.
In practice it is not possible due to these exceptions that happen on each
Visual Studio version when adding or removing the button:
- Visual Studio 2005: the button is added correctly, but you get
"System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT_FAIL
has been returned from a call to a COM Component." when removing the control
calling CommandBarControl.Delete(). Trying to removing the button deleting its
associated command (the technique described in the article
HOWTO: Prevent dead CommandBarButtons when
Visual Studio or an add-in crashes) doesn't work either.
- Visual Studio 2008: "System.UnauthorizedAccessException: Access denied.
(Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" when calling
Command.AddControl(...) to add the button.
- Visual Studio 2010 and higher: "System.UnauthorizedAccessException: Controls cannot be
added to a Toolwindow toolbar." when calling Command.AddControl(...) to add the
button.
So, while the Visual Studio 2005 version could have a bug, it is clear in next
versions that add-ins are not allowed to add buttons to the toolbars of
toolwindows.
The following add-in provides the code to reproduce the problem:
| Language: VB.NET | Copy Code (IE only) |
Imports System
Imports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80
Public Class Connect
Implements IDTExtensibility2
Implements IDTCommandTarget
Private Const _COMMAND_NAME As String = "MyCommand"
Private _DTE2 As DTE2
Private _addIn As AddIn
Private _commandBarControl As CommandBarControl
Private _command As Command = Nothing
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, _
ByVal addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection
Dim window2 As Window2
Dim commandBars As CommandBars
Dim commandBar As CommandBar
Try
_DTE2 = CType(application, DTE2)
_addIn = CType(addInInst, AddIn)
Select Case connectMode
Case ext_ConnectMode.ext_cm_AfterStartup, ext_ConnectMode.ext_cm_Startup
Try
_command = _DTE2.Commands.Item(_addIn.ProgID & "." & _COMMAND_NAME)
Catch
End Try
If _command Is Nothing Then
_command = _DTE2.Commands.AddNamedCommand(_addIn, _COMMAND_NAME, "My command", _
"My command", True, 59)
End If
window2 = DirectCast(_DTE2.Windows.Item(EnvDTE.Constants.vsWindowKindSolutionExplorer), Window2)
commandBars = DirectCast(window2.CommandBars, CommandBars)
commandBar = commandBars.Item("Explorer")
_commandBarControl = DirectCast(_command.AddControl(commandBar), CommandBarControl)
_commandBarControl.Visible = True
End Select
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.ToString)
End Try
End Sub
Public Sub OnDisconnection(ByVal disconnectMode As ext_DisconnectMode, ByRef custom As Array) _
Implements IDTExtensibility2.OnDisconnection
Try
If Not (_commandBarControl Is Nothing) Then
_commandBarControl.Delete()
End If
If Not (_command Is Nothing) Then
_command.Delete()
End If
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.ToString)
End Try
End Sub
Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate
End Sub
Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete
End Sub
Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown
End Sub
Private Sub QueryStatus(ByVal CmdName As String, ByVal NeededText As vsCommandStatusTextWanted, _
ByRef StatusOption As vsCommandStatus, ByRef CommandText As Object) Implements IDTCommandTarget.QueryStatus
If NeededText = vsCommandStatusTextWanted.vsCommandStatusTextWantedNone Then
If CmdName = _addIn.ProgID & "." & _COMMAND_NAME Then
StatusOption = vsCommandStatus.vsCommandStatusSupported Or vsCommandStatus.vsCommandStatusEnabled
End If
End If
End Sub
Private Sub Exec(ByVal CmdName As String, ByVal ExecuteOption As vsCommandExecOption, ByRef VariantIn As Object, _
ByRef VariantOut As Object, ByRef Handled As Boolean) Implements IDTCommandTarget.Exec
If CmdName = _addIn.ProgID & "." & _COMMAND_NAME Then
System.Windows.Forms.MessageBox.Show(CmdName & " clicked.")
End If
End Sub
End Class
| Language: C# | Copy Code (IE only) |
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
namespace MyAddin
{
public class Connect : IDTExtensibility2, IDTCommandTarget
{
const string _COMMAND_NAME = "MyCommand";
private DTE2 _DTE2;
private AddIn _addIn;
private CommandBarControl _commandBarControl;
private Command _command;
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
Window2 window2;
CommandBars commandBars;
CommandBar commandBar;
object[] contextUIGuids = new object[] { };
try
{
_DTE2 = (DTE2)application;
_addIn = (AddIn)addInInst;
switch (connectMode)
{
case ext_ConnectMode.ext_cm_AfterStartup:
case ext_ConnectMode.ext_cm_Startup:
{
try
{
_command = _DTE2.Commands.Item(_addIn.ProgID + "." + _COMMAND_NAME, -1);
}
catch
{
}
if (_command == null)
{
_command = _DTE2.Commands.AddNamedCommand(_addIn, _COMMAND_NAME, "My command",
"My command", true, 59, ref contextUIGuids,
(int)(vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled));
}
window2 = (Window2)_DTE2.Windows.Item(EnvDTE.Constants.vsWindowKindSolutionExplorer);
commandBars = (CommandBars)window2.CommandBars;
commandBar = commandBars["Explorer"];
_commandBarControl = (CommandBarControl)_command.AddControl(commandBar, 1);
_commandBarControl.Visible = true;
}
break;
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
try
{
if (_commandBarControl != null)
{
_commandBarControl.Delete(true);
}
if (_command != null)
{
_command.Delete();
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
public void OnAddInsUpdate(ref Array custom)
{
}
public void OnStartupComplete(ref Array custom)
{
}
public void OnBeginShutdown(ref Array custom)
{
}
public void QueryStatus(string CmdName, vsCommandStatusTextWanted NeededText,
ref vsCommandStatus StatusOption, ref object CommandText)
{
if (NeededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
{
if (CmdName == _addIn.ProgID + "." + _COMMAND_NAME)
{
StatusOption = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
}
}
}
public void Exec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn,
ref object VariantOut, ref bool Handled)
{
if (CmdName == _addIn.ProgID + "." + _COMMAND_NAME)
{
System.Windows.Forms.MessageBox.Show(CmdName + " clicked.");
}
}
}
}
Go back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this
|