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