The Evil EnvDTE namespace

If you have ever written an AddIn for Visual Studio or a Package, you must likely recognize the interfaces EnvDTE.Solution, EnvDTE.Project, EnvDTE.ProjectItem, EnvDTE80.SolutionFolder and EnvDTE.DTE, and you may ask what's so wrong about these interfaces?

In order to answer this question we must look at the history of Visual Studio and Visual Basic. One of the many features introduced with the release of Visual Basic 4.0 in 1995 (https://en.wikipedia.org/wiki/Visual_basic ) was the ability to create "Add In" that ran inside the VB IDE or inside the Office Applications.

The idea was that using a set of COM interfaces one can easily extend the running host with more functionality. Now days this sound fairly easy to do but that's because today we have Java, .NET and may design patterns that are specifically designed to do this (check out the Composite Application Block from P&P). But in those days, Microsoft had unmanaged C++ and VB4 or VB5.

I can understand that If Microsoft had chosen C++ as the default language for writing those Add Ins, the design would probably be much better but instead they went with VB for a number of reasons ( The most important one was cost of development ). So if VB was to be the language for developing these Add In the COM interfaces used for extending the host MUST be VB-compatible.

And been VB-compatible meant a lot of constraints right there. Remember, in those days VB did not have inheritance, it barely did encapsulation, there was no interface concept in the language until VB6.

So VB lacked some pretty fundamental elements in the language, it also added some elements that we may call "detrimental" to the language, yes you're right, I am talking about default properties. You know the language thing that allows to write: Value = recordSet["Name"] instead of value = RecordSet.Columns["Name"].Value. I know that the first looks "shorter" than the later, but the later is explicit about the underlying data structure, however, that's another topic.

So, the firsts Add Ins for VB and Office (Called VBA) were designed with these constraints and if fact Microsoft was right (at the particular time). They were a success in terms of a community writing new Add Ins every day.

Then 2001 came and .NET was born. In 2002 Visual Studio 7.0 was released. With this VB acquire new powers, suddenly it was a full Object Oriented language and we also were given his big brother C#.

However, if you look at the way you extended Visual Stuido 7.0 and for that matter Visual Studio 8.0 and probably Orcas also, we continue to use the same old interfaces that were great for a "detrimental" scripting language as VB4,5,6, but not so great for VB.NET, C# and C++.

Let's see an example of what do I mean, let's take the EnvDTE.Project interface and let's analyzed it.

Photobucket - Video and Image Hosting

The EnvDTE.Project interface is provided by a Project in the current open Solution in Visual Studio (I am using the definition of Project broadly because a Solution Folder is also a Project in Visual Studio, well see why later on, keep reading).

 

The Figure shows elements in the Solution Explorer in Visual Studio. Every single object in the solution tree must implement the IVsHierarchy, those nodes that are projects must also implement the IVsProject interface. However, one may think that most objects that are "Projects" in the solution tree provide an EnvDTE.Project interface. I said most because the reality is that it's up the designer of the Project system to provide or not the EnvDTE.Project.

The reality is that EnvDTE.Project (and for that matter almost all interfaces in the EnvDTE namespace) is an Automation interface. That is, an interface designed to be used by a VB6 client. So, you see where I go with this?

 

 

Photobucket - Video and Image Hosting

Maybe, this picture helps to clear things up. When you have a Project node in the Solution Explorer, this project node must (yes must) implement the IVsHierarchy interface and the IVSProject interfaces. However, it is not the same story with EnvDTE.Project, this interface is provided by asking the IVsHierarchy for the "Extension Object". The designer of the Project System may answer NULL to that request.

It is completely valid for a FooBarProject system not to have an automation object.

The reality is that with the languages and Tools that we have today, there's little need for "automation" interfaces. I am not saying that we should not used them, on the contrary, they can be very useful in certain scenarios, but one needs to understand what's going behind the scenes. I wish somebody had told me all of this when Daniel(https://weblogs.asp.net/cazzu/) and I were designing the concept of Bound References in GAX.

One example when you should NOT use the EnvDTE interfaces is when you are trying to run through the Solution Tree, using the IVsHierarchy interface is much easier and a lot more robust that trying to use a bunch of automation objects.

Another problem with automation objects is that not every project system implements the same interfaces in the same way, one example is the get_Files method, C# implements it using a zero-based index, but the VB project system implements it using a one-based index.

If you are trying to write a Framework on top of Visual Studio, try to avoid going through the automation interfaces, try to see if there is a service in VS that can give you what you want. Example: Instead if using DTE.Selection, use IVsMonitorSelection service. If you need to store a Project pointer, persist the GUID of the project, not the path or canonical name.

All of this to say that, the EnvDTE are there mostly for historical reasons and to support old add ins and extensions. One must realize that they are second class citizens in the Visual Studio world of extensibility and that when writing extensions to VS one must talk with the real underlying objects we are extending.

I wish somebody had told me this before.