Since I started three months ago to use a COM Shim for my .NET-based MZ-Tools 8.0 for VBA/VB6 to achieve isolation and .NET CLR independence, nobody had reported a single problem. However, last week two different problems were reported. This post is about the first one. The error was that on Windows XP, MZ-Tools 8.0 for VB/VBA failed to load. This dreaded error message:
Fortunately, the user reported that installing .NET Framework 4.0 the problem was solved, but why?
The error message is hiding the actual error code and description (Microsoft started to show that crucial piece of information when an add-in fails to load in Visual Studio .NET 2002). I was able to reproduce the problem so I didn’t need to contact the user for further information. An approach to know why an add-in is failing to load on any IDE is to use Process Monitor to capture disk and registry activity and then guess what is failing (some missing registry entry or file, etc.). Unfortunately the current version of Process Monitor doesn’t support Windows XP, and although I couldn’t find an earlier version to download, I found the Registry Monitor and File Monitor utilities (that later became unified in Process Monitor) and they worked on Windows XP. However, I couldn’t guess the problem. I always forget that the easiest way to know the actual error is to create a VBScript with this code that creates a COM object with the ProgId of the add-in (typically “MyAddIn.Connect”):
Dim o Set o = CreateObject("MZTools8VBA")
And executing that script shows the actual problem:
So, the problem was that the CLRCreateInstance function (used by the COM Shim to load the Common Language Runtime, CLR) was not found in mscoree.dll. At this point I knew I needed another tool: depends.exe (Dependency Walker).
The CLRCreateInstance function was introduced in .NET Framework 4.0 to load the CLR 4.0. The CLR 2.0 used by .NET Frameworks 2.0, 3.0 and 3.5 is loaded with a different function. My COM Shim has this logic:
- First it detects if .NET Framework 2.0 is installed. If so, it uses the old API to load CLR 2.0.
- If not, it detects if .NET Framework 4.0 is installed. If so, it uses the new CLRCreateInstance API to load CLR 4.0.
Note: this logic that uses run-time detection of the CLR rather than setup-time detection is flawed by a different reason that caused the second reported problem (for another post).
Since my setup requires .NET Framework 2.0 on Windows XP, I knew that the CLRCreateInstance function was not called on Windows XP. However, since my COM Shim dll linked it at compile-time:
the whole dll of the COM Shim failed to load if that function is missing in mscoree.dll (it seems that my knowledge of C/C++ linking is very limited, I thought I would get a runtime error only if the COM Shim tried to call that missing function…).
This explained why installing .NET Framework 4.0 solved the problem: even if the COM Shim still used CLR 2.0 (by the logic above), the mscoree.dll updated by .NET Framework 4.0 provided the missing CLRCreateInstance function and the COM Shim dll didn’t fail to load.
But a question remained that got me puzzled for several days: nobody had reported this problem on Windows 7, that lacks .NET Framework 4.0 (it installs only .NET Framework 3.5 / CLR 2.0), in these three months. And since my setup doesn’t require .NET Framework 4.0 on Windows 7, I was sure that not all users have .NET Framework 4.0 installed. I should have received tons of bug reports with the same problem. But not a single one… The first thing I did was to check the version of mscoree.dll of my virtual machines with Windows 7. First surprise: they showed 4.0.xxxx, although .NET Framework 4.0 was not installed:
Then I used depends.exe to check that the mscoree.dll of Windows 7 certainly exports the CLRCreateInstance function:
So, how is that Windows 7, lacking .NET Framework 4.0, has a mscoree.dll version 4.0.xxxx that provides the CLRCreateInstance method to load the CLR 4.0?
At this point I decided to start from scratch: I created a virtual machine with Windows 7 RTM, and suprise, surprise, mscoree.dll was version 2.0.xxxx:
and certainly lacked the CLRCreateInstance method:
And of course, installing VB6 or Office and MZ-Tools 8.0 reproduced the problem that happened on Windows XP.
It was only after I applied SP1 to Windows 7, that mscoree.dll was updated to version 4.0.xxxx. So, it seems that Microsoft decided to include the mscoree.dll version 4.0.xxxx of .NET Framework 4.0 in the service pack 1 of Windows 7, even if that service pack doesn’t include .NET Framework 4.0.
Of course the best solution is to use dynamic linking at run-time using GetProcAddress so that the COM Shim can be loaded even if the CLRCreateInstance function is missing:
For the record, Windows 10 uses version 10.0.xxxx of mscoree.dll: