I received four days ago a problem report from a German user of my MZ-Tools add-in for VBA, explaining that after updating to the last build 220.127.116.11, the language of the user interface was always English, despite MZ-Tools being configured to use the language of the Regional Settings, and being these German. Nobody else had reported this and I was unable to reproduce it.
At first I thought that there was a problem in the logic detecting the language of the Regional Settings, but after some verification that was not the case, the problem happened also selecting German directly (and the logic to detect the language of the Regional Settings hasn’t changed for years).
Then I requested him to send me his files and settings. I copied them to my computer but I was unable to reproduce the problem, German was used as language.
Then I sent him all the builds between the last working build and the last (failing) build, so we determined which exact build introduced the problem.
Using source control I could determine that the first failing build used a somewhat different approach to generate the resource dlls used by MZ-Tools, because I am these weeks migrating from a custom builder for MZ-Tools to 100% MSBuild. But the new approach seemed very fine to me, so it should be something else, and I had a suspicion.
In the past years MZ-Tools used an embedded xml file with all languages, and while it worked fine, in recent times I have a tendency to adopt standard Microsoft approaches, so I switched to .resx/resource dlls (despite my dislike for file proliferation). Soon I became familiar with an issue with .resource.dll files: if for some reason the Common Language Runtime (CLR) of the .NET Framework fails to load them, the failure is silent and the user interface defaults to English. This happened in the case that I described in the post The strange case of localized resources not being loaded, where I was failing to re-sign the resource dlls after obfuscating and re-signing the main assembly. Since then I have learned more about obfuscation and signing and I no longer use delay-signing.
Notice that when resource dlls fail to load, three errors are happening:
- Something is generating bad resource dlls (that can’t be loaded by the CLR).
- PEVerify.exe is not being used to verify the resource dlls during the MSBuild script, or it is not reporting the problem.
- The error is not detected at runtime (it’s a silent error), although it can be detected with the Assembly Binding Log Viewer (fuslogvw.exe).
Rather than focusing on the first item to solve the problem, I like to focus first on providing early detection of problems. In my case I noticed that my MSBuild script was not using PEVerify.exe to verify the resource dlls (it was used only against main assemblies), so I added that verification to the build script. Strangely, the verification was successful. But I noticed that I was using the $(TargetFrameworkSDKToolsDirectory) MSBuild variable, that uses .NET Framework 4.0. MZ-Tools 8.0 for VBA is built against .NET Framework 2.0, so I changed the MSBuild script to use the peverify.exe tool of .NET Framework 2.0. And then, finally, I got this:
“The assembly is built by a runtime newer than the currently loaded runtime, and cannot be loaded.”
What? I used the disassembler ildasm.exe, and surprise, surprise, the MZTools8PlugIn.resources.dll was referencing mscorlib version 4.0, despite MZTools8PlugIn.dll being targeting .NET Framework 2.0:
I reproduced the problem creating a Class Library project and adding a resource file. What could be causing this? Quickly I thought about other thing that changed on my computer in the last weeks: I installed Visual Studio 2017 RC to add support for that IDE in MZ-Tools 8.0 for Visual Studio. Latest builds of MZ-Tools are compiled with Visual Studio 2017 RC, but I noticed that the problem also happened using Visual Studio 2015 on the same computer. I was quite sure that this was not the case in the past, as I verified on a second computer with Visual Studio 2015 without Visual Studio 2017 RC. So, this is a problem introduced by Visual Studio 2017 RC, and I have reported it here:
I don’t have a workaround yet (other than using a computer without Visual Studio 2017 RC), but at least now I know the culprit and I have a MSBuild script that will detect all future cases at build time.
The last piece to be explained is why I was unable to reproduce the issue on my computer. The reason is that the user is using Windows 7, where MZ-Tools 8.0 for VBA runs on the installed .NET Framework 2.0 (and therefore cannot load .NET 4.0 resource dlls), while I am using Windows 10, where MZ-Tools 8.0 for VBA runs on the installed .NET Framework 4.0, which is happy to load .NET 4.0 resource dlls.