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 OnConnection method and ext_ConnectMode.ext_cm_UISetup of Visual Studio add-ins

Without doubt, the most confusing area each newbie add-in developer faces when starting to write an add-in for Visual Studio, is the OnConnection method and the  ext_ConnectMode.ext_cm_UISetup value of the connectMode parameter. I think that every week I answer at least one question about this in the MSDN forums. There are several things contributing this confusion:

  • It is not intuitive that you have commands, and you have buttons, and that while commands should created only once in the lifetime of the add-in to preserve keyboard shortcuts, etc. (and they should not be recreated each time that the add-in is loaded), buttons can be recreated or not, depending on whether you are using a permanent user-interface approach, or a temporary user-interface approach. These approaches are not well documented in the MSDN docs.
  • The ext_ConnectMode.ext_cm_UISetup is used by the OnConnection method, and since the OnConnection method (as its name implies) is called each time the add-in is loaded, it gives the impression that the ext_ConnectMode.ext_cm_UISetup flag is passed also each time the add-in is loaded, while in fact it is not passed each time, only the very first time (if you think otherwise, wait until the following bullet). The ext_ConnectMode.ext_cm_UISetup mode would deserve its own OnUISetup mehod rather than sharing the OnConnection method, as I explained in my post Regarding the IDTExtensibility2 interface.
  • In one of those decisions that cause more harm than good, in VS 2005 Microsoft added the /resetaddin command-line flag to the devenv.exe process in the project properties window of an add-in project to get a new ext_ConnectMode.ext_cm_UISetup phase each time that the add-in is debugged, creating the (false) impression that each time that the add-in is run, you should get an ext_ConnectMode.ext_cm_UISetup phase, and therefore the forums are populated with questions like “my add-in works on my machine, but not when I run it on other machine”, or “my add-in works on Windows XP, but not on Vista”, or “my add-in works when debugging it, but not when it runs standalone”, or “my add-in seems to work sometimes, but it seems that never on Mondays” and the like 🙂

So, if you have reached this post searching for a solution for your OnConnection/ext_ConnectMode.ext_cm_UISetup problem, please read the following article of mine and the related ones at the end of it three or four times, without skipping a line of them, and then read the code samples, and then create a couple of add-ins with either approach in the samples, and then run them within Visual Studio to check that they work, and then run then outside Visual Studio, and then create a setup and run them on another machine, and all this will take you an hour or two, but you will fully understand how it works and how it doesn’t work, and why, and then you can return to the faulting code of your original add-in and it should be crystal clear for you what’s wrong 🙂

HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in
http://www.mztools.com/articles/2005/MZ2005003.aspx

More on the build configuration automation model

I already wrote about the convoluted build configuration automation model and provided a visual representation of it to help understanding it. One of the problems that I explained is that the configurations of solutions are modeled as a collection rather than as a 2-D matrix (configuration names and platforms), as it happens with project configurations, which are modeled correctly. While this problem wouldn’t be as bad once you understand it, it gets worse when you want to do some natural things such as manipulating solution platforms and it has been raised in this post of the MSDN Forum about Visual Studio Extensibility:

  • When you delete an EnvDTE.SolutionConfiguration from the DTE.Solution.SolutionBuild.SolutionConfigurations, you get actually more than one solution configuration deleted. This must be the first case in computing when deleting an item of a collection, it actually deletes more than one… You can test it with this macro and a solution with two configuration names (“Debug” and “Release”) and two platform names (“Any CPU” and “Itanium”, for example):
Sub Configs()

   For Each objConfiguration2 As EnvDTE80.SolutionConfiguration2 In DTE.Solution.SolutionBuild.SolutionConfigurations

      MsgBox(objConfiguration2.Name & "/" & objConfiguration2.PlatformName)

   Next

   DTE.Solution.SolutionBuild.SolutionConfigurations.Item(1).Delete()

   For Each objConfiguration2 As EnvDTE80.SolutionConfiguration2 In DTE.Solution.SolutionBuild.SolutionConfigurations

      MsgBox(objConfiguration2.Name & "/" & objConfiguration2.PlatformName)

   Next

End Sub

You get four configurations initially and only two after deleting one. This is so because deleting a solution configuration from the collection actually deletes all the ones with the same configuration name, regardless the platform!!!. Of course, it doesn’t make sense to delete an item from a 2-D matrix, it only makes sense to delete items in the axis (configuration names or platform names).

  • But it gets worse: you can’t delete solution configurations by platform name because of the previous behavior. Maybe the SDK was the solution, so I checked the Visual Studio 2008 SDK in the MSDN site, and it states that: “There are no VSIP interfaces to create solution configurations programmatically. There are no VSIP APIs for editing the solution configurations. You must use DTE.SolutionBuilder. For more information, see Automation Model. However, there are VSIP APIs for managing the solution build. For more information, see IVsSolutionBuildManager2.”. So, if you can’t create solution configurations names or platforms programmatically using the SDK, you can’t delete them too, I guess. You are pointed to the DTE.SolutionBuilder, as if such thing exists in the automation model (it refers to the DTE.SolutionBuild) that, as we have seen, it doesn’t allow you to delete solution configuration platforms.

As I pointed in the original post, you can actually create solution configurations or platforms by creating project configurations and platforms and propagating them to the solution level (last parameter of EnvDTE.SolutionManager.AddConfigurationRow and EnvDTE.SolutionManager.AddPlatform). But there is no “propagation” when deleting them at project level, so I guess that there is actually no way to delete solution platform names. The closest thing that you can do with automation is to iterate the solution configurations to warn the user the platforms that are not allowed to make her to delete them by hand.

Visual Studio 2005/2008 managed add-ins using XML registration (.AddIn file) and unmanaged satellite DLLs

In my last entry I mentioned that I was investigating to use XML registration (.AddIn File) with my MZ-Tools add-in. Finally I was unable because it seems that Visual Studio 2005/2008 managed add-ins using XML registration don’t support unmanaged satellite DLLs (created with C++) for custom pictures for commands. The .AddIn file doesn’t support the SatelliteDllName and SatelliteDllPath tags whose equivalent entries in the Windows registry are used for addins using COM registration. For add-ins using XML registration, it seems that you need managed satellite DLLs (.resx file that generates a .resources file) that don’t need XML tags to be located. Of course this complicates the scenario if your add-in needs to support VS.NET 2002/2003 with the same code base, because you need an unmanaged satellite DLL for VS.NET 2002/2003 and a managed satellite DLL for VS 2005/2008. So, I will keep using the COM registration and unmanaged satellite DLLs for all versions.

I don’t understand this restriction, since COM/XML registration has nothing to do with satellite DLLs. The .AddIn file could have happily supported the SatelliteDllName/SatelliteDllPath tags for unmanaged satellite DLLs to ease backwards compatibility, but now it is too late and the damage is done.

MSDN: Walkthrough: Creating Managed Satellite DLLs
http://msdn.microsoft.com/en-us/library/e9zazcx5.aspx

Huizhong Long’s WebLog: Displaying custom bitmap for VS add-in command button from satellite DLL
http://blogs.msdn.com/hlong/archive/2005/09/27/474522.aspx

All that said, I really hate satellite DLLs (managed or unmanaged), they should be totally unnecessary to provide custom pictures, and I would like to get rid of them:

Microsoft Connect: Custom pictures for commands using icons without satellite DLLs
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=114769

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 ProjectItem.FileCodeModel and conditional compilation

Recently I was playing with the FileCodeModel of a ProjectItem that used conditional compilation to provide some methods in “Debug” configuration (but not in “Release” configuration) such as:

Public Sub Method1()
...
End Sub

#If DEBUG Then
Public Sub Method2()
...
End Sub
#End If

Public Sub Method3
...
End Sub

Which code elements (methods) would return the FileCodeModel in such case when the active configuration is “Release”? It would honor the conditional compilation? It happens that yes, for the “Release” configuration the FileCodeModel returns methods #1 and #3, but not method #2. Is that good or bad? I tend to think that most of the time you will want that behavior. For example, if you are writing an add-in to review code elements (for dead code, etc.), you only want to deal with code elements that actually exist for your current configuration. In other scenarios this is not so good. For example, if you are writing a feature to sort code elements (by name, scope, etc.) you don’t want to leave methods out. But overall I think that Microsoft did it right honoring the conditional compilation.

Regarding the IDTExtensibility2 interface

I have always wondered why the IDTExtensibility2 interface of the Visual Studio host to load (or connect) add-ins is not as simple as just two methods: OnLoad and OnUnload, or if you like the “connection” term, just the OnConnection and OnDisconnection methods. The original IDTExtensibility interface of Visual Basic 5/6 from 1997/1998, which offered four methods (OnConnection, OnDisconnection, OnAddInsUpdate and OnStartupComplete), rather than being simplified in the transition to VS.NET 2002, got a new life as IDTExtensibility2, with even a new method (OnBeginShutdown).  All of them seem totally unnecessary to me, let see why:

  • OnAddInsUpdate: this is perhaps the most useless method. I have yet to see an add-in that makes some use to it. Anyone? It’s good that you can access other add-ins from yours using the DTE.AddIns collection, and even that you can unload some add-in using the AddIn.Connected property (long time ago my MZ-Tools add-in had to unload a conflicting add-in before an operation to avoid a crash and reload it afterwards), but there is no much need to get notified when an add-in is loaded/unloaded. If there is, some event in the DTEEvents class would be better than a method of an interface that you have to empty-implement.
  • OnStartupComplete: this method is called when the add-in is loaded on startup and the IDE is fully initialized (because when the OnConnection method was called, it was not fully initialized). I have yet to see an add-in that needs to behave differently when it is loaded on startup, or sometime later through the Add-in Manager, or that wants to do something before the IDE is not fully initialized. The MSDN documentation states:

    “On occasion, OnConnection does not occur correctly, such as when an add-in is loaded, but a component required by an add-in has not yet loaded. This is unusually due to the fact that Visual Studio has not yet started completely.”.

    In such case I would prefer my OnConnection method to be called when the IDE is fully loaded, not before that. The behavior of OnConnection / OnStartupComplete is so confusing that I had to write an article to show how to do it right, tired of seeing wrong code in the forums.

  • OnBeginShutdown: this is another useless method. The MSDN documentation states:

    “Although a shutdown of Visual Studio might be canceled, the OnBeginShutdown method cannot be canceled. As a result, add-ins should assume that all shutdown events occur and perform any cleanup routines accordingly.”.

    So, when Visual Studio thinks it is going to shutdown, it calls this method and your add-in has to cleanup. What is going to do then when it receives the OnDisconnection call?. But wait! The shutdown could be cancelled (for example, if there are dirty documents, the user is prompted to save them and she cancels), but, alas, your add-in already did the cleanup…  I don’t see the point. Either this method is useless, or at the very least it should be called when the IDE is totally sure that it is going to shutdown (after giving the user the last chance to cancel, to begin with).

BTW, the ext_ConnectMode.ext_cm_UISetup flag of the OnConnection method is so special, the add-in is loaded (or connected) for such a special purpose (to create the commands and permanent user interface of the add-in) that it truly would deserve its own OnUISetup method.

So, if correct initialization/shutdown of add-ins is so tricky, it is no wonder that developers entering the Visual Studio automation world find it so hard.

FWIW, Microsoft recognized this need of simplification in the new managed add-in models for Microsoft Office using Visual Studio Tools for Office (VSTO) 2005 (see the Startup/Shutdown events in VSTO 2005), or in the new IManagedAddIn interface of Office 2007 with its Load/Unload methods. I am not familiar with those models but seeing the docs you realize that you have to deal with just one event on load and just one event on unload. A good step in the right direction.

MZ-Tools Articles Series: BUG: Standard user unable to load/unload COM-based add-ins registered for all users with the VS 2008 Add-in Manager on Windows Vista

Almost a couple years ago I wrote an article The Add-In Manager of Visual Studio 2005 got broken…and won’t be fixed for SP1 and while Visual Studio 2008 fixed that problem, it has introduced a new one when running on Windows Vista, and guess what, VS 2008 SP1 doesn’t fix it either, so I guess we will have it until the next version of Visual Studio… Again, the problem happens with COM-based add-ins, not with add-ins using a .AddIn XML file. I guess that most developers of commercial add-ins still need to support Visual Studio .NET 2003 (my MZ-Tools add-in even supports Visual Studio .NET 2002) and they may want to use a single code base for the code and the setup, so they still use COM registration for add-ins for Visual Studio 2005/2008 (at least this is my case), so it would be good to get this bug fixed.

Here is the article explaining the bug:

BUG: Standard user unable to load/unload COM-based add-ins registered for all users with the VS 2008 Add-in Manager on Windows Vista
http://www.mztools.com/articles/2008/MZ2008025.aspx

And here you have the bug report on the Microsoft Connect web site to vote for it:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=365846

MZ-Tools Articles Series: HOWTO: Using the Process Monitor (ProcMon) tool to diagnose Visual Studio add-ins problems

Last year I wrote a quite popular article HOWTO: Troubleshooting Visual Studio and Office add-ins, to diagnose many common problems with add-ins for Visual Studio or even Office. One invaluable tool to diagnose a whole range of problems with an add-in setup or the Add-In Manager of Visual Studio is the Process Monitor (ProcMon) tool, formerly developed by SysInternals and now part of Microsoft Technet. My MZ-Tools add-ins for Visual Studio (all versions), VB6, VB5 and VBA are installed and registered smoothly for tons of users every week, but from time to time I get a support incident about the setup failing due to something wrong on the user machine and I diagnose the problem requesting the user to run the tool and sending the trace back to me. While the Process Monitor tool applies to any developer, not just add-in developers, not everybody is familiar with it, so I wrote this article to explain how to use the tool and to refer my users to it. As an example, I will show why Visual Studio 2008 fails to recognize .addin files when stored in the folder “%ALLUSERSDOCUMENTS%\Microsoft\MSEnvShared\AddIns” that was introduced by Visual Studio 2008.

HOWTO: Using the Process Monitor (ProcMon) tool to diagnose Visual Studio add-ins problems
http://www.mztools.com/articles/2008/MZ2008024.aspx

MZ-Tools Articles Series (update) INFO: Default .AddIn file locations for Visual Studio add-ins

I have updated the article that I wrote back in January about default folders to place .AddIn registration files for add-ins to include actual examples for Windows Vista since the original article only showed Windows XP examples. I have also provided better information about how to get the actual folder names correctly.

Overall the naming of Windows Vista folders is perfect because:

  1. It doesn’t localize folder names
  2. It uses meaningful names such as:
    • “C:\Users\<username>\AppData\Roaming” while Windows XP used “C:\Documents and Settings\<username>\Application Data” (how do you remember that it is roaming?)
    • “C:\Users\<username>\AppData\Local” while Windows XP used “C:\Documents and Settings\<username>\Local Settings\Application Data”

but because of backwards compatibility with Windows XP it uses junction points and all this folders stuff is really a mess. Anyway, the updated article:

INFO: Default .AddIn file locations for Visual Studio add-ins
http://www.mztools.com/Articles/2008/MZ2008001.aspx

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