The strange case of System.IO.FileLoadException: mixed mode assembly is built against version ‘X’ of the runtime and cannot be loaded in the 4.0 runtime

One of the customers of my MZ-Tools 6.0 for Visual Studio .NET add-in reported some days ago that the setup was showing the following error when installing MZ-Tools for Visual Studio 2010 (RC) (it worked fine for other IDE versions):

“The assembly ‘VSLangProj80, version 8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ should be present in the Global Assembly Cache (GAC) but it has not been found there, maybe the uninstallation of some other product remove it”

It happens that it is not clear for some people (even within Microsoft) that EnvDTE.dll, VSLangProj,dll, etc. should not be included in the setup of Visual Studio add-ins, so some people were including those dlls in their add-in setups, with the undesired consequence that somehow those dlls were being removed from the GAC when uninstalling some add-ins. When I got tired of bug reports related to this, I made the setup of my add-in to check the existence of some required Visual Studio assemblies such as EnvDTE.dll, etc. and to provide the customer with a procedure to restore them (omitted for brevity in the message above) copying them from the Visual Studio folders to the GAC.

So, I got my customer to check the VSLangProj80.dll in the GAC and… it was there. Then I noticed that VSLangProj80.dll has a dependency on VSLangProj2.dll that the setup was not checking. But that dll was also in the GAC. Then I noticed that to check the existence of a DLL in the GAC my setup was trying to load the dll using System.Reflection.Assembly.Load(assemblyName) and if the load failed with any exception, then it assumed that the assembly was not in the GAC. So I guessed correctly that the error message was misleading, I changed the setup to show the message above only if the exception was a System.IO.FileNotFoundException, and to show the actual exception otherwise. Then we got this other error:

“System.IO.FileLoadException: Mixed mode assembly is built against version ‘v1.0.3705’ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information”

Then I learned what a “mixed mode assembly” is and the useLegacyV2RuntimeActivationPolicy attribute that needs to be used in a .config file to fix that issue in CLR 4.0, but I will let Mark Miller (Marklio) to explain it in full detail and to the MSDN documentation the short version.

There is something that I haven’t solved yet and it is why I was unable to reproduce the problem on my computer when the .config file didn’t have yet that attribute, but anyway the problem was solved for my customer.

The strange case of .wixproj cannot be opened because its project type is not supported by this version of the application

Today I installed the latest 3.0 version of the Windows Installer XML (WiX) toolset (3.0.5419.0), which integrates with both Visual Studio 2005 and 2008 and provides a new project type and project template to create WiX setups. When I clicked the File, New Project menu, WiX project type, it worked fine in VS 2005. However, it caused the following error in VS 2008:

“.wixproj cannot be opened because its project type is not supported by this version of the application. To open it, please use a version that supports this type of project.”

After searching the web for a while to no avail, I finally noticed that this problem was caused because my shortcut to VS 2008 included /SafeMode after devenv.exe. When the shortcut didn’t include that command-line switch, it worked fine. That switch disables the Add-In Manager and prevents add-ins and 3rd party packages (such the WiX one) being loaded. I had it because I have my MZ-Tools add-in marked to load on startup (to avoid loading it by hand through the Add-In Manager each time I debug it), but I don’t want it to be loaded the very first time that I open VS to load its project, to avoid the problem PRB: ‘Could not copy temporary files to the output directory’ error building Visual Studio .NET add-in. Another way to prevent it is to press the left Shift key while VS is started, but that approach doesn’t work well on Windows 7 and VS 2010 will not support it, as explained in the article, so using /SafeMode will be the only approach.

Now, it would be nice if VS showed a more helpful message such as:

“.wixproj cannot be opened because its project type belongs to a 3rd party package that is not allowed to load when the Visual Studio process (devenv.exe) is launched with the /SafeMode switch.”

Creating setups for Visual Studio add-ins using Windows Installer XML (WiX)

Although as I have posted many times I personally use and recommend the free InnoSetup script-based tool to create the setup of my MZ-Tools family of add-ins (see HOWTO: Create a setup for a Visual Studio 2005 / 2008 add-in using Inno Setup), there are people who prefer MSI-based setups.

The tricky part of installing XML-based add-ins is always to decide where to put the .AddIn file (see INFO: Default .AddIn file locations for Visual Studio add-ins) and then to modify the <Assembly> value to point to the location where the user has decided to install the add-in dll (typically in the C:Program Files folder). This second part is always omitted from the Microsoft documentation and posts, because it requires a custom action, which is complicated because it requires code.

For this purpose, Windows Installer XML (Wix) greatly simplifies the task. WiX is a toolset that builds Windows installation packages from XML source code. Although I haven’t started to play with WiX yet, I have found that Alex Shevchuk has a great article series about moving from MSI to WiX, and specially interesting is the part 25 about updating XML files using XmlFile, which can be used to change the <Assembly> value.

I will try to find time to write a HOWTO article about this some day, but meantime, if you are interested, you can download the VS 2008 SDK 1.1 and go to the file C:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioTeamSystemIntegration\Test Tool Extensibility\VsIdeHostAdapter\Installer\VsIdeTestHost.wxs, which uses this approach (bold line):

<!-- Directories -->
<DirectoryRef Id="TARGETDIR">
   <!-- One of the per-machine directories Visual Studio searchings for .Addin files -->
   <Directory Id="CommonAppDataFolder">
      <Directory Id="MSCommonAppData" Name="MS" LongName="Microsoft">
         <Directory Id="MSEnvCommonAppData" Name="MSEnvSH" LongName="MSEnvShared">
            <Directory Id="DIR_ADDINS" Name="Addins" />
         </Directory>
      </Directory>
   </Directory>
   <!-- VS install dir replaced by RegistrySearch -->
   <Directory Id="VSINSTALLDIR" Name="VS2005" />
</DirectoryRef>

<!-- Components: files and registry entries -->
<DirectoryRef Id="DIR_ADDINS">
   <Component Id="C_VsIdeTestHostAddinXml" Guid="$(var.C_VsIdeTestHostAddinXml_Guid)">
      <Condition>VSIDETESTHOST_TEAMSUITE OR VSIDETESTHOST_TEAMDEV OR VSIDETESTHOST_TEAMTEST</Condition>
      <File Id="VsIdeTestHostAddinFile" Name="HAAddin.ADD" Vital="yes" DiskId="1" LongName="$(var.AddinName).AddIn" Source="$(var.InstallerSources)\VsIdeTestHost.AddIn" />
      <XmlFile Id="AddAssemblyElement" Action="setValue" File="[#VsIdeTestHostAddinFile]" ElementPath="/Extensibility/Addin/Assembly" Value="[#VSIdeAddinDllFile]" Sequence="1" />
      <XmlFile Id="AddinNameElement" Action="setValue" File="[#VsIdeTestHostAddinFile]" ElementPath="/Extensibility/Addin/FriendlyName" Value="$(var.AddinName)" Sequence="1" />
   </Component>
</DirectoryRef>

BTW, notice that the sample uses the “CommonAppDataFolder” variable, which is localized on Windows, while Visual Studio has a bug hardcoding the English name (%ALLUSERSPROFILE%\Application Data\Microsoft\MSEnvShared\AddIns) so the sample doesn’t work on non-English machines, as explained in the article INFO: Default .AddIn file locations for Visual Studio add-ins.

Tricky bugs in the new WPF-based shell of Visual Studio 2010

One of the things that I provide in my add-ins is that modal windows are 1) resizable and 2) with memory (that is, remembering the last size used by the user). I am passionate about user interface usability and I hate modal windows that are not resizable in today’s big screens, such as the Tools, Options window of Visual Studio. I know this is so because of historical reasons (MFC stuff or similar), but after 8 years and five Visual Studio releases (including a new WPF-based shell) you are still forced to scroll, despite you may have a big display… some new stuff like the windows related to data sources are resizable (they are implemented in .NET where resizing is more easy). I also hate the windows that are resizable, but the programmer didn’t take the extra step to persist the size when the window is closed, so the user must resize it each time that the window is opened…

Anyway, I have special code for all that stuff that resizes and centers the window before is shown, and while doing some testing with VS 2010 I noticed that something was wrong when the VS 2010 IDE was maximized because the window(s) of my add-in didn’t show centered. Finally I isolated the bug and it happens that DTE.MainWindow.Width property of the new WPF-based VS 2010 shell can return a wrong result if you maximize the IDE window by hand.

Here it is the acknowledged bug:

DTE.MainWindow.Width or DTE.MainWindow.Height don’t return correct size when IDE maximized by hand
https://connect.microsoft.com/VisualStudio/feedback/details/536703/dte-mainwindow-width-or-dte-mainwindow-height-dont-return-correct-size-when-ide-maximized-by-hand

Interestingly, it works fine if you resize the main window by code (and not by hand), so tricky and subtle are the bugs introduced by the new WPF-based shell.

Since I didn’t have any hope of getting this kind of bugs fixed for the RTM, I was able to workaround the problem in the add-in.

MZ-Tools 6.0 now supporting Visual Studio 2010 Release Candidate

I updated my MZ-Tools 6.0 add-in to support Visual Studio 2010 Release Candidate and finally today March 1 I have released it.

Microsoft finally fixed most of the bugs that I have been reporting in the last months in the WPF-based commandbars so add-ins can get loaded in the IDE without crashing and AFAIK I was able to workaround all the issues that were not fixed (and won’t be in the RTM).

FWIW, some technical details:

– Internally this MZ-Tools build is compiled (using VS 2008) against .NET Framework 2.0 / CLR 2.0 and not the .NET Framework 4.0 / CLR 4.0 that VS 2010 uses (and the only that ships), but it works fine AFAIK.

– Although this MZ-Tools 6.0 build ships several assemblies (one for each VS IDE) for historical reasons (it still supports VS.NET 2002/2003), I have done tests for future versions and it seems to be possible to build a single assembly in .NET Framework 2.0 / CLR 2.0 that targets VS 2005, 2008 and 2010, using references provided by VS 2005 (that are also available in next VS versions) or using Reflection for references whose version changes between IDE versions (I think that you can use assembly redirections too).

VS 2010 and the macros IDE

Although not very usual, add-ins can be created for the Macros IDE too. In fact, version 6.0 of MZ-Tools integrates with the VS IDE and with its macros IDE. I will remove support for the macros IDE in future versions because I think that nobody needs/uses it and it complicates the code and the setup (specially the uninstallation), but until then, it works with both IDEs.

While the VS IDE executable is devenv.exe, the macros (VSA) IDE is vsaenv.exe. From the automation (EnvDTE) point of view, the EnvDTE.DTE class has the EnvDTE.DTE.MacrosIDE() As EnvDTE.DTE property.

Until VS 2010, each VS IDE has its own macros IDE with matching versions. However, VS 2010 (VS 10.0) actually uses the VS 2008 Macros IDE (VSA 9.0), as you can see by the look and feel (not WPF-based) and in the About window.

No longer possible to create comboboxes on commandbars of VS 2010 through automation (EnvDTE), only through packages

Joginder Nahil (from Starprint Tools) has notified me about a breaking change that I was not aware in the new WPF-based commandbars of VS 2010: the lack of support to create comboboxes on commandbars. I have been fortunate enough to avoid the need to use that UI item in my MZ-Tools add-in (I haven’t even written an article about this), but I was aware that comboboxes and MRU lists were possible since VS 2005 because of this old post of Craig Skibo (former member of the automation team of Visual Studio):

Command Bar Types – Part 2
http://blogs.msdn.com/craigskibo/archive/2005/10/20/483133.aspx

Now, in VS 2010 comboboxes are no longer creatable through automation (EnvDTE), only through packages (SDK). Here is the report:

Exception DeprecatedException occurs when adding a combobox to vs2010 IDE toolbar
https://connect.microsoft.com/VisualStudio/feedback/details/532817/exception-deprecatedexception-occurs-when-adding-a-combobox-to-vs2010-ide-toolbar

Thanks Joginder, and I am sorry the bad news.

Getting properties from the DTE.Properties collection

I have updated an article that I wrote back in 2005:

HOWTO: Getting properties from the DTE.Properties collection of Visual Studio .NET.
http://www.mztools.com/articles/2005/MZ2005008.aspx

And the reason is that I have found lately that guessing the names of properties to index DTE.Properties(category, page) is not as easy as reading the MSDN documentation (whose list may not be up-to-date) or using regedit.exe to inspect the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\<version>\AutomationProperties registry entry. Specifically I have found that:

– There is no way through automation (EnvDTE) to get the C# formatting options that were introduced by VS 2005.

– Text Editor XAML settings are not exposed through DTE.Properties in VS 2008 but they are in VS 2010 (something that the MSDN docs don’t reflect yet and I doubt they will)

– Text Editor XOML settings are not exposed through DTE.Properties even in VS 2010.

I guess that some SDK service can get that information, or maybe it is something not exposed by the owner package of those settings. So I am using the other way, which is to read directly the actual property values from the HKEY_CURRENT_USER hive. But it is also tricky, because the term “TextEditor” can become “Text Editor”, “PlainText” can become “Plain Text” and the C# formatting settings seem to be updated only when VS closes and not when the Options dialog is closed (and they seem to appear only if they differ from the defaults)…

Different template names for text files in C# and VB.NET to use with Solution2.GetProjectItemTemplate

When you execute the following macro that gets the file templates for classes, forms and text files in C# and VB.NET:

Sub Macro1()

   Dim objSolution2 As EnvDTE80.Solution2

   objSolution2 = CType(DTE.Solution, EnvDTE80.Solution2)

   MsgBox(objSolution2.GetProjectItemTemplate("Class.zip","VisualBasic"))
   MsgBox(objSolution2.GetProjectItemTemplate("Form.zip", "VisualBasic"))
   MsgBox(objSolution2.GetProjectItemTemplate("Text.zip","VisualBasic"))

   MsgBox(objSolution2.GetProjectItemTemplate("Class.zip", "CSharp"))
   MsgBox(objSolution2.GetProjectItemTemplate("Form.zip", "CSharp"))
   MsgBox(objSolution2.GetProjectItemTemplate("Text.zip", "CSharp"))

End Sub

It fails for the 6th case:

objSolution2.GetProjectItemTemplate("Text.zip", "CSharp")

I thought it was a bug but it happens that the symmetric beauty of the code is broken because the actual name for the C# case is “TextFile.zip”, not  “Text.zip”:

objSolution2.GetProjectItemTemplate("TextFile.zip", "CSharp")

It seems that C#/VB.NET parity didn’t reach this point yet 😉

VS 2010 RC problems with CommandBar.RowIndex to position toolbars

These are two “minor” bugs that the new WPF-based commandbars of Visual Studio 2010 are going to have since won’t be fixed in this release:

VSIP: VS 2010 Dec LCTP: toolbar with CommandBar.RowIndex = -1 not created in new row
https://connect.microsoft.com/VisualStudio/feedback/details/518455

VSIP: VS 2010 Dec LCTP: CommandBar.RowIndex of toolbar not updated after creating and making it visible
https://connect.microsoft.com/VisualStudio/feedback/details/518452

If your add-in uses more than one toolbar, it can affect you. I found a workaround using big values for the RowIndex property rather than -1 to ensure that the toolbars appear below existing toolbars.

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