There are two parts to this story. The first part is deals with how to interact with the Visual Studio development environment programmatically, in order to add a tab to the toolbox and place components on it. That can be accomplished within the confines of a simple Console application. However, in a real-world scenario, you’d want to install your custom components by means of a Setup project with an MSI file, which first installs the components into the Global Assembly Cache (GAC). That’s what the second part of the story is all about: creating a setup and deployment project that first installs the components into the GAC and then uses a custom action with an installer class to create the toolbox tab and place the components onto the tab.
Toolbox Story Part 1
There are two approaches you can take to install components into the Visual Studio 2005 toolbox. The more sophisticated approach, which gives you the most control, is to install the Visual Studio SDK and create a custom package to interact with the Toolbox service. This is what most professional component vendors opt for, but it requires you to obtain a license key from Microsoft, which is free but does involve an extra step. The second approach, and the one I use here, is to control the Visual Studio environment via automation by adding a reference to EnvDTE (Development Tools Environment).
For this approach to work, you have to implement what is known in the world of programmers as a “kludge†(that’s Yiddish for “hackâ€). In order to add a tab with components that are meant for windows forms projects, you actually need to create a dummy project. I obtained some code from Microsoft Tech Support that includes the workaround and also cleans up the project list that appears on the VS start page. Here’s the primary code snippet:
dte.ExecuteCommand( “View.PropertiesWindow”, string.Empty);
EnvDTE. Window window =
dte.Windows.Item(EnvDTE.Constants.vsWindowKindToolbox);
EnvDTE. ToolBox toolbox = (EnvDTE.ToolBox)window.Object;
EnvDTE. ToolBoxTab myTab = toolbox.ToolBoxTabs.Add(tabName);
myTab.Activate();
myTab.ToolBoxItems.Add( “doesn’t matter”, location,
vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
There are two ways to install components. For private assemblies, you supply the name of the DLL and all the components in that assembly are placed in the toolbox tab. For shared assemblies installed in the GAC, you supply the class name of the individual component as part of the assembly strong name, and just that component is placed on the toolbox tab. I use a project settings file (see my last post for an explanation of app settings in VS 2005) to contain the strong name of each component. Here you can download the code for a console application which installs shared components into the VS toolbox. (Open the ToolboxConsole.sln solution file.) Notice that you can see another instance of Visual Studio pop up and message boxes which show the tab and component names. This is strictly for debugging purposes, so you can more easily see what’s going on. (Just uncheck the DEBUG constant in the project properties page.) You can run the console app from a command line with a “-u†switch to uninstall the components from the toolbox.
Toolbox Story Part 2
Most of the time you won’t want to run a console app to have developers install your shared components into a tab on the Visual Studio toolbox. The ideal situation would be for them to run an installation program which first installs the components into the GAC and then places them on the toolbox tab. Accomplishing this feat requires you to master creating installer classes and custom actions for setup projects.
First you’ll need to create a Class Library project with your component. Be sure to sign the assembly with a strong name file, which you can accomplish from the Signing tab of the project properties page. Then you’ll add to the solution a Setup project. In the File System properties page, add the special Global Assembly Cache folder and the primary output from your class library.
Next add another class library to your solution. Right click the project, then select Add Existing Item, and select “Installer Classâ€. This will add an installer class your project. In the class, type public override, then select “Commit†to create an override of the base class Commit method. Do the same for the Uninstall method. Then in the File System editor of the setup project, add the installer class project output to the Application Folder. The code snippet has the Commit override call a static method of the class installed in the GAC. This shows that the installation into the GAC occurred before the Commit method is called.
public override void Commit(System.Collections.IDictionary savedState)
{
base.Commit(savedState);
MyClass.ShowMessage
(“Calling GAC Assembly in the Committed Event”);
}
After that, open the Custom Actions Editor and add the primary output to the Install, Commit and Uninstall nodes. You need it in both Install and Commit to avoid an exception while initializing the install state. Click here to download a simple VS project that installs a component into the GAC and invokes a method to prove it was installed properly.
To tie it all together, I created a project which contains the ToolboxConfigure project, installs the shared components into the GAC and then into the VS toolbox. Open the ToolboxSetup.sln solution file in the project in the first download link in this post. The end result is an MSI file which allows developers to install your custom shared components into the Visual Studio toolbox. If you open a Windows app project the components should appear when you show the design surface of a windows form or component. It took me a couple days to learn both parts of the story and work out the kinks. Sometimes the component tab would fail to appear, because I would stop debugging before cleanup could occur. But logging off would destroy any instances running in the background and the component installation would then work as expected, Feel free to email me (link) with any questions, or just post them here in a blog comment. Enjoy!
Thank you very much