COM Shim CLR Loader Bug
The latest version of the COM shim wizards was released back in the summer, here. With the help of Adam Smith of Xobni (and of course, the indispensable Misha), we've identified a minor bug with the project code that the wizard generates for the shim. In fact, this bug was identified prior to the last release (as you can read in Misha's blog comments here), but we simply forgot to include the fix – my apologies for that.
Part of what the shim does is to load the CLR: it does this by calling CorBindToRuntimeEx. We test the return from CorBindToRuntimeEx, and if it's S_FALSE, this indicates that the CLR has already been loaded. In the released version of the shim, if we get S_FALSE, we simply return.
However, there is a scenario where the CLR could already have been loaded but not started. It's an unusual scenario: it could happen if some other managed code was loaded into the process but never executed. The problem is that the shim code assumes that if the CLR is loaded it is not necessary for us to start it. Of course, if the only other things in the process that load the CLR are all shims created with the COM Shim Wizard, then this assumption would be true – because the first one to load would have loaded the CLR and started it. However, this assumption doesn't hold if there are other native components that load the CLR and don't start it.
The change to fix the bug is to EITHER call ICorRuntimeHost::Start if we get S_FALSE, OR simply don't test for S_FALSE at all – this works because we do call Start later on. The fixed code is shown below, with the S_FALSE test removed and highlighted:
HRESULT CCLRLoader::LoadCLR()
{
HRESULT hr = S_OK;
// Ensure the CLR is only loaded once.
if (m_pCorRuntimeHost != NULL)
{
return hr;
}
// Load the CLR into the process, using the default (latest) version,
// the default ("wks") flavor, and default (single) domain.
hr = CorBindToRuntimeEx(
0, 0, 0,
CLSID_CorRuntimeHost, IID_ICorRuntimeHost,
(LPVOID*)&m_pCorRuntimeHost);
// If CorBindToRuntimeEx returned S_FALSE, the CLR has already
// been loaded.
//if (hr == S_FALSE)
//{
// return hr;
//}
// If CorBindToRuntimeEx returned a failure HRESULT, we failed to load
// the CLR.
if (!SUCCEEDED(hr))
{
return hr;
}
// Start the CLR.
return m_pCorRuntimeHost->Start();
}
We'll work with the gentle folks at MSDN to get the COM Shim Wizard download updated as soon as possible. In the meantime, you can make this simple change to the wizard-generated code in ClrLoader.cpp. Note that this test for S_FALSE occurs in all variants of the shim code – that is, the shim for add-ins, smart tags and real-time data components. It can be removed from all these variants.
Thanks again to Adam Smith, Shamil Salakhetdinov, and Misha for identifying the problem and the fix.
Comments
- Anonymous
November 26, 2007
The comment has been removed - Anonymous
December 28, 2007
I've incorporated the fix according to this article. I know the shim code is being invoked on a deployment system, but I still can't get the shim to call my managed Excel UDF. The problem is that the proper registry keys are not being generated, either via the COM Shim Wizard or from the Setup Project. Complete details are in my own blog - get there from the unmunged link associated with this comment. - Anonymous
November 17, 2008
We experienced a problem with our COM Shim created by the Wizard - the call to CorBindToRuntimeEx was failing with error 0x80131700. We found that specifying the version as the 1st parameter to the call resolved the issue. - Anonymous
November 18, 2008
The comment has been removed - Anonymous
December 01, 2008
Does this CLR loading problem, would cause any issue on deployment machine, or it is only development machine specific issue - Anonymous
December 02, 2008
Mehul - as I explained, the problem was in the code that was generated by the wizard, which will run on both the dev machine and the end-user's machine.Note that this problem has been fixed in the latest version of the wizard, described here: http://msdn.microsoft.com/en-us/library/bb508939.aspx