Logo
PRB: COMException 0x80020003 getting events from commandbar popup in Visual Studio 2010

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio 2010
Date: February 2011    
       
Introduction

This article discusses a problem that happens when an add-in for Visual Studio 2010 tries to get events from a commandbar popup. This problem did not happen in Visual Studio 2008.

More Information

The automation model (EnvDTE) of Visual Studio provides the DTE.Events.CommandBarEvents(CommandBarControl) to get the Click event of a CommandBarControl, which can be a CommandBarButton or a CommandBarPopup. This approach is not recommended for the following reasons:

  • For a CommandBarButton, the recommended way is to create it from an EnvDTE.Command and to use the Exec method of the IDTCommandTarget interface to know when the button is clicked. See HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in. The CommandBarEvents approach was used in the old Microsoft Visual Basic 5.0 / 6.0 environment, which lacked commands and the IDTCommandTarget interface.
  • For a CommandBarPopup, when it is clicked Visual Studio automatically shows the menu items. But some people use the Click event to set the state of the children menu items (CommandBarControls). Again, this is not the recommended approach. The proper way is to use the QueryStatus method of the IDTCommandTarget interface. This method is called by Visual Studio just before showing the menu items. Apart from the previous article, see also HOWTO: Controlling the state of command in a Visual Studio add-in.

In Visual Studio 2008 you could use the CommandBarEvents approach to get the Click event from a CommandBarPopup (although only for CommandBarPopups added by an add-in, not for CommandBarPopups provided by Visual Studio). In Visual Studio 2010 you get a COMException 0x80020003 "Member not found" when calling DTE.Events.CommandBarEvents with a CommandBarPopup added by an add-in.

In both Visual Studio versions the CommandBarEvents approach works with CommandBarButtons (although not recommended).

The following add-in provides the code to reproduce the problem:

Language: VB.NET   Copy Code Copy Code (IE only)
Imports SystemImports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80
Imports System.Windows.Forms

Public Class Connect
   Implements IDTExtensibility2

   Private _dte As EnvDTE.DTE
   Private WithEvents _builtInToolsCommandBarEvents As CommandBarEvents
   Private WithEvents _myToolsCommandBarEvents1 As CommandBarEvents
   Private WithEvents _myToolsCommandBarEvents2 As CommandBarEvents
   Private _myToolsCommandBarControl1 As CommandBarControl = Nothing
   Private _myToolsCommandBarControl2 As CommandBarControl = Nothing


   Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, _
      ByVal addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection

      _dte = CType(application, DTE)

      Select Case connectMode

         Case ext_ConnectMode.ext_cm_Startup
            ' OnStartupComplete will be called

         Case ext_ConnectMode.ext_cm_AfterStartup
            InitializeAddIn()

      End Select

   End Sub

   Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete

      InitializeAddIn()

   End Sub

   Private Sub InitializeAddIn()

      Dim commandBars As CommandBars
      Dim menuCommandBar As CommandBar
      Dim standardCommandBar As CommandBar
      Dim commandBarControl As CommandBarControl
      Dim commandBarPopup As CommandBarPopup
      Dim builtInToolsCommandBarControl As CommandBarControl = Nothing

      commandBars = DirectCast(_dte.CommandBars, CommandBars)

      menuCommandBar = commandBars.Item("MenuBar")
      standardCommandBar = commandBars.Item("Standard")

      ' Add a commandbar popup on the main menu bar
      _myToolsCommandBarControl1 = DirectCast(menuCommandBar.Controls.Add(MsoControlType.msoControlPopup), CommandBarControl)
      _myToolsCommandBarControl1.Caption = "My tools 1"
      _myToolsCommandBarControl1.Enabled = True

      ' Add a button without a command on the Standard toolbar. 
      ' Note: this is NOT the recommended approach. The proper way is to create buttons from commands. See:
      ' HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in.
      ' http://www.mztools.com/articles/2005/MZ2005003.aspx
      _myToolsCommandBarControl2 = DirectCast(standardCommandBar.Controls.Add(MsoControlType.msoControlButton), CommandBarControl)
      _myToolsCommandBarControl2.Caption = "My tools 2"
      DirectCast(_myToolsCommandBarControl2, CommandBarButton).Style = MsoButtonStyle.msoButtonCaption

      ' Locate the built-in "Tools" commandbar popup
      For Each commandBarControl In menuCommandBar.Controls

         If TypeOf commandBarControl Is CommandBarPopup Then

            commandBarPopup = DirectCast(commandBarControl, CommandBarPopup)

            If commandBarPopup.CommandBar.Name = "Tools" Then

               builtInToolsCommandBarControl = commandBarControl
               Exit For

            End If

         End If

      Next

      ' Add event handlers to the add-in commandbar popup, to the add-in button and to the built-in commandbar popup

      ' Note: this works in Visual Studio 2008 but no longer in VS 2010. You get a COMException 0x80020003 "Member not found"
      Try
         _myToolsCommandBarEvents1 = DirectCast(_dte.Events.CommandBarEvents(_myToolsCommandBarControl1), CommandBarEvents)
      Catch ex As Exception
         MessageBox.Show(ex.ToString)
      End Try

      ' This works in VS 2008 and VS 2010, and the Click event is raised
      Try
         _myToolsCommandBarEvents2 = DirectCast(_dte.Events.CommandBarEvents(_myToolsCommandBarControl2), CommandBarEvents)
      Catch ex As Exception
         MessageBox.Show(ex.ToString)
      End Try

      ' Note: while this statement doesn't fail, the Click event for built-in commandbar popups is not raised
      Try
         _builtInToolsCommandBarEvents = DirectCast(_dte.Events.CommandBarEvents(builtInToolsCommandBarControl), CommandBarEvents)
      Catch ex As Exception
         MessageBox.Show(ex.ToString)
      End Try

   End Sub

   Private Sub _builtInToolsCommandBarEvents_Click(ByVal CommandBarControl As Object, ByRef Handled As Boolean, _
      ByRef CancelDefault As Boolean) Handles _builtInToolsCommandBarEvents.Click

      ' Note: this event won't be raised by Visual Studio for built-in commandbar popups
      MessageBox.Show("Built-in Tools commandbarpopup clicked")

   End Sub

   Private Sub _myToolsCommandBarEvents1_Click(ByVal CommandBarControl As Object, ByRef Handled As Boolean, _
      ByRef CancelDefault As Boolean) Handles _myToolsCommandBarEvents1.Click

      MessageBox.Show("MyTools1 commandbar popup clicked")

   End Sub

   Private Sub _myToolsCommandBarEvents2_Click(ByVal CommandBarControl As Object, ByRef Handled As Boolean, _
      ByRef CancelDefault As Boolean) Handles _myToolsCommandBarEvents2.Click

      MessageBox.Show("MyTools2 clicked")

   End Sub

   Public Sub OnDisconnection(ByVal disconnectMode As ext_DisconnectMode, ByRef custom As Array) _
      Implements IDTExtensibility2.OnDisconnection

      If Not _myToolsCommandBarControl1 Is Nothing Then
         _myToolsCommandBarControl1.Delete()
      End If

      If Not _myToolsCommandBarControl2 Is Nothing Then
         _myToolsCommandBarControl2.Delete()
      End If

      _myToolsCommandBarEvents1 = Nothing
      _myToolsCommandBarEvents2 = Nothing
      _builtInToolsCommandBarEvents = Nothing

   End Sub

   Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate
   End Sub

   Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown
   End Sub

End Class

Related articles



Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)


Top