The strange case of System.InvalidOperationException: “Loading of the ImageList did not succeed”

In the last months, I have had two or three reports of the users of my MZ-Tools extension about this exception:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Loading of the ImageList did not succeed.
 at System.Windows.Forms.ImageListStreamer..ctor(SerializationInfo info, StreamingContext context)
 --- End of inner exception stack trace ---

With a full trace that is included in this StackOverflow question with the same problem.

Incidentally, I had seen that exception very sporadically in the last tests of a session of integration tests of MZ-Tools.

For Visual Studio, MZ-Tools has more than 3,000 integration tests (most of them reproduce user actions such as setting options, executing commands and getting results in code or in treeviews, etc.). It is my experience that no version of Visual Studio has been able to run all the tests without crashing due to out of memory errors, etc. so I tend to run them in sets of 500-800 tests, restarting Visual Studio after each session. In this scenario, I have never seen the exception above.

For VB6 and VBA, on the other hand, there are “only” 1,500+ integration tests, and both IDEs are very capable of running all of them in a single session (and much faster than Visual Studio). In this case, I have seen the exception in the last tests but very rarely. So, I finally decided to investigate this issue.

There is little information on the web about this exception with the ImageList. Some old MSDN KB articles mention problems with the ImageList and leaks:

FIX: ImageList Class Leaks GDI objects (for .NET Framework 1.0)

Memory usage increases for a .NET Framework 2.0-based application when you use the ImageList.ImageCollection.Item property to obtain an image or when you call the ImageList.ImageCollection.GetEnumerator method.

I am using .NET Framework 2.0 but it is fully patched. Since the problem could be related to GDI objects leaks, I used theTask Manager to check it:

TaskManager

To add the GDI Objects column you need to right-click on the column header and then select it on the list:

TaskManagerColumns

Then I ran the 1,500+ integration tests in Excel while watching the GDI Objects counter and, to my surprise, the counter increased and increased, never releasing objects. So, there is a GDI object leak somewhere that I will investigate in the next days. I don’t know yet if this is the same cause for the users of my extension (it could be that they use the IDEs for very long periods of time without restarting) but certainly I have now a a GDI object leak to find.

The strange case of localized resources not being loaded

For many years I have used a custom localization approach for my MZ-Tools add-in: instead of using .resx files, I used a single embedded .xml document which had nodes for each term, and in turn each one had children nodes for each language (I currently provide six languages). Then I had some functions to retrieve the required term in the desired language. This approach has some advantages, such a centralized source of resources for localization, less size at run-time, and a simplified setup with no resource dlls to deploy (I am aware that *.resources.dll files can be embedded too, but the approach is tricky).

Recently I wanted to use a web-based platform for localization, and to use .resx files which are the “standard” approach for localization. There are also 3rd party extensions such as ResXManager that allows you to manage localized resources in a centralized way using a grid. For the web platform I decided to use OneSky (it’s great and it allows up to 5 users for free). On this platform you can use tons of formats to upload/download the resources to localize, including of course .resx files. So, finally I had all changes made and a new setup that deploys all the *.resources.dll files:

Resources

The localization worked during development, however it failed when installing the extension with the setup. The MZ-Tools add-in failed for VBA/VB6/VB5, it also failed for VS 2005-2010, and the MZ-Tools package also failed for VS 2012-2015. The strings were always shown in English, the default language. Why? I suspected it was somehow related to obfuscation, which I use in the “Release” configuration (used by the setup) but not in the “Debug” configuration (used during development). Using .NET Reflector I didn’t notice anything wrong with the deployed *.resources.dll files. So, I thought about replacing the installed obfuscated main dll by the original one before obfuscation, but before I had to disable strong name verification because at “Release” configuration you need to use delay signing to use obfuscation, and re-sign after obfuscation. To disable strong name verification you have to execute:

sn.exe –Vr *,<public key token>

Suddenly, before replacing the main dll, all worked. So, the problem was that the *.resources.dll files were using delay signing and .NET was refusing silently to load them. I guess that using the Assembly Binding Log Viewer (fuslogvw.exe) would have revealed this. By the way, you can know if a .NET assembly is using delay signing or not (even if it is set to skip strong name verification) using:

sn.exe –vf <assembly>

So, when a Visual Studio project is set to use delay signing, not only its main output assembly but also its *.resources.dll files lack the strong name, and the build process that you use to sign again the main assembly must re-sign also its *.resources.dll files.

Build 2016 sessions of interest for Visual Studio Extensibility developers

In the past Microsoft Build 2016 conference a few weeks ago there were a couple of sessions that were of interest to VSX developers:

In the first one, “Visual Studio 2015 Extensibility”, Mads Kristensen “writes an extension from scratch live on stage, then integrates with GitHub, automates the build process and deploys the finished extension to the Visual Studio Marketplace”. I enjoyed it a lot and learned some things that I didn’t know. I encourage you to see it:

The second one is “The Future of Visual Studio”, by Amanda Silver. While this session doesn’t talk about VSX, it contains some good news: the new version of Visual Studio “15” will take much less time to install, like 180 seconds a minimal installation thanks to a new “streamlined acquisition experience”, with no MSI or GAC involved (this is mind-boggling, isn’t it?). Of course, adding components for development with different technologies will take considerably more time, so we will have to wait for the final result of the new setup experience:

She had also an interview with Seth Juarez about that session:

I currently have on my development machine six versions of Visual Studio (2005, 2008, 2010, 2012, 2013 and 2015), along with their service packs and Windows updates, which are required to ensure that my MZ-Tools extension (as add-in or as package) works correctly on each VS version. Also, I have different virtual machines with only one version of VS installed on each one, which is required to ensure that I am not using a reference that is missing in some VS version (which wouldn’t be noticed on the main development machine because all VS versions are installed). Each time that I have to create a new development environment of VS versions I know it will take me the whole day… watching TV shows or doing something else. On the one hand I think that Visual Studio has become a huge monster, still COM-based, with lots of internal technologies and dependencies. On the other hand, there is something in the MSI technology that makes it slow. For example, a setup created by InnoSetup for a Visual Studio add-in is faster than a setup created by MSI. Anyway, hopefully in the future the installation of Visual Studio will be less painful, now that Microsoft is aware of the pain.