The strange case of InvalidCastException using EditPoint.FindPattern with Visual Studio Database Projects

Many months ago I reported to Microsoft through Microsoft Connect an InvalidCastException that happened when using the EditPoint.FindPattern with .sql files of a database project of Visual Studio 2008 Team Suite (or VS 2008 Edition for DB Professionals) Beta 2:

EditPoint.FindPattern causes InvalidCastException on SQL editor of VSTS for DB Professional projects
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=295427

As I reported, the problem didn’t happen in Visual Studio 2005 (at the time of that report), so apparently the bug was introduced in Visual Studio 2008 Beta 2. Fortunately Microsoft fixed the bug for VS 2008 RTM, so I thought the case was closed.

However, last week a customer of my MZ-Tools add-in reported that same problem but using VS 2005. How could that be if the problem didn’t happen at that time? In fact the problem didn’t happen today with VS 2005 SP1 and the VS 2005 Vista update on my computer. Reviewing the list of updates that the customer had installed, I had all of them but this one:

Microsoft® Visual Studio® 2005 Team Edition for Database Professionals Service Release 1
http://www.microsoft.com/downloads/details.aspx?familyid=9810808c-9248-41a5-bdc1-d8210a06ed87&displaylang=en

I installed it, and bingo! The problem was reproduced. So, while VS 2005 SP1 works fine, that update, which was released after SP1, introduced the bug, that was included in VS 2008 Beta 2 and was fixed in VS 2008 RTM, but for VS 2005 users the bug remains there if they install that service release.

MZ-Tools Articles Series (Updated): PRB: Visual Studio .NET events being disconnected from add-in.

As you may know if you are a C# add-in programmer, DTE events can get disconnected if you don’t hold a class variable pointing to them (VB.NET add-in programmers tend to use the WithEvents approach which already uses a class variable so they don’t suffer this problem). Although this issue is well documented in MSDN, FAQs, blogs, and an article of mine, etc., it was not clear yet for some people why a garbage collection happened if VS holds a reference to the object raising the events. So, I have updated the article to explain it more clearly:

PRB: Visual Studio .NET events being disconnected from add-in.
http://www.mztools.com/articles/2005/mz2005012.aspx

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.

MZ-Tools Articles Series: HOWTO: Get the target .NET Framework of a Visual Studio 2008 project from a Visual Studio add-in or macro

Today I had to get the target .NET Framework of a VS 2008 project. While the project file stores the values as “v2.0”, “v3.0”, etc, the values returned by the automation model are a bit surprising at first glance. Here is the article that I wrote about this:

HOWTO: Get the target .NET Framework of a Visual Studio 2008 project from a Visual Studio add-in or macro
http://www.mztools.com/articles/2008/MZ2008015.aspx

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

The strange case of System.UnauthorizedAccessException when registering a Visual Studio add-in for COM Interop

Today I received a bug report for a new customer of my MZ-Tools add-in for Visual Studio (who purchased directly the product without trying the trial version) and the first thing that he encountered when running the setup was:

System.UnauthorizedAccessException: Access to the registry key ‘HKEY_CLASSES_ROOTComponent Categories{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}’ is denied.

(alas, not the most wonderful first impression about a just purchased product, but…)

He was administrator and had disabled the antivirus and other things to no avail.

The exception was thrown from RegAssemblyVSNET200X.exe, a small utility that my setup uses to register the .NET add-in DLL for COM Interop, which basically checks that some required DLLs exist on the machine and then calls System.Runtime.InteropServices.RegistrationServices.RegisterAssembly to register the assembly for COM/ Interop (the same that you can do with the regasm.exe utility of the .NET Framework).

The only reference to this problem that I found with Google was:

http://www.dotnet247.com/247reference/msgs/54/273059.aspx

That shows that a call to EnsureManagedCategoryExists is made. When you register an assembly for COM Interop, a registry entry is created like this:

HKEY_CLASSES_ROOT
   CLSID
      <Your GUID>
         Implemented Categories
            {62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}

And after creating that registry entry, the .NET Framework calls EnsureManagedCategoryExists to ensure that the implemented category, well, actually exists. Using Reflector for .NET to decompile that method I got:

Private Sub EnsureManagedCategoryExists()
   Using key As RegistryKey = Registry.ClassesRoot.CreateSubKey("Component Categories")
      Using key2 As RegistryKey = key.CreateSubKey("{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}")
         key2.SetValue("0", ".NET Category")
      End Using
   End Using
End Sub

And somehow even if you are administrator the CreateSubKey method can fail if the user doesn’t have proper permissions.

While I was investigating all this, the customer was smart enough to find this KB article explaining the problem and solution:

FIX: “Access to the Registry Key Denied” Error Message When You Register .NET Assembly for COM Interop
http://support.microsoft.com/kb/327507

The article states that it is a permissions problem (even if you are an administrator) although it does not clarify how permissions can become different on several machines (for most admins, COM Interop registration works fine). It states too that the problem was fixed in .NET Framework 1.1, which means that it should happen only with .NET Framework 1.0 (Visual Studio .NET 2002), but the customer was using MZ-Tools for Visual Studio .NET 2003, 2005 and 2008, so there is something missing here and in fact, as fas as I can tell, the logic and the decompiled EnsureManagedCategoryExists method is virtually the same for the three .NET Framework versions.

Anyway I hope this post helps to solve this problem if you ever encounter it.

MZ-Tools Articles Series: HOWTO: Add a filtered task with navigation to the Task List from a Visual Studio add-in

Another “task” that can be quite usual from a Visual Studio add-in is to add a task to the Task List or Error List. It happens in Visual Studio 2005/2008 that it is not as easy as it seems because of the following:

  • VS 2005/2008 uses a separate Error List window for errors, and the automation model (EnvDTE) doesn’t provide a way to add errors, you need to implement an error provider for that (typically compilers implement an error provider). So, you can only add items to the Task List, not to the Error List.
  • While a Task Item has properties for a file and line number, when you double click it VS doesn’t navigate to that file and line number unless you have used the EnvDTE80.TaskItems2.Add2 method.
  • When an add-in (or macro) adds a task, it is added to a new item in the combobox of the Task List with the name “Add-ins and macros”, instead of, say, the “User Tasks” item. So you need to filter the combobox by that provider, but, alas, this is very tricky. Chetan Chudasama, from the Visual Studio team, published how to do it in its Programmatically setting TaskList view blog post. He didn’t mention where the numbers such as 2200 come from, so wrote a HOWTO: Execute a command by Guid and Id from a Visual Studio add-in post explaining it.

Here is the article:

HOWTO: Add a filtered task with navigation to the Task List from a Visual Studio add-in
http://www.mztools.com/articles/2008/MZ2008014.aspx

MZ-Tools Articles Series: HOWTO: Execute a command by Guid and Id from a Visual Studio add-in

While most Visual Studio commands have a name and you can execute them using DTE.ExecuteCommand, there are cases where commands don’t have a name, just the Guid and Id that truly identifies them, For example, the command to filter the Task List of Visual Studio 2005/2008 by its combobox (my next article will be about this). This article explains how to get the Guids and IDs of Visual Studio commands, and how to execute a command from the automation model (EnvDTE) given its Guid and Id:

HOWTO: Execute a command by Guid and Id from a Visual Studio add-in
http://www.mztools.com/articles/2008/MZ2008013.aspx

MZ-Tools Articles Series: HOWTO: Open the Web Browser and navigate to a page from a Visual Studio add-in or macro

A quite simple question (once you know the answer) is how to open the Web Browser of Visual Studio and navigate to some web site or page. I thought that the automation model didn’t provide such capability and was about to use a workaround, but it happens that it provides a method to do it. Just in case you weren’t aware of it, here it is: 

HOWTO: Open the Web Browser and navigate to a page from a Visual Studio add-in or macro
http://www.mztools.com/articles/2008/MZ2008012.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!

VS SDK, packages, add-ins, macros and more…