2004-08-30
| Rate This Article: | Add This Article To: |
A Visual Studio tool window is a window that can be dragged around the screen or attached to an edge. When they're attached to an edge, tool windows either can be pinned open, or automatically slide closed when you move the mouse out. Examples include the Ctrl+Alt+L Solution Explorer and the Ctrl+Alt+X Toolbox.
Visual Studio can host ActiveX controls in a tool window. Hosted tool windows use the same DTE (Development Tools Environment) API as macros, so they can enumerate and manipulate open windows, including edit buffers. Tool windows also can add controls to forms, which is something that macros cannot do.
You can't write an ActiveX control in .NET directly. However, Microsoft offers a ActiveX shim that loads a UserControl into a tool window, so you can write Visual Studio .NET extension code in C#.
This first article covers the basics of hosting your C# code within a tool window; the next article will discuss the more advanced topic of dragging controls from your tool window onto a form designer.
I should, perhaps, point out that you should budget plenty of time for any add-in project. The test cycle is slow and repetitive; the DTE API is nowhere near as well-designed or as well-documented as the FCL; and you will spend a fair amount of time trying to figure out how get DTE to do what you want it to, without raising exceptions. For more information, I recommend Johnson, Skibo, and Young's Inside Microsoft Visual Studio .NET.
Note: These articles apply to VS 2003 and 2002. You'll have to do some tweaking to get things to work in VS 2005, at least in Beta 1.
Your very first step is to download the Microsoft ActiveX shim. (If this link doesn't work, Google for VSUserControlHost.)Install the source by running the self-extracting archive ToolWindow.exe, or use your favorite zip utility. Load the project into VS and build it. Once you have the shim built, you follow the same four steps to build each new add-in:
Step 1. Use the New Project wizard to create a new add-in project. From the Shift+Ctrl+N New Project dialog, open the Other Projects folder, and select the Extensibility Projects sub-folder. Select Visual Studio .NET Add-in and give the new project a name and location. The Add-in Wizard has six pages. On the first page, you choose a language; the default is C#. On the second page, you choose an application host: deselect the VSMacros IDE option. (I'm not really sure what difference this makes. The wizard generates the same source for dual-hosted projects as for VS-only projects; presumably the installer is somewhat different.) On the third page, you provide a name and description for your add-in; these will be displayed in the Tools / Add-in Manager dialog.
On the fourth page, you choose add-in options. I recommend that you leave the Tools menu option unchecked; checking this option creates a menu command that loads the add-in, which is not the same thing as reopening a closed window (which is an operation that belongs on the View window). Leave the "modal UI" option unchecked if you ever use MessageBox or ShowDialog. Be sure to leave the "load when the host application starts" option unchecked. While you may eventually want to have the add-in always load, you can't recompile an add-in once it has been loaded into the current VS process, even if it's subsequently been unloaded.
The fifth page of the wizard allows you to add text and an icon to the VS About box; the sixth page summarizes your choices. When you click the Finish button, the wizard creates your new project. When that's done, right click on the new project in the Solution Explorer and add a reference. Select the COM tab, and select the VSUserControlHost 1.0 Type Library.
Step 2. Edit the Connect.cs file to create your tool window and optionally add a menu command. The basic plumbing is the same for every add-in, and really differs only in a few names; some ambitious person could write a wizard that would automatically generate all the boilerplate to host a UserControl in a tool window. Short of that, you can just copy and paste from the SimpleAddin project that accompanies this article.
Add three using clauses to the start of the file: System.Windows.Forms, System.Windows.Forms.Design, and VSUserControlHostLib.
The wizard will create two private fields, _DTE applicationObject and AddIn addInInstance. I rename applicationObject to DTE, and add EnvDTE.Window ToolWindow and Command ViewCommand.
Leave the constructor empty; the real work happens in the OnConnection method. The wizard-generated code just saves the _DTE interface and the DTE.AddIn parameters to fields of the Connect object: You'll need these to create a tool window and to interact with Visual Studio.
You create a tool window with code like this:
object obj = null;
ToolWindow = DTE.Windows.CreateToolWindow(
addInInstance,
"VSUserControlHost.VSUserControlHostCtl",
ToolWindowCaption,
Guid.NewGuid().ToString("B"),
ref obj );
The ToolWindowCaption will be displayed in the UI, so keep it short. The Guid parameter doesn't matter. You can use Guid.NewGuid() to generate a new GUID every time the add-in is loaded, or you can simply hardwire an arbitrary GUID—but it must be in the "B" format: "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}". The ref obj returns the DocObj associated with the tool window; I don't use it in any of the sample code.
Get the shim control:
IVSUserControlHostCtl shimControl = (IVSUserControlHostCtl) ToolWindow.Object;
and tell it to host your user control:
shimControl.HostUserControl( System.Reflection.Assembly.GetExecutingAssembly().CodeBase, "SimpleAddin.AddInControl" );
The first parameter is the assembly that contains your user control. This code assumes that the user control is in the same assembly as the Connect class. The second parameter is the user control's namespace and class name. HostUserControl creates your user control, and returns a reference to it as a System.Object. In most cases, you'll want to capture this reference in the Connect class:
AddInControl Addin = (AddInControl) shimControl.HostUserControl().
Note that you must use a UserControl, not a Form. Using a Form will hang VS, so this is not a mistake you're likely to make twice.
Set
ToolWindow.Visible = true;
and you're all set.
Adding a View menu command that will bring back your tool window after you close it is always useful—but this article is already too long. The sample code (which you can download
Step 3. Build the setup project, and install your add-in. The wizard creates a setup project for you. Right click on it in the Solution Explorer, and select Build; right click again and select Install.
I'm afraid I don't know any better way to change the name and description you entered in the New Project wizard than to edit the installer's .vdproj file outside of the IDE.
Step 4. Build your add-ins UI iteratively.
An add-in is a class library. The New Project wizard set the add-in's Start Application to Visual Studio, so F5 will start a second copy of Visual Studio, running within Visual Studio. You can set breakpoints in Connect.cs or within your user control, and they will work perfectly normally.
Load your user control by bringing up the Tools / Add-in Manager dialog. Check the box next to the add-in name (this article's add-in is named "Simple") and click the OK button. The add-in will appear in a new tool window. Visual Studio will select a random size and location, and the window may or may not be docked. You can reliably persist and restore the size and location; as far as I can tell, while you can detect that your tool window is docked at shutdown (in the Connect. OnDisconnection method), you can not dock your tool window programmatically.
Jon Shemitz is an independent developer and author in Santa Cruz, California.
![]() |
|


