Problem Description
We have discovered an issue in our application where a COM client (VB6) cannot handle a failing HRESULT returned from a .NET COM Interop component. This issue only exists after our customer's machines had the .NET Framework 4.5 or later (4.5.1 and 4.5.2) pushed to them, replacing .NET 4.0.
The .NET component in question processes errors by creating System.Runtime.InteropServices.COMException instances and throwing them. The CLR COM Interop layer catches the exception and returns a failing HRESULT to the COM caller. In the case of VB6, we code the COM client to expect failing HRESULTS (VB6 errors) using On Error GoTo <label> processing. And this has been working for our COM VB6 clients for years with .NET 2.0 and 4.0.
However, as soon as we install .NET 4.5 (or later), our VB6 On Error statement is ignored and our application crashes. There seems to be no way to trap the failing HRESULT. When we connect a debugger to the crash, we see that 'System.Runtime.InteropServices.COMException' was thrown, but not handled. It looks like this exception is not being caught/processed by the CLR in the COM Interop layer.
Verification Using .NET 2.0 and .NET 4.0
Our .NET component targets .NET 3.5, so I have the luxury of using EXE.CONFIG files to control the runtime. When I specify the 3.5 framework (2.0 CLR), the code works as expected. When I specify .NET 4.0 (CLR) but have .NET 4.5 installed, I get the crash.
Note that I am using the 'useLegacyV2RuntimeActivationPolicy="true" to avoid side by side .NET Frameworks.
Targeting .NET 4.0 for the .NET Component does not solve the problem. We tried this and the exception was still crashing our COM client.
Additional Information
It should be noted that we have only found a few methods that have this problem and the CLR's issue seems to be related to the number and/or type of the parameters. Our COM Client is calling the .NET Interop component's AddPointConnected method. This method has 5 paramters. The 4th parameter is an in,out parameter and the 5th parameter is an 'out' parameter. There is something about this combination that causes the COMException to not be handled properly by the COM Interop layer of the CLR.
We've tried many combinations of parameters, changing order, removing items, etc. Some permutations continue to cause the exception and others don't. The common issue appears to be the combination of the 'ref' and the 'return' parameters.
Other Workarounds
We tried targeting .NET 4.0 from Visual Studio 2010, but that did not fix the crash.
Moving to Visual Studio 2013 is not possible in our current schedule.
Sample Code
I was able to create a complete sample problem that shows the issue. It consists of only two parts. The .NET Component is in a class library that exposes several interfaces and a component that implements the complex interface. The method in question 'AddPointConnected' is implemented with only the following code:
public IRoutePoint AddPointConnected(int PassKey, ConnectType connectType, IRoutePoint connectPt, ref ILeg newLeg) { throw new COMException("You cannot add anymore points"); }
The client uses the following code to try to trap the failing HRESULT:
Private Sub Command2_Click() Dim clientEditor As DotNetClassLibrary.IComplexInterface Dim newLeg As ILeg Dim newPoint As IRoutePoint Set clientEditor = CreateObject("DotNetClassLibrary.ClientEditor") On Error GoTo CaughtError Set newPoint = clientEditor.AddPointConnected(0, DotNetClassLibrary.ConenctType_ADD_AFTER, Nothing, newLeg) MsgBox ("This message should not be seen.") Exit Sub CaughtError: MsgBox ("The exception was properly caught") End Sub
I have attached the sample project here:
<iframe src="https://onedrive.live.com/embed?cid=AE1D3AA8CFE3192F&resid=AE1D3AA8CFE3192F%21114&authkey=AA5xyH5tGKHeKYU" width="98" height="120" frameborder="0" scrolling="no"></iframe>
Brian R.