Kemp Brown
Microsoft Corporation
January 1999
Summary: Discusses extensibility in Microsoft® Visual Studio® version 6.0. (11 printed pages) Describes how to create tools, such as add-ins and wizards, to customize your development environment.
Extensibility is the capacity to extend, or stretch, the functionality of the Microsoft Visual Studio integrated development environment (IDE). The IDE provides you with a programming interface known as the Extensibility object model, a set of powerful interfaces for customizing the environment. It allows you to hook into the IDE to create extensions known as add-ins.
There are two types of extensibility: built-in and user-designed.
The Extensibility object model consists of four related groups of individual code objects that control major facets of the common IDE. Each functional group enables you to create tools to customize the development environment and help you accomplish your programming tasks more quickly and easily. These groups are:
Each group consists of one or more collections and objects that contribute to a particular purpose. For example, the primary function of the events object group is to provide access to events occurring in the IDE. One object in this group is the CommandBarEvents object, which allows you to respond to events occurring on menus and toolbars. Another is the BuildEvents object, which exposes events occurring at the beginning and end of solution builds.
You can create add-ins two different ways: with the aid of a wizard or manually.
The best and easiest way to create an add-in (if you're using a common shell language such as Microsoft Visual J++™) is to use a tool called the Add-In Wizard.
To run the Add-In Wizard
The Add-In Wizard creates a basic add-in framework that you can run immediately after you finish. The wizard lets you supply a display name for the add-in (which appears in the Add-In Manager dialog box) and a description of the add-in. You can optionally choose to have the wizard generate the code to add a command to the Tools menu for invoking the add-in once it is loaded into the IDE. When the wizard is done, you will have a new project with a single item.
Note If you are using the Visual J++ development system for the Java language, and you don't install it in the default location, you must modify the add-in's project settings to correct the pathname for the alternate launch program, devenv.exe. If you launch devenv.exe as the alternate launch program for your add-in project, the second instance runs in debug mode. This allows you to step through your add-in code in the first IDE instance and watch the effects of the add-in in the second IDE instance.
Although it's highly recommended that you use the Add-In Wizard to create your add-ins, you can also create an add-in from scratch.
To manually create an add-in in Visual J++
import com.ms.vstudio6.dte.*;
import com.ms.vstudio6.msaddndr.*;
import com.ms.office97.*;
Public Class MyAddin implements IDTExtensibility2
When you implement the IDTExtensibility2 interface in your code and register the resulting DLL after building the code, the IDE can create an add-in server and call its exposed methods.
Method name | Description |
OnConnection | Called when an add-in is connected |
OnDisconnection | Called when an add-in is disconnected |
OnAddInsUpdate | Called when the Addins collection is updated |
OnStartupComplete | Called when the system has completed starting |
OnBeginShutdown | Called when the system is being shut down |
Using the Object Browser, you can view the following type libraries to examine objects in the Extensibility object model.
Type library name | File name | Description |
Visual Studio 6.0 Extensibility | dte.olb | The DTE add-in object model |
Microsoft Add-In Designer | msaddndr.olb | The IDTExtensibility interface |
Microsoft Office 8.0 Object Library | office97.olb | Command bars |
VJExt | vjext.olb | Visual J++ project and code models |
void
procedures for the previously mentioned interface methods. For example, create this procedure:
public void OnConnection(Object VSInst, int ConnectMode, Object
AddInInst, SafeArray custom){
}
When you select the add-in, code is added to your add-in to identify its class ID, globally unique identifier (GUID), and type library ID. The compiler's preprocessor uses this information in conjunction with a method called @com.register to register your add-in. A registration string looks like this:
/**
* @com.register (clsid=710B1AE4-9E3A-1101-883A-B07C0CC10000,
typelib=710B1AE3-9E3A-1101-883A-B07C0CC10000)
*/
Note These numbers are unique to each add-in.
/**
* @com.register (clsid=710B1AE4-9E3A-1101-883A-B07C0CC10000,
typelib=710B1AE3-9E3A-1101-883A-B07C0CC10000, progid="MyAddin.Connect")
*/
Here's how it looks when it's all put together:
import com.ms.vstudio6.dte.*;
import com.ms.vstudio6.msaddndr.*;
import com.ms.office97.*;
/**
* @com.register (clsid=710B1AE4-9E3A-1101-883A-B07C0CC10000,
typelib=710B1AE3-9E3A-1101-883A-B07C0CC10000, progid="MyAddin.Connect")
*/
public class MyAddin implements _IDTExtensibility2 {
public void OnConnection(Object VSInst, int ConnectMode, Object AddInInst, SafeArray custom) {
}
public void OnDisconnection(int RemoveMode, SafeArray custom) {
}
public void OnAddInsUpdate(SafeArray custom) {
}
public void OnStartupComplete(SafeArray custom) {
}
public void OnBeginShutdown(SafeArray custom) {
}
}
Note that this code serves only as a basic framework for common shell add-ins. From this point, you would add code to place the add-in as a command in a menu or command bar, create unique functionality for the add-in, and so forth.
Add-ins, whether created manually or with the Add-In Wizard, must be registered with Microsoft Windows®, just as any other ActiveX server. Once registered, the IDE recognizes your add-in and lists it in the Add-In Manager. If you are using Microsoft Visual Basic®, the Add-In Designer prompts you for this information and automatically performs all required add-in registration tasks. If you manually create the add-in in Visual J++, however, you must add a public method named OnCOMRegister to reveal the add-in to the Add-In Manager. (This is done for you if you use the Add-In Wizard.) For example, this code is required:
public static void onCOMRegister (boolean reg) {
if (reg == true) { //Register
try {
RegKey regKey
= new RegKey(RegKey.getRootKey(RegKey.USER_ROOT),
"Software\\Microsoft\\VisualStudio\\6.0\\Addins\\
MyAddin.Connect ", RegKey.KEYOPEN_CREATE);
regKey.setValue("Description", "Addin description goes
here.");
regKey.setValue("FriendlyName", "Friendly Add-In Name");
regKey.setValue("LoadBehavior", 0);
regKey.close();
}
catch (RegKeyException rke) {
}
}
else { //Unregister
try {
RegKey regKey
= new RegKey(RegKey.USER_ROOT,
"Software\\Microsoft\\VisualStudio\\6.0\\Addins",
RegKey.KEYOPEN_WRITE);
regKey.deleteSubKey("MyAddin.Connect");
regKey.close();
}
catch (RegKeyException rke) {
}
}
}
Alternatively, you can manually create your own .reg file. A typical .reg file for an add-in might look like this:
REGEDIT4
[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\6.0\Addins\
ProjectName.Classname
"Description"="A description of the add-in."
"FriendlyName"="My new addin"
"LoadBehavior"=dword:00000000
For information about creating add-ins in Visual Basic, see "Using Add-In Designer" in the Visual Basic documentation. Also see the sample add-in written in Java in the Visual J++ Samples directory.
Wizards are a type of add-in that leads a user through a sequence of actions, generates projects and project items, and then goes away. They implement the IDTWizard interface, which has only a single method, Execute.
Although they can be constructed any way you like, Microsoft implements its wizards in a specific manner. A Microsoft wizard consists of a number of frames. Each frame contains an image in the upper-left corner, a label description to the right of the image that may also contain instructions, and an optional area near the bottom in which other controls can be placed, as in the following example.
The process of creating a wizard is very similar to creating a regular add-in.
import com.ms.office97.*
import com.ms.vstudio6.msaddndr.*
import com.ms.vstudio6.dte.*
Public Class MyAddin implements IDTWizard
When you create a wizard, you gain access to the Wizard Extensibility model using an interface called IDTWizard. When you implement the IDTWizard interface in your code and create a .vsz file in one of the appropriate directories, the IDE can create a wizard and call the Execute method.
public void Execute(int RemoveMode, SafeArray custom)
{
}
When you select the wizard, code is added to your add-in to identify its class ID, globally unique identifier (GUID), and type library ID. The compiler's preprocessor uses this information in conjunction with a method called @com.register to register your wizard. The registration string looks like this:
/**
* @com.register (clsid=710B1AE4-9E3A-1101-883A-B07C0CC10000,
typelib=710B1AE3-9E3A-1101-883A-B07C0CC10000)
*/
Note These numbers are unique to each wizard. Also, you don't need to register your wizard with the IDE with the onCOMRegister procedure as you do with ordinary add-ins.
/**
* @com.register (clsid=710B1AE4-9E3A-1101-883A-B07C0CC10000,
typelib=710B1AE3-9E3A-1101-883A-B07C0CC10000, progid="MyWizard.Connect")
*/
Here's how it looks when it's all put together:
import com.ms.office97.*
import com.ms.vstudio6.msaddndr.*
import com.ms.vstudio6.dte.*
/**
* @com.register (clsid=710B1AE4-9E3A-1101-883A-B07C0CC10000,
typelib=710B1AE3-9E3A-1101-883A-B07C0CC10000,
progid="MyWizard.Connect")
*/
public class MyAddin implements _IDTWizard {
public void Execute(Object VSInst, int ConnectMode, Object
AddInInst, SafeArray custom) {
}
}
VSWizard 6.0
Wizard=VIDWizard.CblankSiteWizard OR GUID
Param=test1
Param=test2
The wizard then appears in the Add Item and Add Project dialog boxes as a new item that can be added to a solution. You can also refer to the .vsz file in a .vsdir file to control how and where it displays in the Add Item and Add Project dialog boxes.
You can place files in the projects and items directories and use them in a Visual Studio solution. To customize which items are displayed in the Add Project and Add Item dialog boxes, as well as the order in which they are displayed, you can use .vsdir files. (Note, however, that .vsdir files are not part of the Automation model.)
The IDE looks for files with a .vsdir extension in the directories that contain new items and projects. .Vsdir files provide a sort order for items displayed in the Add Project and Add Item dialog boxes. There can be multiple .vsdir files at each level in the directories that contain new projects and items. The IDE reads all of them at a given level and builds an overall order for displaying items. Items not listed in .vsdir files appear after all items listed in a .vsdir file. For more information about how to construct .vsdir files, see the section "Creating .Vsdir Files" later in this article.
While regular add-ins cannot be used in the projects and items directories, you can, however, place wizards in these directories and have them activate if they have an associated .vsz file. For information about creating .vsz files, see the next section.
The IDE also provides a Template Wizard that can be used to prompt users for information and merge that information with template sources to produce new project items. Users can add a new template to the Add Item dialog box by creating a new .vsz file that refers to the Template Wizard and the sources for the template. For more information on this, see "Creating Custom Templates" in the Visual Studio documentation.
A .vsz file represents items that appear in the Add Item and New Project dialog boxes as new items and projects that can be added to your solution. The .vsz file contains information that identifies a wizard and provides custom information for it. The custom information allows you to invoke the same wizard with different data from different .vsz files. This allows a single wizard to perform seemingly different functions.
The following shows the format of a typical .vsz file:
VSVersion=6.0
ClassName=MyProgID.Info
Param=c:\users\fizzle.java
Param="another custom parameter"
Part | Meaning |
VSVersion | Identifies the wizard interface the wizard will be expected to implement. |
Classname | The ProgID of the wizard. |
Param | Custom parameters that get passed to the wizard upon execution. You can have any number of custom parameters.
Each parameter is contained on a separate line. The quotes shown in the preceding example are optional. |
You can optionally create a .vsdir file for your wizard, or modify an existing file to contain information about the wizard. A .vsdir file is a text file that is used to provide information to the Add Item and New Project dialog boxes. The .vsdir file provides information about the items these dialog boxes display, such as the sort order and the icon to display for each item.
You can have multiple .vsdir files in a single directory; however, one .vsdir file is generally used to contain information for multiple wizards, folders, or templates. An example of a typical .vsdir file is shown here:
Form.java|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#36201|10|#36202|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#253|0|Form
Control.java|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#36203|20|#36204|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#258|0|Control
DATAFORM.VSZ|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#36220|40|#36221|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#262|0|DataForm
Form|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#36056|10
Class|{AECC23E0-8AA3-11d0-B606-00A0C922E851}|#36054|20
.Vsdir files contain a single record per file or folder template, with fields separated by a pipe (|) character. Any nonrequired field for which there is no meaningful data should contain a zero (0) as a placeholder. The following fields can be specified for a given record.
Field | Meaning |
RelPathName | Name of the .vsz file for the wizard. |
{clsidPackage} | Optional GUID representing a product (for example, Visual J++) that has a DLL containing localized resources. |
LocalizedName | Optional name of the wizard as it will appear in the Add Item dialog box—can be a string or a resource identifier of the form "#ResID." |
SortPriority | An integer representing the relative priority of the wizard, with 1 being highest. Determines the sort order of items. |
Description | Localizable description of the template or wizard as it will appear in the Add Item dialog box—can be a string or a resource identifier of the form "#ResID." |
DLLPath or {clsidPackage} | Used to load an icon for the wizard from a .dll or .exe file. Specify either the full path to the .dll or .exe, or a GUID of a product that has a .dll file containing localized resources. |
IconResourceId | Optional resource identifier within the .dll file that determines the icon to display. If no icon is defined, the shell substitutes the default icon for a file with the same extension as the item. |
Flags | A group of flags that disable or enable the Name and Location fields on the Add Item dialog box. The flags can have the following values:
Space (" "): enable file name 8192: disable file name |
SuggestedBaseName | The default name for the wizard—either a string or a resource identifier of the form "#ResID." If necessary, the shell appends the base value with an integer to make the name unique. For example, the shell might change MyFile.asp to MyFile1.asp.
This default name is shown in the Name field in the dialog box. |
There are many ways you can use add-ins and wizards to enhance, extend, and automate the IDE:
These are just a few ideas. Add-ins give you the freedom to create custom programming solutions to save you time and help you become more productive. Just think of the possibilities!