Category Archives: The strange case of…

The strange case of “%ALLUSERSPROFILE%\Datos de programa\Microsoft\MSEnvShared\AddIns” add-in file path

(Or why it is a bad idea for an add-in to add add-in file paths to Visual Studio)

When Visual Studio 2005 introduced XML-based add-ins, which used an .AddIn file rather than COM registration), rather than providing just two fixed folders to place such files (one for all users, other for the current user), Microsoft provided five (5!!) folders, listed in the Tools, Options menu, Environment, Add-in/Macros Security section.

Not only that, Visual Studio allows to add more folders using the Add… button or programmatically writing to the “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\AutomationOptions\LookInFolders” registry key (VS 2005).

Not only that, you will have a difficult time expanding VS-proprietary placeholders like %VSAPPDATA%, %VSCOMMONAPPDATA% or %VSMYDOCUMENTS%, if your add-in setup wants to use one of those folders.

Not only that, Visual Studio 2008 added a sixth folder, %ALLUSERSDOCUMENTS%\Microsoft\MSEnvShared\Addins.

Not only that, Visual Studio 2008 actually fails to look for XML files in that new folder (see HOWTO: Using the Process Monitor (ProcMon) tool to diagnose Visual Studio add-ins problems)

And not only that (finally), Visual Studio hardcoded “Application Data” in one of the paths (“%ALLUSERSPROFILE%\Application Data\Microsoft\MSEnvShared\Addins”) without taking into account that that folder is localized and in other languages it doesn’t exist with that name on the hard disk. For example, in Spanish, it is should be “%ALLUSERSPROFILE%\Datos de programa\Microsoft\MSEnvShared\AddIns”.

I documented all that in the article INFO: Default .AddIn file locations for Visual Studio add-ins.

Guess what? Yesterday, while writing an utility that scans the add-in file paths, I noticed that on my Spanish computer Visual Studio 2005/2008 listed “%ALLUSERSPROFILE%\Datos de programa\Microsoft\MSEnvShared\AddIns” as one of the add-in file paths in the Tools, Options menu, Environment, Add-in/Macros Security section. Indeed VS 2005 listed 6 folders instead 5, and VS 2008 listed 7 folders instead of 6.

How could that be? At first I thought that the service pack 1 of both IDEs could have “fixed” the problem adding the localized version of that path maintaining the wrong one (with “Application Data” hardcoded). But I quickly discarded that explanation because I had installed SP1 from long time and those folders were not there. Then I remembered that I had installed recently an add-in (I won’t cite its name), and looking into the contents of the “%ALLUSERSPROFILE%\Datos de programa\Microsoft\MSEnvShared\AddIns” folder, there was the .AddIn files of this add-in. So, the setup of this add-in is placing the .AddIn file in that folder, AND it is adding that folder to the “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\AutomationOptions\LookInFolders”. In other words, it is trying to “fix” what Microsoft did wrong with that folder. But I think this is a bad idea for this reason: if this add-in is installed on a non-English computer and the user happens to be a developer of add-ins who is unaware of the problem of the hardcoded “Application Data” path, he will see two paths listed:

%ALLUSERSPROFILE%\Application Data\Microsoft\MSEnvShared\Addins
%ALLUSERSPROFILE%\Datos de programa\Microsoft\MSEnvShared\AddIns

And certainly he will use the second one because any non-English developer knows that it is the correct one (using an API call to get the actual localized folder), but when his add-in is installed on another machine, the second path is not in the list of paths that VS scans, and the add-in won’t appear in the Add-In Manager.

Placing the .AddIn file in the first path (%ALLUSERSPROFILE%\Application Data\Microsoft\MSEnvShared\Addins) is also a bad idea because the setup will create that English folder on non-English computers, and then the computers will have those two paths physically on the hard disk.

So, what to do? I’d recommend to use the “%VSCOMMONAPPDATA%\AddIns” folder instead, which is also for all users but it neither mess the list of paths of Visual Studio nor creates English folders on non-English computers. The only drawback is that the folder is actually different each VS version:

For Windows XP:

  • VS 2005: “C:\Documents and Settings\All Users\Application Data\Microsoft\VisualStudio\8.0\Addins”
  • VS 2008: “C:\Documents and Settings\All Users\Application Data\Microsoft\VisualStudio\9.0\Addins”

For Windows Vista:

  • VS 2005: “C:\ProgramData\Microsoft\VisualStudio\8.0\Addins”
  • VS 2008: “C:\ProgramData\Microsoft\VisualStudio\9.0\Addins”

To get it programmatically the custom action of your setup that copies the .AddIn file must call the API that returns special folders with the parameter CSIDL_COMMON_APPDATA and then concatenate
“Microsoft\VisualStudio\8.0\Addins” for VS 2005 or “Microsoft\VisualStudio\9.0\Addins” for VS 2008. For example:

  • Using the .NET Framework the call is System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData)

Being the path different for each VS version you can’t use a single .AddIn file with two hosts inside (HostApplication tags) for VS 2005 and VS 2008, but that’s a minor extra work for the setup of an add-in, and we all know that software is all about our users, not about us the developers…

The strange case of Visual Studio 2008 severely crashing loading an add-in

Some months ago a customer of my MZ-Tools add-in reported a crash in Visual Studio 2008 Team Suite when loading it. When an add-in crashes loading it, usually Visual Studio captures the exception or COM error and shows a semi-friendly messagebox indicating that the add-in has caused an exception or failed to load, and give you the chance of removing it. While sometimes the error is <Unknown Error> and you get only the error number (specially if the problem is found by the CLR loading the add-in and not executing the code), this crash was more severe: “Visual Studio needs to close”, and your only options are to close or to restart. MZ-Tools doesn’t have instrumentation yet, but after a couple of custom builds with traces sent to the customer I was able to determine that the problem happened creating the very first toolbar. Somehow the customer changed to Visual Studio 2008 Professional Edition and the problem disappeared so I closed the incident (falsely).

Last week it was a prospect who experienced the severe crash. It is not the best experience for a prospect to download a trial version of your product, install it and get such a crash. I knew that for such severe crashes the problem is not really my add-in but the prospect would think otherwise… Since the add-in is marked to load on startup, it crashes VS every time so chances are that he will uninstall and forget the product. But fortunately he reported it to me, so I troubleshooted it. After a couple of days verifying that the problem was actually MZ-Tools and not other extensions, that the referenced assemblies were present and that the versions were correct, I recalled this problem, that I had almost totally forgotten. I retreived the e-mails of the previous case, and the problem happened with VS 2008 Team Suite also this time. And when I was about to send him a minimal add-in that creates a toolbar to reproduce the problem, I searched the web and I found this post by Jamie Cansdale, former MVP colleague and author of TestDriven.NET (formerly NUnitAddIn):

VS 2008 crashes on startup when ‘Code Analysis Tools’ feature is not installed
http://weblogs.asp.net/nunitaddin/archive/2007/11/29/vs-2008-crashes-on-startup-when-code-analysis-tools-feature-is-not-installed.aspx

So, the problem happens in Visual Studio 2008 Team Suite if you don’t install the “Code Analysis Tools”. Since in the first case the user switched to Visual Studio 2008 Professional Edition, which doesn’t include the Code Analysis Tools (only Visual Studio 2008 Development Edition or Visual Studio 2008 Team Suite), the problem disappeared. In the second case, the prospect run the setup again and certainly the Code Analysis Tools were not installed. After installing them, MZ-Tools loaded fine.

Now, I have tried to reproduce the problem to report it to Microsoft to no avail:

My computer has Visual Studio 2008 Team Suite with the Code Analysis Tools and SP1. I have removed the Code Analysis Tools and the problem doesn’t appear. I have removed the SP1 and nothing. I have removed VS 2008 completely and I have installed it from scratch without the Code Analysis Tools and the problem doesn’t appear. So, I don’t know yet how to reproduce but at least I am glad that I know how to solve it and hopefully I won’t forget it again (I’ll force myself to check the “The strange case of …” series for those rare problems…)

I have also updated this article:

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

UPDATE (Dec 11, 2008): Finally I have reproduced the problem with a clean virtual machine and Visual Studio 2008 Development Edition without the “Code Analysis Tools” and without installing SP1. The problem happens when an add-in performs certain operations with commandbars of DTE such as:

  • Trying to create a toolbar
  • Trying to retrieve an nonexistent command bar
  • Trying to set the Name property of a Commandbar
  • Maybe others

The problem can be solved through two ways:

  • Installing the missing “Code Analysis Tools” component
  • Installing Service Pack 1

While not many users are affected by this bug since most of them perform a full installation of Visual Studio 2008 and/or install SP1, the problem is so nasty that you may want to detect this circumstance and show a warning when loading your add-in. Something like the following in the OnConnection method before manipulating CommandBars:

If IsVS2008TeamSuite() Or IsVS2008DevelopmentEdition() Then

   If Not IsCodeAnalysisToolsComponentInstalled() Then

      If Not IsVS2008SP1Installed() Then

         MessageBox.Show("This add-in is going to crash :-(")

      End If

   End If

End If

Some details to implement those functions:

  • You can detect if VS 2008 SP1 is installed using the registry key:

– HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\VSServicing\9.0\VSTS\<locale>, name “SP” for VS 2008 Team Suite

– HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\VSServicing\9.0\VSTD<locale>, name “SP” for VS 2008 Development Edition

Where <locale> is the language of Visual Studio, such as 1033 for English, 3082 for Spanish, etc. Your add-in can get the locale of IDE using the DTE.LocaleID property.

The SP value can be 0 (no SP installed) or 1 (SP1 installed).

  • You can detect if VS 2008 Team Suite installed if the registry key “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Setup\VS\VSTS” exists.
  • You can detect if VS 2008 Development Edition installed if the registry key “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Setup\VS\VSTD” exists.
  • You can detect if the “Code Analysis Tools” component is installed getting the folder of VS 2008 (reading the “ProductDir” name under the registry key above), appending “Team ToolsStatic Analysis ToolsFxCop” and checking if the file FxCopSdk.dll exists or not.

Notes:

  • VS 2008 without SP1 lacks the folder “Team ToolsStatic Analysis ToolsFxCop” if Code Analysis Tools are not installed (as expected).
  • VS 2008 SP1 creates that folder even if you don’t have Code Analysis Tools installed, but it doesn’t add DLLs, just some RepositoryCompatibility folder with some XML files.

The strange case of toolwindow not showing when the add-in is loaded on startup

Visual Studio preserves the visibility state of its own toolwindows (Solution Explorer, etc.) but not of toolwindows created by add-ins. It is up to the add-in to store the state of its toolwindows when unloaded, and restore them when it is loaded again. So, some add-ins can show their toolwindows when loaded and not only when the menu to show them is invoked. However, some developers are noticing that in some cases toolwindows don’t show when the add-in is loaded on startup, but they show if the add-in is loaded by hand using the Add-In Manager. If this is the case, chances are that it is because you are not using the OnConnection method correctly and the IDE is not fully initialized when the add-in is trying to show its toolwindow:

HOWTO: Use correctly the OnConnection method of a Visual Studio add-in
http://www.mztools.com/articles/2008/MZ2008004.aspx

This is just one of the many side effects of a badly designed IDTExtensibility2 interface that populates the MSDN forum with related questions every week…

The strange case of add-in setup not detecting running instances of Visual Studio 2008 on Windows Vista

If you are creating a setup for your Visual Studio add-in, chances are that you don’t want running instances of Visual Studio when the add-in is going to be installed or uninstalled. For my MZ-Tools add-in, I use the free InnoSetup, which is script-based and uses Pascal for custom code, and I wrote an article some time ago about how to create a setup for a Visual Studio add-in using InnoSetup.

A couple of weeks ago I noticed something strange: when running the setup on Windows Vista, it detected running instances of Visual Studio .NET 2002, 2003 and 2005, but not of Visual Studio 2008. Actually, I detected the problem on Windows 2008 Server with the Visual Studio 2010 CTP, but I was able to reproduce the problem with Windows Vista and Visual Studio 2008.

The setup detects running instances of Visual Studio by using the GetActiveOleObject function for the ProgID of each Visual Studio version (“VisualStudio.DTE.7”, etc.):

function IsVSRunningByProgID(ProgID: String):Boolean;
var
IDE: Variant;
begin

try
IDE := GetActiveOleObject(ProgID);
except
end;

if VarIsEmpty(IDE) then
Result := False
else
Result := True
end;

The GetActiveOleObject function returns a running (if any) COM (ActiveX) server given a ProgId. Somehow it was failing for Visual Studio 2008 whose ProgId is “VisualStudio.DTE.9.0”. I tried to reproduce the problem with a VB6 program using the GetObject function, and it worked, but I soon realized that the GetObject function of VB6 always return an instance: if none is running, it creates one.

Incidentally, the setup worked as expected on Windows XP so I suspected that the User Account Control (UAC) of Windows Vista (and Windows Server 2008) could be the culprit. And the final detail was that while Visual Studio .NET 2002, 2003 and 2005 require by default admin rights (so you get a “consent prompt” from the UAC of Windows Vista), Visual Studio 2008 was designed to run without admin rights, so it launches without “consent prompts” on Windows Vista, running as a standard user even if you are an administrator. Searching on the InnoSetup forums, I confirmed that on Windows Vista a process running with elevated priviledges (such as my setup) cannot interact with a COM process running with low priviledges (such as Visual Studio 2008), so the GetActiveOleObject call fails (“Operation unavailable”) and no instance is returned, as if no instance was executing. In fact, the setup worked as expected if I run Visual Studio 2008 as an administrator (using the context menu) and getting the “consent prompt” of the UAC.

So, which is the solution for this problem? The forums mentioned something about mutexes or something that I am not willing to investigate, because sometimes when you devote a lot of time to a tough problem you realize that you don’t have a problem actually, or that it is not so severe. For example, an add-in can be installed perfectly even with Visual Studio running, it just needs to copy some files and add some registry entries. Its toolbar and menus won’t appear in the running instances of Visual Studio but if the user goes to the Add-In Manager, it will be there. There is only a problem when uninstalling the add-in, because removing the commands (and permanent UI if used) requires to persist the changes and if there is a running instance of Visual Studio the changes will be overwritten when this other instance is closed. But I guess I’ll have to live with that.

For applications that are not setups, such as applications automating the IDE (or for setups that allow you to execute .NET code), you can use System.Diagnostics.Process.GetProcessByName(“devenv”) and it will work.

The strange case of 8013141A loading a Visual Studio add-in

A developer posted a couple of days ago in the MSDN forum about Visual Studio Extensibility that loading his add-in caused and exception with error number <Unknown Error> (8013141A). Of course, searching with Google doesn’t always offer much information about these bizarre errors, nor the tools of the Windows SDK for which this error is, well, unknown too.

Since the section of my article about troubleshooting crashes in add-ins didn’t help much, I have enhanced it with further and more detailed explanations, and a mention to this error:

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

The strange case of empty Add-In Manager (not showing XML-based add-ins)

There is a problem that I have never experienced but it was happening for a few people in Visual Studio 2005 / 2008. The symptoms were:

  • The Add-In Manager is empty
  • The Add-In only shows registry-based add-ins, not XML-based add-ins (using an .AddIn file)

Of course the first difficulty was to notice that the problem happened to several add-ins, not only a specific add-in. When you don’t see your add-in in the Add-in Manager, the first thought is that your add-in is not correctly registered, specially because folders to put the .AddIn file are a bit tricky, as I explained in the article INFO: Default .AddIn file locations for Visual Studio add-ins (COM-registration is also tricky, BTW).

Using a file-monitoring tool like Process Monitor revealed that Visual Studio actually found .AddIn files, so there was no registration problem.

After almost one year with this problem unsolved, someone discovered yersterday the cause: a bad installation of MSXML 6.0, which apparently is used by Visual Studio to read the actual contents of the XML .AddIn files used by add-ins. After uninstalling MSXML 6.0 and installing the latest MSXML 6.0 SP1 the problem was solved. Here is the whole discussion thread with the problem:

VS 2008: Add-In Manager is empty
http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/6778e3a2-2783-4826-a5f2-7089e1c8fb90

I have updated my article:

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

I would be nice if Visual Studio showed an error message rather than failing silently when parsing .AddIn files, and better yet, used the XML parser of the .NET framework rather that depending on an external component.

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 strange case of “No such interface supported” (Error 80004002) loading a Visual Studio add-in

Some days ago I received an angry complaint from a prospect of the trial version of my MZ-Tools add-in, who uninstalled it because, somehow, he didn’t want the add-in loaded at startup during the evaluation period but he wanted to load it manually from time to time… Anyway, it happens that my MZ-Tools add-in still uses COM-registration because it shares code and setup with the versions for VS.NET 2002/2003, and therefore is subject to the couple of bugs of the Add-In Managers of VS 2008 and 2005. Of course the blame ended on the Microsoft side but too late, I’m afraid. It is unfortunate to lose sales because of these little problems… so today I started to investigate the migration from COM-registration to XML-registration for the versions of MZ-Tools for VS 2005 and 2008. And after some hours of internal refactoring needed, the .AddIn file created, I was ready to debug the add-in, when I got:

“No such interface supported” (80004002)”

How could that be? I have spent years creating add-ins for samples and I never got that error. A search in Google returned no useful information. At first I thought that it was related to the fact that I didn’t want my add-in, which is written in VB.NET, to have a root namespace (for those of you using C#, in VB.NET you can set a project-level property with the root namespace and avoid writing it in each code file), because I don’t want my commands to be of the form “MZTools.Connect.MyCommand” but of the form “MZTools.MyCommand”, which is possible as I explained in this article.

After some minutes investigating, I discovered that my AssemblyInfo.vb file has the ComVisible attribute set to False, instead of the default True that the add-in wizard creates:

<Assembly: ComVisible(False)>

because it doesn’t make sense to expose to COM the classes of an add-in, except the Connect class. And here was the problem: while I had the <ComVisible(True)> attribute attached to the Connect class, when I removed the <Guid(…)> and <ProgId(…)> attributes, which are not required for XML-registration, I removed too the <ComVisible(…)> attribute, because I thought that it was not required for XML-registration, but it happens that it IS required, go figure! I think we’ll never get rid of COM in Visual Studio extensibility in a million of years, no matter how hard Microsoft tries to disguise it…

The strange case of System.BadImageFormatException: Could not load file or assembly ‘Microsoft.mshtml’

A couple of days ago another customer of my MZ-Tools add-in reported this exception:

“System.BadImageFormatException: Could not load file or assembly ‘Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The module was expected to contain an assembly manifest.”

The GAC (C:\Windows\Assembly folder) showed the file with the correct version and public key token, so what could it be?

As you may know, what you see in the Windows Explorer when you go to the C:\Windows\Assembly folder is not exactly the contents of that folder but a shell, and fortunately I am old enough to know the old MS-DOS commands to see the actual contents of a folder:

  • Click the Start, Run… menu
  • Type CMD and enter to open a MS-DOS window
  • Type CD C:\Windows\Assembly (CD stands for Change Directory)
  • Type DIR to list the contents
  • Type CD GAC
  • Type DIR to list the contents
  • Type CD Microsoft.MSHtml
  • Type DIR to list the contents
  • Type CD 7.0.3300.0__b03f5f7f11d50a3a
  • Type DIR to list the contents
  • You should get something like (it is in Spanish but I have marked in bold the relevant information):

El volumen de la unidad C no tiene etiqueta.
El número de serie del volumen es: 88B8-2ADF

Directorio de C:\WINDOWS\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a

22/11/2007  11:16    <DIR>          .
22/11/2007  11:16    <DIR>          ..
22/11/2007  11:08         8.007.680 Microsoft.mshtml.dll
22/11/2007  11:16               207 __AssemblyInfo__.ini
2 archivos      8.007.887 bytes
2 dirs  16.842.235.904 bytes libres

So, the size of Microsoft.mshtml.dll should be 8.007.680 bytes, but for the customer was 0 bytes, so there was a file corruption. A repair of Visual Studio didn’t solve the problem so he had to delete the file with the command DEL Microsoft.mshtml.dll and then with a good copy of the file install it in the GAC (you can use the gacutil.exe command-line utility or drag and drop the file using the Windows Explorer).