The Managed Extensibility Framework (MEF)

Since I didn’t attend the PDC 2008, I have started to watch some recorded sessions. While the most interesting one for people extending Visual Studio (“TL32 Microsoft Visual Studio: Customizing and Extending the Development Environment” by Tim Wagner) that I mentioned in my last post is not available yet (I guess it will be posted in a few days), today I have watched the one about the new Managed Extensibility Framework (MEF) by Glenn Block:

Managed Extensibility Framework: Overview
http://channel9.msdn.com/pdc2008/TL33/

which is the foundation of a new approach to extensibility in VS 2010.

You know what is happening here: once the core .NET Framework is good and stable (.NET 2.0) we are getting lots of Microsoft “foundations” and “frameworks” built on top of it: Windows Communication Foundation, Windows Workflow Foundation, Microsoft Sync Framework, Microsoft ADO.NET Entity Framework, etc. While I am not fan of using whatever Microsoft (or anyone else) ships in version v1 because it will require some time to get stable and really good (and even fun!), once they reach that point this is great because of two reasons:

  1. You get a lot of plumbing architecture done for free and you concentrate on your business.
  2. Microsoft is going to use them in their own products. For example, I think that Microsoft Sync Framework will be used in SQL Server, Windows Mobile, etc., Windows Workflow Foundation is / will be used in SharePoint, Biztalk workflows, etc. This guarantees a bigger level of commitment to some framework which otherwise has a much bigger chance of becoming “disposable” creations.

The session from the PDC is great to get introduced to MEF, which I was not familiar with (BTW, you can start at minute 20 to skip old approaches to extensibility). I was familiar with the problem of extensibility, discovery and catalog of extensions, and plumbing code for menus and toolwindows, because starting with the first the version (4.0) of my MZ-Tools add-in for Visual Studio .NET, despite being an extension for the Visual Studio host with about 40 features, it was in turn extensible. That is, you can build DLLs with classes extending some base class provided by the MZ-Tools SDK and implementing some methods, and you get in the MZ-Tools toolbar new operations (actions performed over the files of your solution, either to review them or to modify them):

MZ-Tools SDK
http://www.mztools.com/v6/sdk.aspx

And in fact I provided several external operations as samples (C# and VB.NET) of features (not included in the MZ-Tools feature set) in the Community Section of my web site:

Community Place
http://www.mztools.com/community.aspx#ExternalOperations

I tried to do it really simple for my customers:

  1. You create a class library with one class for each new operation that you want to add.
  2. Classes inherit from a base class provided by the MZ-Tools SDK and implement very few plumbing methods
  3. You build the class library and you put the DLL in certain folders (no need for registration files at all)

When loaded, the MZ-Tools host gets the DLLs from those folders, loads them, iterates exported types searching the ones that inherit from the needed base class and then calls its methods to get menu captions, icons, etc.

The Managed Extensibility Framework addresses this kind of scenarios decoupling as much as possible the host and the extensions, using attributes to denote what the extension offers (menus, toolwindows, etc.) and what the extension needs from the host (services). It also discovers extensions, catalogs them and does the needed connections between the host and the extensions. It also addresses the performance problem that can happen with a host with tons of extensions, using delayed loading.

So, a very interesting subject. Even if you are simply creating extensions for Visual Studio, MEF will be used in VS 2010 as a new way to extend it, so it’s good to get started learning it.

Visual Studio 2010 extensibility moving beyond add-ins and packages…?

Last Thursday October 23 the VSX Team blog announced a VSX Talk at the upcoming PDC that contained this very interesting news:

“The next version of Visual Studio moves beyond add-ins and packages to unleash powerful new ways to customize and extend the environment. Learn about the Visual Studio extension model-built on a common Microsoft .NET extensibility framework–that makes it easy to customize Visual Studio in new ways. See how to create extensions for the new code editor and project system, and hear how to build your own graphical designers and specialized development environments.”

That the automation model (EnvDTE) for add-ins (and macros) was being somewhat de-emphasized was quite obvious in the last Visual Studio 2008 release, where after the great improvements that we saw in the VS 2005 automation model (EnvDTE80) very few was added in the VS 2008 version, and all the work of the VSX Team seemed to be about the Visual Studio SDK. But that there is something in the works to move beyond packages is something entirely new. The Visual Studio extensibility is hindered severely from the begining (2002 version) by the fact that the IDE is a native COM application, not a .NET application (some portions are .NET but the core is COM) and the attempts to hide this fact in the Visual Studio SDK have not been 100% successful. So, it is going to be tremendously interesting if the “Visual Studio extension model-built on a common Microsoft .NET extensibility framework” will solve this problem. I hope so very much.

Anyway, for existing Visual Studio extenders this doesn’t mean that you can forget about add-ins or packages because your product needs to support old versions of Visual Studio. I am still supporting VS.NET 2002/2003 in my MZ-Tools add-in and while I will stop supporting those versions at some point in the future, most vendors will have to support the VS 2005, VS 2008 and VS 2010 in the next few years so leveraging the same existing code base (whether it is an add-in or a package) will be common approach in most cases. But at some point in 4-6 years, when you need to support only from VS 2010 onwards, and when this new extensibility approach is more mature, maybe we can forget that VS is COM-based and automation will be truly simple. The first answers in a week, at the PDC…

New extensibility assembly EnvDTE90a.dll in Visual Studio 2008 SP1

I have discovered today by chance that there was a new assembly EnvDTE90a.dll on my machine, whose namespace EnvDTE90a is documented in the MSDN docs:

EnvDTE90a Namespace
http://msdn.microsoft.com/en-us/library/envdte90a.aspx

As you may know, the common automation model is supplied by a set of EnvDTEXX.dll assemblies:

  • EnvDTE.dll (provided by VS.NET 2002 and higher)
  • EnvDTE80.dll (provided by VS 2005 and higher)
  • EnvDTE90.dll (provided by VS 2008)

Each one provides new types and does not replace the old ones. Rather, it adds classes like CodeClass2, HTMLWindow3, etc.

Then you have the VB.NET / C# specific automation model which is supplied by a set of VSLangProjXX.dll assemblies:

  • VSLangProj.dll (provided by VS.NET 2002 and higher)
  • VSLangProj2.dll (provided by VS.NET 2003 and higher)
  • VSLangProj80.dll (provided by VS 2005 and higher)
  • VSLangProj90.dll (provided by VS 2008)

Again, each one provides new types and does not replace the old ones.

Finally, you have the Visual C++ specific automation model which is supplied by the following assemblies:

  • Microsoft.VisualStudio.VCProject.dll
  • Microsoft.VisualStudio.VCProjectEngine.dll
  • Microsoft.VisualStudio.VCCodeModel.dll

On the contrary to the other automation assemblies, each Visual Studio version provides a different version and each version completely replaces the old one.

  • 7.0.3300.0 (Visual Studio .NET 2002)
  • 7.0.5000.0 (Visual Studio .NET 2003)
  • 8.0.0.0 (Visual Studio 2005)
  • 9.0.0.0 (Visual Studio 2008)

(Don’t get me started about the inconsistencies in the version numbering in Visual Studio)

The new EnvDTE90a.dll assembly is supplied by the SP1 of VS 2008 and it provides new automation capabilities for the debugger. AFAIK, this is the first time that a service pack introduces a new automation assembly but the SP1 of VS 2008 is much more than a service pack that fixes bugs, it introduced much new functionality.

I have updated this article of mine to reflect this:

INFO: Assemblies used in Visual Studio Extensibility
http://www.mztools.com/Articles/2007/MZ2007004.aspx

VSX Developer Conference 2008 Sessions screencasts available

Microsoft has just post the screencasts of most sessions of the Visual Studio Extensibility (VSX) Developer Conference 2008 back in September. I didn’t attend because it is a long trip (I live in Madrid – Spain-), a flight to Seattle is not direct (you need a stopover in France, England, Netherlands or in the US) and the fare is not what we could say a domestic flight, not to mention the jet lag that you get when returning. Also, I have already been to Seattle three times in the last four years for the MVP Summits, so tourism is no longer an added value for such a trip. But fortunately the videos are available so although the networking and social aspects of such events are missing, we can get the content (the audio and the PowerPoint slides in synch).

Today I have watched the one from the list that attracted me more, which is not technical, but the one of about marketing tools for Visual Studio (How to Market Your Extensions (VSX107) by Joe Marini) and I have enjoyed it a lot although I was familiar with all the topics explained (it happens that I had read all the books and blogs but one mentioned in the last slide). Making the transition from a freeware MZ-Tools 3.0 for VB6/VB5/VBA to a commercial MZ-Tools 6.0 for VS.NET 2002-2008 product has been a challenge for me, not only from the technical point of view (VB6 -> .NET) but for the most part from the marketing point of view for a geek like me. I have read lots of books, articles, blogs, etc. about it so I am now a bit less clueless 😉

The screenshots are available here:

VSX Developer Conference 2008 Sessions overview:
http://msdn.microsoft.com/en-us/vsx/cc676517.aspx

The strange case of no ext_ConnectMode.ext_cm_UISetup phase fired, not even once

Continuing today with some tests about the The OnConnection method and ext_ConnectMode.ext_cm_UISetup of Visual Studio add-ins of my last post, I created a sample add-in using the code of the first sample (temporary UI) of my article HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in, and later I changed my mind to use the ext_ConnectMode.ext_cm_UISetup phase using the second sample. To my surprise, the ext_ConnectMode.ext_cm_UISetup phase was never fired, not even once, despite the fact that debugging the add-in should fire it each time because of the /resetaddin command-line flag in the Start Options of the Debug tab of the project properties window.

Opening a command prompt window to use devenv.exe /resetaddin MyAddin.Connect caused no effect too. So, I started to get paranoid about the VS 2008 SP1 that I installed some weeks ago. Could it be possible that it broke the behavior somehow? Unfortunately no, the cause was other: in order to Visual Studio calls the OnConnection method of your add-in with the ext_ConnectMode.ext_cm_UISetup phase, your add-in registration must specify that it wants “CommandPreload”, a flag in the registry (COM registration) or tag in the .AddIn file (XML registration). Otherwise Visual Studio doesn’t bother to load add-ins that haven’t requested the ext_ConnectMode.ext_cm_UISetup phase. When you use the add-in wizard to create an add-in project, the page 4 of 6 has a checkbox:

“Yes, create a “Tools” menu item. By default this will cause the Add-in to load when the button is clicked unless the Add-in is set to load on startup of the host application.”

that you must check for the wizard to set that “CommandPreload” flag. I totally forgot this flag and it happens that since I always delete the whole code of the Connect class generated by the add-in wizard because I don’t like the code that it creates, most of the time I don’t bother to check that checkbox to delete less code… so, if you change your mind about whether you want ext_ConnectMode.ext_cm_UISetup phase or not in your add-in, it is not enough to change the code of your OnConnection method, you need to pay attention to that flag, either to get the ext_ConnectMode.ext_cm_UISetup phase, or to optimize your add-in preventing to load it for a phase that it won’t use…

The OnConnection method and ext_ConnectMode.ext_cm_UISetup of Visual Studio add-ins

Without doubt, the most confusing area each newbie add-in developer faces when starting to write an add-in for Visual Studio, is the OnConnection method and the  ext_ConnectMode.ext_cm_UISetup value of the connectMode parameter. I think that every week I answer at least one question about this in the MSDN forums. There are several things contributing this confusion:

  • It is not intuitive that you have commands, and you have buttons, and that while commands should created only once in the lifetime of the add-in to preserve keyboard shortcuts, etc. (and they should not be recreated each time that the add-in is loaded), buttons can be recreated or not, depending on whether you are using a permanent user-interface approach, or a temporary user-interface approach. These approaches are not well documented in the MSDN docs.
  • The ext_ConnectMode.ext_cm_UISetup is used by the OnConnection method, and since the OnConnection method (as its name implies) is called each time the add-in is loaded, it gives the impression that the ext_ConnectMode.ext_cm_UISetup flag is passed also each time the add-in is loaded, while in fact it is not passed each time, only the very first time (if you think otherwise, wait until the following bullet). The ext_ConnectMode.ext_cm_UISetup mode would deserve its own OnUISetup mehod rather than sharing the OnConnection method, as I explained in my post Regarding the IDTExtensibility2 interface.
  • In one of those decisions that cause more harm than good, in VS 2005 Microsoft added the /resetaddin command-line flag to the devenv.exe process in the project properties window of an add-in project to get a new ext_ConnectMode.ext_cm_UISetup phase each time that the add-in is debugged, creating the (false) impression that each time that the add-in is run, you should get an ext_ConnectMode.ext_cm_UISetup phase, and therefore the forums are populated with questions like “my add-in works on my machine, but not when I run it on other machine”, or “my add-in works on Windows XP, but not on Vista”, or “my add-in works when debugging it, but not when it runs standalone”, or “my add-in seems to work sometimes, but it seems that never on Mondays” and the like 🙂

So, if you have reached this post searching for a solution for your OnConnection/ext_ConnectMode.ext_cm_UISetup problem, please read the following article of mine and the related ones at the end of it three or four times, without skipping a line of them, and then read the code samples, and then create a couple of add-ins with either approach in the samples, and then run them within Visual Studio to check that they work, and then run then outside Visual Studio, and then create a setup and run them on another machine, and all this will take you an hour or two, but you will fully understand how it works and how it doesn’t work, and why, and then you can return to the faulting code of your original add-in and it should be crystal clear for you what’s wrong 🙂

HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in
http://www.mztools.com/articles/2005/MZ2005003.aspx

More on the build configuration automation model

I already wrote about the convoluted build configuration automation model and provided a visual representation of it to help understanding it. One of the problems that I explained is that the configurations of solutions are modeled as a collection rather than as a 2-D matrix (configuration names and platforms), as it happens with project configurations, which are modeled correctly. While this problem wouldn’t be as bad once you understand it, it gets worse when you want to do some natural things such as manipulating solution platforms and it has been raised in this post of the MSDN Forum about Visual Studio Extensibility:

  • When you delete an EnvDTE.SolutionConfiguration from the DTE.Solution.SolutionBuild.SolutionConfigurations, you get actually more than one solution configuration deleted. This must be the first case in computing when deleting an item of a collection, it actually deletes more than one… You can test it with this macro and a solution with two configuration names (“Debug” and “Release”) and two platform names (“Any CPU” and “Itanium”, for example):
Sub Configs()

   For Each objConfiguration2 As EnvDTE80.SolutionConfiguration2 In DTE.Solution.SolutionBuild.SolutionConfigurations

      MsgBox(objConfiguration2.Name & "/" & objConfiguration2.PlatformName)

   Next

   DTE.Solution.SolutionBuild.SolutionConfigurations.Item(1).Delete()

   For Each objConfiguration2 As EnvDTE80.SolutionConfiguration2 In DTE.Solution.SolutionBuild.SolutionConfigurations

      MsgBox(objConfiguration2.Name & "/" & objConfiguration2.PlatformName)

   Next

End Sub

You get four configurations initially and only two after deleting one. This is so because deleting a solution configuration from the collection actually deletes all the ones with the same configuration name, regardless the platform!!!. Of course, it doesn’t make sense to delete an item from a 2-D matrix, it only makes sense to delete items in the axis (configuration names or platform names).

  • But it gets worse: you can’t delete solution configurations by platform name because of the previous behavior. Maybe the SDK was the solution, so I checked the Visual Studio 2008 SDK in the MSDN site, and it states that: “There are no VSIP interfaces to create solution configurations programmatically. There are no VSIP APIs for editing the solution configurations. You must use DTE.SolutionBuilder. For more information, see Automation Model. However, there are VSIP APIs for managing the solution build. For more information, see IVsSolutionBuildManager2.”. So, if you can’t create solution configurations names or platforms programmatically using the SDK, you can’t delete them too, I guess. You are pointed to the DTE.SolutionBuilder, as if such thing exists in the automation model (it refers to the DTE.SolutionBuild) that, as we have seen, it doesn’t allow you to delete solution configuration platforms.

As I pointed in the original post, you can actually create solution configurations or platforms by creating project configurations and platforms and propagating them to the solution level (last parameter of EnvDTE.SolutionManager.AddConfigurationRow and EnvDTE.SolutionManager.AddPlatform). But there is no “propagation” when deleting them at project level, so I guess that there is actually no way to delete solution platform names. The closest thing that you can do with automation is to iterate the solution configurations to warn the user the platforms that are not allowed to make her to delete them by hand.

Visual Studio 2005/2008 managed add-ins using XML registration (.AddIn file) and unmanaged satellite DLLs

In my last entry I mentioned that I was investigating to use XML registration (.AddIn File) with my MZ-Tools add-in. Finally I was unable because it seems that Visual Studio 2005/2008 managed add-ins using XML registration don’t support unmanaged satellite DLLs (created with C++) for custom pictures for commands. The .AddIn file doesn’t support the SatelliteDllName and SatelliteDllPath tags whose equivalent entries in the Windows registry are used for addins using COM registration. For add-ins using XML registration, it seems that you need managed satellite DLLs (.resx file that generates a .resources file) that don’t need XML tags to be located. Of course this complicates the scenario if your add-in needs to support VS.NET 2002/2003 with the same code base, because you need an unmanaged satellite DLL for VS.NET 2002/2003 and a managed satellite DLL for VS 2005/2008. So, I will keep using the COM registration and unmanaged satellite DLLs for all versions.

I don’t understand this restriction, since COM/XML registration has nothing to do with satellite DLLs. The .AddIn file could have happily supported the SatelliteDllName/SatelliteDllPath tags for unmanaged satellite DLLs to ease backwards compatibility, but now it is too late and the damage is done.

MSDN: Walkthrough: Creating Managed Satellite DLLs
http://msdn.microsoft.com/en-us/library/e9zazcx5.aspx

Huizhong Long’s WebLog: Displaying custom bitmap for VS add-in command button from satellite DLL
http://blogs.msdn.com/hlong/archive/2005/09/27/474522.aspx

All that said, I really hate satellite DLLs (managed or unmanaged), they should be totally unnecessary to provide custom pictures, and I would like to get rid of them:

Microsoft Connect: Custom pictures for commands using icons without satellite DLLs
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=114769