Paul Kimmel on VB/VB .NET : Creating Visual Studio .NET Add-Ins
Creating Visual Studio .Net Add-Ins
Microsoft has taken excellent strides in making it more convenient for third party developers to customize and extend Visual Studio .Net. Developers and extenders can write Macros to automate repetitive tasks, create Wizards to serialize complex tasks, create Class Library Add-Ins that plug into Visual Studio .Net, or participate in the VSIP (Visual Studio Integration Program), for a fee and get access to Visual Studio for Applications and other resources. The VSIP program is to support, in part, integrators that may be implementing languages for Visual Studio .Net.
In this article I will demonstrate just one kind of customization, the Add-In. Add-Ins are class library projects that implement the Extensibility2 interface. There are about a half-dozen interface methods that you have to implement to make the class library work correctly with Visual Studio .Net. Fortunately there is a wizard that makes it easy to get started. Following that line of thinking that is where we will start. We'll create an Add-In using the Visual Studio .Net Add-In wizard.
Using the Add-In Wizard
Add-Ins are applications that extend or customize Visual Studio .Net in some way. Add-Ins do not have to be complex to be useful; if the concept is useful to you and saves you sufficient enough effort in the future to warrant development then I encourage you to create the Add-In. (Keep in mind you can always create a macro first and convert the macro code into an Add-In later.)
We will briefly review the Add-In wizard steps because most of you are probably familiar with how to use wizards. Add-Ins are class libraries. You don't have to use the wizard to create an Add-In. If you create a class library and implement IDTExtensibility2 and IDTCommandTarget for convenience and register the Add-In with regasm.exe then you can achieve the same result. The wizard is just easier. In fact, the preceding two sentences adequately summarize what the wizard does for us.
To create an Add-In using the wizard:
- Select File|New|Project|Other Projects|Extensibility Projects|Visual Studio.Net Add-In. Provide a name for your Add-In and click OK to start the wizard.
- The wizard has a welcome screen and six steps before it generates code. Click Next on the welcome screen.
- Select Visual Basic on the page 1 of 6 screen, and click Next.
- On page 2 of 6 use the default host applications: VSMacros IDE and Visual Studio.Net. Click Next.
- On page 3 of 6 enter a name for your add-in and a brief description. Click Next.
- Step asks among other things if you would like to create to interact with your Add-In. Check this box. This will add the IDTCommandTarget interface to your class library, allowing you to run your Add-In from VS.NETs Tools menu and directly invoke it through the Command Window. Also check that you want the Add-In to load when the hostVS.NET and VSMacrosload, and check that the Add-In should be available to all users. Click Next.
- On Page 5 of 6 fill out the Help About information if you want your information available in a help box. Click Next.
- Step 6 of 6 allows you to review selections. Click Finish when you are satisfied with your selections.
The end result will be a Class Library project with your Add-In as the assembly name and the root namespace. The class will be named Connect. The output from the wizard follows.
Listing 1: Output from the Visual Studio .Net Add-In wizard.
1: Imports Microsoft.Office.Core2: Imports EnvDTE3: imports System.Runtime.InteropServices4: 5: [ Read me for Add-in installation and setup information. ]6: 7: <GuidAttribute("921DE547-32FA-40BB-961A-EA390B7AE27D"), _8: ProgIdAttribute("MyAddin.Connect")> _9: Public Class Connect10: 11: Implements IDTExtensibility212: Implements IDTCommandTarget13: 14: Dim applicationObject As EnvDTE.DTE15: Dim addInInstance As EnvDTE.AddIn16: 17: Public Sub OnBeginShutdown(ByRef custom() As Object) _18: Implements IDTExtensibility2.OnBeginShutdown19: End Sub20: 21: Public Sub OnAddInsUpdate(ByRef custom() As Object) _22: Implements IDTExtensibility2.OnAddInsUpdate23: End Sub24: 25: Public Sub OnStartupComplete(ByRef custom() As Object) _26: Implements IDTExtensibility2.OnStartupComplete27: End Sub28: 29: Public Sub OnDisconnection( _30: ByVal RemoveMode As ext_DisconnectMode, ByRef custom() As Object) _31: Implements IDTExtensibility2.OnDisconnection32: End Sub33: 34: Public Sub OnConnection(ByVal application As Object, _35: ByVal connectMode As ext_ConnectMode, _36: ByVal addInInst As Object, _37: ByRef custom() As Object) _38: Implements IDTExtensibility2.OnConnection39: 40: applicationObject = CType(application, EnvDTE.DTE)41: addInInstance = CType(addInInst, EnvDTE.AddIn)42: If connectMode = ext_ConnectMode.ext_cm_UISetup Then43: Dim objAddIn As AddIn = CType(addInInst, AddIn)44: Dim CommandObj As Command45: 46: 'IMPORTANT!47: 'If your command no longer appears on the 48: ' appropriate command bar, you add a new or 49: ' modify an existing command, or if you would like 50: ' to re-create the command, close all 51: ' instances of Visual Studio .NET and double 52: ' click the file 'ReCreateCommands.reg' in the folder 53: ' holding the source code to your Add-in.54: 'IMPORTANT!55: Try56: CommandObj = applicationObject.Commands.AddNamedCommand( _57: objAddIn, "MyAddin", "MyAddin", _58: "Executes the command for MyAddin", _59: True, 59, Nothing, 1 + 2)60: '1+2 == vsCommandStatusSupported+vsCommandStatusEnabled61: 62: CommandObj.AddControl( _63: applicationObject.CommandBars.Item("Tools"))64: Catch e As System.Exception65: End Try66: End If67: End Sub68: 69: Public Sub Exec(ByVal cmdName As String, _70: ByVal executeOption As vsCommandExecOption, _71: ByRef varIn As Object, ByRef varOut As Object, _72: ByRef handled As Boolean) Implements IDTCommandTarget.Exec73: handled = False74: If (executeOption = _75: vsCommandExecOption.vsCommandExecOptionDoDefault) Then76: If cmdName = "MyAddin.Connect.MyAddin" Then77: handled = True78: Exit Sub79: End If80: End If81: End Sub82: 83: Public Sub QueryStatus(ByVal cmdName As String, _84: ByVal neededText As vsCommandStatusTextWanted, _85: ByRef statusOption As vsCommandStatus, _86: ByRef commandText As Object) _87: Implements IDTCommandTarget.QueryStatus88: 89: If neededText = _90: EnvDTE.vsCommandStatusTextWanted.vsCommandStatusTextWantedNone Then91: If cmdName = "MyAddin.Connect.MyAddin" Then92: statusOption = _93: CType(vsCommandStatus.vsCommandStatusEnabled + _94: vsCommandStatus.vsCommandStatusSupported, vsCommandStatus)95: Else96: statusOption = vsCommandStatus.vsCommandStatusUnsupported97: End If98: End If99: End Sub100: End Class
From the listing we can determine that the class name is Connect and that Connect implements IDTCommandTarget and IDTExtensibility2 (lines 11 and 12). IDTExtensibility requires an implementation for OnBeginShutdown, OnAddInsUpdate, OnStartupComplete, OnDisconnection, OnConnection, and IDTCommandTarget requires that we implement Exec and QueryStatus. A required implementation includes simply an empty procedure.
OnBeginShutdown is called when the IDE shutting down. OnAddInsUpdate is called when the list of Add-ins changes. OnStartupComplete occurs when the IDE has finished loading. OnDisconnection occurs when an Add-In is unloaded from the host, and OnConnection occurs when an Add-In is loaded into a host. Exec is called when a user invokes the Add-In behavior and QueryStatus is called when the user drops down the Tools menu or when Intellisense is displaying available Add-ins from the Command Window or somewhere else.