Category Archives: Other

Empty ProjectProperties4 and ProjectConfigurationProperties4 interfaces in VSLangProj90.dll ?

As you may know, while the general Visual Studio automation model uses the EnvDTE DLL series (EnvDTE.dll, EnvDTE80.dll, EnvDTE90.dll), there are some extension DLLs for the automation model of VB.NET and C#, the VSLangProj DLL series (VSLangProj.dll, VSLangProj2.dll, VSLangProj80.dll and VSLangProj90.dll). For more information, see my article INFO: Assemblies used in Visual Studio Extensibility.

Apart from some enums which are handy to interpret values returned from properties, the VSLangProj DLLs contain interfaces such as VSLangProj.ProjectProperties, VSLangProj2.ProjectConfigurationProperties2, VSLangProj80.VBProjectProperties3, etc. whose properties are the names that you can use when calling the EnvDTE.Project.Properties.Item(“XXX”) or EnvDTE.Configuration.Properties.Item(“XXX”).

However, if you look at the VSLangProj90.dll file of VS 2008 with the Object Browser, the VBProjectProperties4, VBProjectConfigurationProperties4, CSharpProjectProperties4 and CSharpProjectConfigurationProperties4 interfaces are all empty. I don’t know the cause, but it seems an oversight, likely they were created and later it was forgotten to add the properties. If there were no properties to add, there was no need to create them, but certainly the automation model of VS 2008 has some new project properties such as “TargetFramework” that do not appear there and that I used yesterday in my article MZ-Tools Articles Series: HOWTO: Get the target .NET Framework of a Visual Studio 2008 project from a Visual Studio add-in or macro.

Visual Studio CommandBars don’t have unique names

Just in case you are not aware of this yet (I found a problem related to this today in the MSDN forum), Visual Studio CommandBars don’t have unique names, which means that retrieving a specific commandbar such as “Project” with this code can fail returning a commandbar that you didn’t expect:

DTE.CommandBars.Item("Project")

In fact, there are 3 or 4 commandbar named “Project” in Visual Studio 2005 and 2008, as this macro will show:

Dim sMsg As String

For Each objCommandBar As CommandBar In CType(DTE.CommandBars, Microsoft.VisualStudio.CommandBars.CommandBars)

   If objCommandBar.Name = "Project" Then
      sMsg = ""

      For Each objCommandBarControl As CommandBarControl In objCommandBar.Controls
         sMsg &= objCommandBarControl.Caption & Microsoft.VisualBasic.ControlChars.CrLf
      Next
      MessageBox.Show(sMsg)

   End If

Next

The same happen with the “View” commandbar and others.

CommandBars are truly identified by Guid/Id pairs, and Dr.eX posted the workaround to this problem some time ago:

Using IVsProfferCommands to retrieve a Visual Studio CommandBar
http://blogs.msdn.com/dr._ex/archive/2007/04/17/using-ivsproffercommands-to-retrieve-a-visual-studio-commandbar.aspx

Introducing the Automation Model (EnvDTE) Enhancement Request series

Apart from very simple approaches (macros, templates) and super-specialized DSL tools for very specific purposes, there are really only two general Visual Studio extensibility approaches: the Automation Model (formerly Extensibility model), a.k.a. EnvDTE, and the Visual Studio SDK.

While the Visual Studio SDK will be enhanced over the next years to make it truly simple, .NET-oriented, object-oriented, free of COM or C++ style APIs, etc. and maybe some day we will have a unified approach, the automation model (EnvDTE) still have its place, and there are quite a few areas of it that could be enhanced. Seeing the EnvDTE90.dll of the last Visual Studio 2008, it seems that it hasn’t been enhanced a lot :-(. So, I am planning a series of enhancement requests that I will send to Microsoft through the official channel (Microsoft Connect). Supposedly requests from MVPs get more consideration, but that plan is to post links on this blog so if you are an add-in developer (or not) you can vote for them. Hopefully Microsoft can implement them for the next Visual Studio version. I think this is a very good moment because Visual Studio 2008 has just been released, the version cycle lasts 2 years and it should be the proper time to write the specs of the next version.

My first enhancement request is the problem #1 of all times in the extensibility of Microsoft IDEs since more than 10 years ago, the problem of custom, transparent pictures for buttons:

Automation Model (EnvDTE) Enhancement: Accept .NET System.Drawing.Icon to set custom pictures in add-in commands and toolwindows
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=336868

Vote for it!

The special and in another time unique “Solution Items” folder of Visual Studio 2005

Back in VS.NET 2002/2003 a solution could contain only up to two folders, which were special: the Solution Items folder and the Miscellaneous Files folder (if you configured a setting in the Options window to show it), and the automation model (EnvDTE) contained their well-known GUIDs to identify them (EnvDTE.Constants.vsProjectKindSolutionItems, EnvDTE.Constants.vsProjectKindMisc).

VS 2005 introduced a new concept, the “solution folders”, that could contain projects, and you could create lot of them, and you had a new well-known GUID (EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder As String = “{66A26720-8FB5-11D2-AA7E-00C04F688DDE}” to identify such folders, and guess what, alas, it happens that the old Solution Items folder is just a “solution folder” in the new IDE, indistinguishable from the others but by the name, so the GUID cannot identify it and then you can only rely on the name “Solution Items” to distingush them (because the IDE doesn’t allow you to create two solution folders with the same name), and the Project.UniqueName includes a GUID too (such as “Solution Items{24571E2E-0233-4835-9C48-80E8D75EC95E}”) to make them truly unique I guess (just in case you nest them, because as I said, the IDE doesn’t allow two folders with the same name with the same parent, but it does with different parents).

So, in VS 2005, there is no really a unique “Solution Items” folder, you could rename it, or have tons of them with files, even nested, but if you really want to locate and use it as you could in VS.NET 2002/2003, I think that your only chance is the name, and whether you use the UniqueName or the Name to search the “Solution Items” string, take into account that can be localized (not tested) if you deploy it to international non-English IDEs.

devenv.exe /SafeMode and add-ins in Visual Studio 2005 / 2008

Just a curious difference in behavior between Visual Studio 2005 and Visual Studio 2008 that the MSDN documentation doesn’t cover very well:

According to the MSDN documentation of VS 2005, “This switch prevents all third-party VSPackages from loading when Visual Studio starts, thus ensuring stable execution.” One would expect that if third-party VSPackages are not loaded, add-ins would be also excluded from loading, but they aren’t, they are loaded.

Visual Studio 2008 works as expected and the whole Add-in Manager is disabled.

Unknown error (error number 80131522) loading add-ins

I am writing an article about creating setups for Visual Studio add-ins and testing I have found that if the namespace/class specified in the <FullClassName> tag of the .AddIn XML file does not match the actual namespace and connect class name in the source code, you get an obscure <Unknown error> (error number 80131522) loading the add-in. Searching the web I found in the forums that I was not the first developer with this problem, so I have updated my article to reflect this:

HOWTO: Troubleshooting Visual Studio and Office add-ins
http://www.mztools.com/articles/2007/MZ2007009.aspx

It would be great if Microsoft could provide more helpful message errors when things are not set up as expected…

New book on Visual Studio extensibility

As you may have noticed, there aren’t many books on Visual Studio Extensibility, so any new book is great news. This is the case of a new book with the title “Professional Visual Studio Extensibility” by Keyvan Nayyeri:

http://nayyeri.net/blog/professional%2Dvisual%2Dstudio%2Dextensibility%2Dfinally%2Dreleased/

It is already available from Wiley and Wrox (where you can read the TOC, index, and first chapter) and will be available from Amazon shortly. I haven’t read it yet (I am awaiting a complimentary copy in a few days or weeks) but I am excited because this book covers more than add-ins or macros, so you have chapters about VS SDK packages, DSL tools, Visual Studio Shell, extending the debugger or even MSBuild. While there is lot of information about those subjects in MSDN and blogs, I personally prefer a good book to learn new technologies.

How do I get a System.Type from a type name?

This is another question that appears from time to time in the forums, and it is one extremely complicated to have a 100% satisfaction with the result :-). I haven’t written a MZ-Tools Series article for this since I don’t have a comprehensive answer with a sample code, but I will elaborate a bit about this in this post.

The question is, suppose I have a string like “Car” that I know it’s a type. How can I get the System.Type that represents that type? Before that question there is a previous one: how did I get that string? There are several ways:

  • Using the code model (EnvDTE.Project.CodeModel or EnvDTE.ProjectItem.FileCodeModel), you have a CodeVariable, CodeParameter, etc. which has a CodeTypeRef property that returns the type of the code element.
  • Parsing a procedure code (by hand, since the code model doesn’t cover that), you get statements like “Dim objCar as Car” (VB.NET) or “Car mycar” (C#), so somehow you get the “Car” string and you guess that it is a type.

There are a couple of complications to note here:

  • Types have a short name, such as “Car”, and a fully qualified name, such as “Vehicles.Motorized.Car”. Since you can have “Imports” statements at file or project level in VB.NET and “using” statements at file level in C#, it is not required that the fully qualified name to appear in the variable or parameter declaration. Note: even if the declaration contains a dot (.) you can’t assure that it is a fully qualified name because it can be a partially-qualified name, such as if you import the “Vehicles” namespace at file level and you declare the variable as Dim objCar As Motorized.Car.
  • Types can reside in compiled assemblies references, or, alas, in the project’s source code or in a project (not compiled) reference. In the last two cases, you can’t have a System.Type, since maybe the project is not compiled yet (first time) or maybe the last compilation was days ago and it is not up-to-date. In these cases, for most accuracy you don’t really want a System.Type but an EnvDTE.CodeElement such as an EnvDTE.CodeClass, EnvDTE.CodeStruct, EnvDTE.CodeInterface, etc. So, your add-in has to deal with two kind of types: compiled types (represented by a System.Type) and source code types (represented by a CodeElement).

So, let’s try to solve them:

  • To get the fully qualified name of a type name, assumming that it comes from a EnvDTE.CodeTypeRef, you can try the CodeTypeRef.AsFullName property (in contrast to its CodeTypeRef.AsString property). I don’t know how reliable is this in each version of Visual Studio and for each language (VB.NET, C#) but my experience is that you can’t fully trust the code model. As a workaround, you should compose a list of fully qualified candidate type names combining the imported namespaces and then try to resolve which of them is the true one. This is what the compiler does after all when building the project, although it doesn’t expose that information to add-ins or packages (AFAIK).
  • Given the fully qualified name, or a list of candidates, you need to “resolve” them to a System.Type or EnvDTE.CodeElement. To do this, I would start with compiled references since is faster than using the code model. You would have to get the references of the project which are compiled assemblies (see HOWTO: Getting information specific to VB.NET and C# projects from an add-in or macro). For each compiled reference you get the name of the assembly and using Reflection you can use Assembly.Load or Assembly.LoadFrom to load it and then call Assembly.GetExportedTypes to get the public types and then iterate them until you find the one that matches the fully qualified type name. If you don’t find it, then chances are that it is a type declared in the source code of the project, or in one of the project (not compiled) references. In these cases you have to navigate the code model of each project (see HOWTO: Navigate the files of a solution from a Visual Studio .NET macro or add-in and HOWTO: Navigate the code elements of a file from a Visual Studio .NET macro or add-in). Needless to say, this can be slow.

All that said, you may have heard of the ITypeResolutionService service of Visual Studio, which sounds promising to avoid all that. I haven’t tried it personally because it was not clear for me how to get an instance of it (most documentation refers to component designers) but today I found two posts of MVP fellow Daniel Cazzulino that can be helpful:

Retrieving available types in current project and its references (without locking)
http://blogs.clariusconsulting.net/kzu/retrieving-available-types-in-current-project-and-its-references-withoult-locking/

and

How to get a System.Type from an EnvDTE.CodeTypeRef or EnvDTE.CodeClass
http://blogs.clariusconsulting.net/kzu/how-to-get-a-system-type-from-an-envdte-codetyperef-or-envdte-codeclass/

So, he explains how to get the all the types declared in a project and references using the ITypeDiscoveryService, and how to get a System.Type from a type name using the ITypeResolutionService, retrieving both services from an EnvDTE.Project. These is great news, but notice the caveat that for types declared in source code, it will retrieve a System.Type from the last successful compilation (if any) and not an EnvDTE.CodeElement. Assuming that you don’t mind the issue of the out-of-date compilation, getting a System.Type can be enough for some scenarios, but not for others, such as when you want to go to the source code file of the type (think the Go To Definition command of Visual Studio), where you really want an EnvDTE.CodeElement (which contains the ProjectItem and location, etc.) and not a System.Type.

TechDays 2008

This week I attended the TechDays 2008 here at Madrid, a two-days event to launch Visual Studio 2008, Windows Server 2008 and SQL Server 2008 (this product actually is not released yet but…). I don’t know if it was that Microsoft Iberica (the subsidiary for Spain and Portugal) celebrated its 20 anniversary or that the new products deserved it, but this has been the greatest Microsoft event that I ever attended (except the Microsoft TechEd at Barcelona that I attend every some years). It was like a mini-TechEd, with lots of parallel sessions, hands-on labs, ask the expert, partners expo, etc. and even hot dogs ;-). Lots of known people (many speakers were fellow MVPs) and very good content in most sessions. Apart from the new exciting technologies such as WCF, WFF, WPF or SilverLight I was mostly interested in Team Foundation Server 2008, a great tool for collaboration and team work that hopefully I will install and use this year, and which furthermore provides extensibility, so who knows if I enter that area some day…