Extensibility in Visual Studio is a bit like science and technology-there is always more to learn and discover even for the experts.

In this article, I’ll present a few tips and tricks you may find helpful when creating packages with the Visual Studio SDK.

Hi, I’m Dr. eX, your Visual Studio Extensibility expert! This article presents tips and tricks for enhancing your development with the Visual Studio SDK. I’ll present some new scenarios and productivity techniques for creating packages. Let’s jump right in to some of my notes from my technical laboratory.

Top 10 Help Topics for the Microsoft Visual Studio 2008 SDK

For starters, let me show you how to find ten of the most popular VSX Help topics. I’ll list the topics first and then I’ll show you how to find them.

  1. "Getting Started with the Visual Studio SDK" (Visual Studio SDK > Getting Started)
  2. "Visual Studio Integration Guided Tour" (Visual Studio SDK > Getting Started > Guided Tour)
  3. "Visual Studio Integration Samples" (Visual Studio SDK > Visual Studio Development Environment SDK > Samples)
  4. "Introduction to the Visual Studio Development Environment SDK" (Visual Studio SDK > Visual Studio Development Environment SDK > Getting Started > Introduction)
  5. "Visual Studio Development Environment Model" (Visual Studio SDK > Visual Studio Development Environment SDK > Architecture > Concepts > Visual Studio Development Environment Model)
  6. "Migrating VSPackages to Visual Studio 2008" (Visual Studio SDK > Visual Studio Development Environment SDK > Getting Started > Migrating VSPackages to Visual Studio 2008)
  7. "Running Visual Studio and the Visual Studio SDK Under Windows Vista" (Visual Studio SDK > Visual Studio Development Environment SDK > Getting Started > Running Under Windows Vista)
  8. "User Interface Essentials" (Visual Studio SDK > Visual Studio Development Environment SDK > User Interfaces > Essentials)
  9. "Project Type Essentials" (Visual Studio SDK > Visual Studio Development Environment SDK > Projects and Solutions > Projects > Project Types > Essentials)
  10. "Visual Studio 2008 Shell" (Visual Studio SDK > Visual Studio Development Environment SDK > Visual Studio 2008 Shell)

To access the above Help topics, do one of the following:

  • With the Visual Studio 2008 SDK installed, on the Start menu, point to All Programs, click Microsoft Visual Studio 2008 SDK, and click Microsoft Visual Studio 2008 SDK Documentation. In the Contents pane, expand the folders listed in the order above, and then click the topic.
  • From a Web browser, go to http://msdn2.microsoft.com, and click the Library tab at the top of the page. In the Contents pane, expand MSDN Library, expand Development Tools and Languages, expand Visual Studio 2008, and then expand Visual Studio. Now as you refer to the topics in the list above, expand the folders for the topic that interests you and then click the topic.

Tips and Tricks for the Microsoft Visual Studio SDK

Online/Offline Help

To switch between the offline (in the product) and online (on the MSDN Web site) versions of the Visual Studio SDK documentation, do the following:

  1. With Microsoft Document Explorer open, on the Tools menu, click Options. Expand Help, and click Online.
  2. In the When loading Help content area, do one of the following: a. Click the Try online first, then local option to view the online version of the documentation. b. Click the Try local only, not online to view the offline version of the documentation.
  3. Quit and restart Document Explorer for the changes to take effect.

Finding Keywords in Code Examples

To interact with an index of the code files included in the Visual Studio SDK, do one of the following:

  1. In the Licenses list, select MSVSSDK.
  2. In the Search box, type a keyword to search for, such as IVsPackage, and then click Search.
  3. A list of code files containing that keyword will appear.
  1. In the Project box, type Visual Studio SDK.
  2. In the Search box, type a keyword to search for, such as IVsPackage, and click Search.
  3. A list of code files containing that keyword will appear.

VS SDK Documentation Feedback

To provide feedback to Microsoft about the Visual Studio SDK documentation, do one of the following:

  1. Send an e-mail to vssdkfbk@microsoft.com with the feedback included.
  2. From the online version of the documentation, with any Help topic displayed, click Community Content, and follow the on-screen directions to submit your feedback to Microsoft.
  3. From the offline version of the documentation, with any Help topic displayed, click the feedback link at the bottom of the topic, and follow the on-screen directions to submit your feedback to Microsoft.

Using IVsProfferCommands to Retrieve a Visual Studio CommandBar

If you are an add-in developer, you are probably familiar with adding menu items and toolbar buttons to the Visual Studio environment. In most instances, add-in developers take their cue from the code generated by the Visual Studio Add-in Project Wizard.

For example, Listing 1 shows the code generated when you create a new C# add-in project and select the “Create Command Bar UI” check box in the add-in project wizard.

When you run the code in Listing 1 a new command (“My Command”) is added to the Tools menu. Note how this particular sample retrieves the CommandBar for the “Tools” menu by way of the Controls collection on the CommandBar representing the main IDE menu named “MenuBar”.

This is the preferred technique for retrieving a CommandBar representing a menu on the main IDE menu, because in theory there could be other CommandBar objects named “Tools” in the DTE.CommandBars collection.

A Problem

The code in Listing 1 does not account for when the user manually removes the “Tools” menu. Nor does it take into consideration that some add-in or Visual Studio Package may have added an identically named toolbar or menu to the environment.

Consider the Visual Studio macro in Listing 2.

When run, the macro displays a sorted list of CommandBar names contained in the DTE.CommandBars collection. Note that many of the names listed are duplicated.

Given that CommandBars can have identical names; that users may change the Visual Studio IDE’s menu layout; and third parties can add additional menus with identical names to the IDE, it becomes very difficult to retrieve a specific CommandBar from the DTE.CommandBars collection.

The Solution

If you are a Visual Studio package developer, you are probably familiar with using .CTC files to add new menus, toolbars, and commands to the Visual Studio IDE. For the uninitiated or curious, please refer to the documentation and samples included with the Visual Studio SDK. To briefly summarize, each command, menu, and toolbar added via a .CTC file is uniquely identified by a GUID:ID pair. This GUID:ID pair can be used with the IVsProfferCommands.FindCommandBar method to retrieve a specific CommandBar object.

Finding the GUID:ID pair for a particular menu or command can be a hit or miss affair. You could search the various .IDL, .CTC, and .H files included with the Visual Studio SDK, or post a message in the MSDN Extensibility Forum and hope for a response. But with Visual Studio SP1, you can now use the undocumented but extremely useful EnableVSIPLogging registry value to help find the GUID:ID pair that indentifies the specific menu or command you are interested in. You can learn more about the EnableVSIPLogging registry value in the Dr. eX blog post entitled, “Using EnableVSIPLogging to identify menus and commands with VS 2005 + SP1.”

The IVsProfferCommands interface is defined in the EnvDTE namespace, but is marked for “Microsoft Internal Use Only”. However, given the need for a solution to the problem defined above, and after consulting with the Visual Studio development team, Dr. eX and the Visual Studio IDE development team feel comfortable recommending this as a viable solution for both add-in and package developers.

You can retrieve the IVsProfferCommands interface by calling QueryService on the DTE object’s IOleServiceProvider interface. Note that IOleServiceProvider is the OLE/COM equivalent of the .NET IServiceProvider. However, these two interfaces are different, and you need to use the OLE/COM version of this interface to successfully retrieve the IVsProfferCommands service. This interface is defined in the Microsoft.VisualStudio.OLE.Interop.dll assembly that ships with the Visual Studio SDK. But you can readily define this interface yourself, without having to download the Visual Studio SDK.

For example:

[
  ComImport,
  Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
  InterfaceTypeAttribute(ComInterfaceType.
                         InterfaceIsIUnknown)
]
internal interface IOleServiceProvider
{
   [PreserveSig]
   int QueryService([In]ref Guid guidService,
      [In]ref Guid riid,
      [MarshalAs(UnmanagedType.Interface)] out
      System.Object obj);
}

Then it is just a matter of calling QueryService to retrieve the IVsProfferCommands interface, and then invoking IVsProfferCommands.FindCommandBar to retrieve the CommandBar you are interested in (Listing 3).

Debugging Package Load Failures

You can just picture the situation. You’ve coded up your package and tested it out on your development machine. You’ve even managed to get a setup project together. Everything is working just as expected, but when you run your setup on another machine, you get a dialog box saying “Package Load Failure.”

Never fear, Dr. eX is here to cure what ails you! There are several possible causes for a package load failure.

Invalid/Missing Package Load Key

Perhaps the number one cause of failure when deploying a new package is an invalid or missing package load key (PLK). In order to deploy your package on an end-user’s machine, you’ll need to embed a package load key as a string resource.

How to Diagnose a Package Load Key Issue

To find out if your package is failing to load because of a problem with the PLK, you can use the /log switch included in Visual Studio 2005. If there is a failure because of a PLK problem, you will see something like the following in the VS activity log (located at {USERPROFILE}\{AppData}\Microsoft\VisualStudio\{Hive}\ActivityLog.xml):

Warning
 CheckPackageSignature failed;
 invalid Package Load Key
 {YOUR PACKAGE GUID HERE}
  Microsoft Visual Studio Appid Stub
 2006/12/11 17:49:25.950

You should note that even if you do have a valid PLK, you may still see this warning once or more in the log because Visual Studio attempts to check if your PLK is valid for different versions of Visual Studio. For example, even if you applied for a PLK to load in Visual Studio 2005, at runtime Visual Studio will check if you have a valid key for Visual Studio 2002, 2003, or 2005. Since the key isn’t a valid 2002 key (even though it is valid for 2005), a warning is logged. This check is done to ensure that packages created for earlier versions of Visual Studio continue to load in later versions.

A PLK is a signed hash of the following registration information taken from your package registration key at HKLM\Software\Microsoft\VisualStudio\8.0\Packages\{YOURGUID}:

  • CompanyName (This is entered when first creating your login on the VSIPMembers.com site. You can find the exact string on the list of Products registered there.)
  • ProductName (This is entered when first creating the product information, not when requesting the PLK.)
  • ProductVersion
  • MinEdition (Standard, Professional, etc...)
  • Your Package Guid
  • The "appid" that your PLK is for (i.e., the version of Visual Studio)

Because the PLK is a signed hash of this information, if you need to change any of these details about the package, you must obtain a new Package Load Key from the VSIP members Web site. If for some reason you don’t get the e-mail with the PLK from the Web site, you can resubmit for a new PLK, you can try asking on the VSX forum, or contact Microsoft Product Support.

To find out more details about how package load keys work and how to properly embed a PLK in your package DLL, check http://msdn2.microsoft.com/en-us/library/bb165795(VS.80).aspx.

How to Remedy a PLK Issue

In the above MSDN topic you’ll find a link to another excellent article that contains more detailed information at http://msdn2.microsoft.com/en-us/library/bb164677(VS.80).aspx.

Exception in Constructor/SetSite/Initialize Methods

If you’ve determined that the PLK check is succeeding (or you aren’t to the deployment stage yet), but your package is not loading, it is possible that your package is throwing an exception in its constructor or SetSite/Initialize method. At package load time, an object of your package type is instantiated and the constructor is executed. Then, in order to site the package to the hosting instance of Visual Studio, the SetSite method is called. If you are deriving from the Package class in the Managed Package Framework (which most packages written in C# do), you will not see a SetSite implementation in your code. Rather, the MPF implementation of SetSite will call the Initialize method, which you can override.

How to Diagnose an Exception in the Constructor or SetSite Method

The simplest way to determine this problem is by setting breakpoints in the constructor and SetSite and/or Initialize method and stepping through your execution path with the debugger. If any exceptions are thrown (or error codes returned), Visual Studio will fail to continue the package loading process.

How to Remedy an Exception in the Constructor or SetSite Method

Remedying an exception is, of course, a case-by-case task. You will need to determine the proper fix for your package to prevent the exception from being thrown to Visual Studio if it is a recoverable, non-fatal error situation.

Dependency Load Failure

Even though your package DLL may be loading just fine, that doesn’t mean that all the dependencies in your package are loading! For example, if your package references a binary on your development machine that is not properly redistributed on an end user’s machine, you may get a package load failure.

How to Diagnose a Dependency Load Failure

For managed packages, the simplest way to diagnose such a problem is via the Assembly Binding Log Viewer tool (fuslogvw.exe) included with the .NET Framework SDK. The MSIL Dissassembler (ildasm.exe) may also be helpful in determining the exact assemblies that your package depends on.

For native packages, things are a bit trickier, but not hopeless. Dr. eX recommends using the profiling feature in the Dependency Walker tool (depends.exe) on devenv.exe (Visual Studio’s executable). This will give you detailed information about where Visual Studio is loading binaries from. If Visual Studio can’t find your package binary, it will be logged during the profiling. Filemon may also be helpful as it allows you to see real-time file system activity. Dumpbin.exe (using the /DEPENDENTS switch) may also provide some clues.

How to Remedy a Dependency Load Failure

In most cases, the problem is caused by not properly redistributing a binary on which your package relies. The remedy is to obtain permissions and needed resources from the author of the dependent binaries and include these in your package’s setup. In the case that you can’t obtain such permissions (for legal or technical reasons), your only solution may be to remove the dependency.

For managed assemblies, you will need to ensure that your dependencies are located in the Global Assembly Cache (GAC) or the probing path for Visual Studio. The probing path is determined by the devenv.exe.config file and includes the PublicAssemblies and PrivateAssemblies folders. The Assembly Binding Log Viewer (mentioned above) will log the details of the probing algorithm so you can see where Visual Studio attempted to load the assembly from.

Registration Problem (Assembly/Codebase/InProcServer32)

There are a few different ways to register your package such that Visual Studio knows where to load it from. If you’re package is managed, your key in the registry under Packages will have either a value for Assembly (containing the complete strong name of the assembly) or Codebase (containing a file path to your assembly) as well as an InProcServer32 value pointing to mscoree.dll (the .NET runtime). If you’re package is native, the InProcServer32 value should point to the location of your DLL on disk.

How to Diagnose a Registration Problem

In order to diagnose a registration problem you will need to compare the registration values to where files are actually located on disk. For a managed package, the Assembly Binding Log Viewer (fuslogvw.exe) tool mentioned earlier will also be helpful as it will contain information on where Visual Studio attempted to load your package from.

How to Remedy a Registration Problem

Because this is caused by improper registration, you will need to adjust your setup program to register appropriately. See the MSDN Help topic on deploying VSPackages at http://msdn2.microsoft.com/en-us/library/bb165366(VS.80).aspx.

ProjectAggregator2 Not Installed

When you install the Visual Studio 2005 SDK on your machine, a component called ProjectAggregator2 is also installed silently. This component is used for packages that implement a project system in managed code. If you are writing a managed project system (or project subtype), you will need to redistribute ProjectAggregator2.msi as a part of your setup program.

How to Diagnose ProjectAggregator2 Not Installed

During the package setup, ProjectAggregator2.msi should be installed before the package itself is installed. On an end-user’s machine, you can look in the Add/Remove Programs in Windows and see if there is a listing for "Microsoft Visual Studio ProjectAggregator2". Note that you will not see this listed in Add/Remove Programs on a machine with the Visual Studio SDK installed.

How to Remedy ProjectAggregator2 Not Installed

You will need to install ProjectAggregator2.msi before your package is installed as part of your setup program. This MSI package can be installed silently by calling msiexec.exe. Also note that since Windows Installer is a transaction-based technology, you will need to have a "wrapper" setup program to invoke msiexec and install ProjectAggregator2.msi. Due to the design of Windows Installer, you cannot invoke a MSI installation from another MSI.

Take Two DLLs and Call Me in the Morning...

If you’ve diagnosed a package that fails to load, hopefully one of the above remedies will get your package back on its feet. Remember that, as with most problems, an ounce of prevention is worth a pound of cure. The doctor recommends the following tips to avoid PackageLoadFailureitis:

  • Apply for a package load key (and use it in testing) as early as you can in the development cycle. This will prevent last minute scrambles to apply for, wait for, embed, and test the package load key just before you ship your package.
  • Know what binaries you depend on and ensure you have legal permissions to ship them.
  • Use reliable installer technologies for managing registration and installation of your package. The Visual Studio 2005 SDK includes several samples that demonstrate the use of one such technology, Windows Installer (via WiX).
  • Follow other Visual Studio package deployment guidance as prescribed in the documentation.

As a final note, a couple of my colleagues and I in the research lab are working on a tool which will do much of the diagnosis of package load failures mentioned in this article automatically for you! We’re tentatively calling it the “Package Load Analyzer” and it should be coming to a release of the Visual Studio SDK soon. It will be a deployable tool that you can use not only in development, but also for debugging purposes on test and end-user systems to help you make your package more reliable and robust.

Visual Studio Extensibility Demystified

Since we (the VSX team) have placed the VS 2005 SDK 3.0 on the Microsoft Download Center, many developers have downloaded the SDK. The developers who are using the SDK now are no longer just developers who build commercial VSIP products. Users of the SDK now include students and developer enthusiasts who are building Visual Studio extensions to make their work more productive or just for fun and curiosity.

To that end, I’d like to spend a little bit of time explaining the various levels of Visual Studio extensibility to help developers who are new to the Visual Studio platform get ramped up.

Within the Visual Studio environment itself, there are three levels of extensibility: macros, add-ins and VSPackages.

Macros

Macros are the easiest way for developers to quickly gain access to Visual Studio’s underlying automation object model. If you hit Alt+F11 in Visual Studio, the Macros IDE will appear and here you can start writing your macro. Macros are sometimes called the "duct tape" of Visual Studio because of their versatility and flexibility. You can easily combine Visual Studio commands or set automation properties to create interesting behaviors. Listing 4, for example, illustrates a very simple macro that toggles the word wrap text editor option.

If you are interested in learning more about how to create, record, and use macros, I suggest that you go to http://msdn2.microsoft.com/en-us/library/b4c73967(VS.80).aspx for some resources.

So when should you use macros as the VS extensibility model? The scenarios that are great for using macros are those where you are trying script Visual Studio to automate certain tasks, provided that you can accept several limitations:

  • You can only write macros in Visual Basic.
  • To share macros with others, you must give them your macro projects which will include source code. Since the user of the macros can see the source code, there is no protection of your intellectual property.
  • Some extensibility scenarios cannot be achieved via macros. For example, you cannot create a new tool window, a new editor or a new project system via macros.

Scripting the IDE is powerful and often useful in many scenarios. But if you want to do more than duct-taping, you will need to develop Add-ins or VSPackages.

Add-ins

Similar to macros, add-ins also leverage on the automation object model of Visual Studio. But unlike macros, add-ins are compiled into binary code so your intellectual property can be protected. Perhaps more importantly, add-ins allow you to seamlessly integrate new tool windows, plug in options pages, dynamically enable commands, and add branding onto the splash screen and Help About boxes-scenarios that macros do not enable. Features offered by add-ins can fit seamlessly into the IDE as if they were a part of Visual Studio. In implementation, you also have the choice of creating add-ins in C#, Visual Basic or C++.

You can find many great add-ins in the community today. Visual Studio Hacks has a list of interesting add-ins at http://www.visualstudiohacks.com/type/addins.

James Avery has written a great MSDN article about the ten must-have tools at http://msdn.microsoft.com/msdnmag/issues/04/07/MustHaveTools/default.aspx (some of which are add-ins) for Visual Studio. A couple of student interns from the C# team have created some interesting add-ins that enhance code navigation and editing.

As you can see, you can use add-ins to build tools and features that support a large number of scenarios. The automation object model is extremely powerful. To get a sense of what this automation object model looks like, you can refer to the automation object model chart at http://msdn2.microsoft.com/en-gb/library/za2b25t3(VS.80).aspx.

If you are interested in learning more about how to create add-ins, a good place to get started is http://msdn2.microsoft.com/en-us/library/5abkeks7(VS.80).aspx.

VSPackages

VSPackages are the most powerful way to extend Visual Studio. Using VSPackages (a.k.a. VSIP interfaces), you gain access to the same API that internal teams at Microsoft have to integrate anything you want inside Visual Studio. This deep level of integration allows developers to build everything that add-ins enable, plus more. With VSPackages, you can even build custom project systems, debuggers, editors, data designer extensions, and language integrations. IronPython is a great example of a language integration project built with VSPackages, and you can find this sample integration in the Visual Studio SDK.

By the way, the Visual Studio SDK is a great way to start learning about how to use this powerful mechanism to deeply integrate with Visual Studio. You can view the online documentation at http://msdn.com/vsx. It is easy to get started with VSPackages once you have the SDK installed because it provides wizards to help you create your first command, tool window or editor via VSPackages. In Visual Studio 2005, the Managed Package Framework has made VSPackage development a lot easier.

You can request a PLK through the http://vsipmembers.com site. Simply register for an account (it’s free!) and fill out the information in the list below in order to request a PLK. And you need to make sure the information you entered in the PLK request process remains unchanged in your code. The VSIP site will generate the PLK based on the following pieces of information:

  • Company Name
  • Package GUID
  • Product Name
  • Product Version
  • Minimum Product Edition

If you change any of this information in your VSPackage, you will need to re-request a new PLK through the Web site.

Levels of Extensibility in Visual Studio

Visual Studio is a great extensibility platform that offers developers many choices for how they want to customize and extend their development environment to meet their unique needs. Whether you choose macros, add-ins or VSPackages depends on your scenarios. In general, you can use these rule-of-thumbs:

  • If you are trying to automate tasks in the IDE quickly and you are fine with distributing your code in source code form, macros may be the most appropriate.
  • If you want to distribute your code in binary form, and the automation object model satisfies your needs, try using an add-in.
  • If you want to create a custom project system, editor, debugger or language service, you will need to use VSPackages.

Conclusion

For more tips and tricks for VSX, check out my blog at http://blogs.msdn.com/dr._ex/default.aspx and the blogs of various VSX team members linked to on the VSX Team blog at http://blogs.msdn.com/vsxteam. Now I’m going back into the VSX laboratory to work on some new cool extension ideas for Visual Studio.

Dr. Ex represents the VS Ecosystem team's as a VSX expert! You can find his blog athttp://blogs.msdn.com/dr.ex/.