runtime: Events get ignored by COM in VBA (Excel) when invoked inside a Task

Description

COM events from a COM component created in .NET 6 are not received by a COM client written in VBA (Excel). However, these events are ignored only when they are invoked inside a ‘System.Runtime.Action’ class run by ‘System.Threading.Tasks.Task’ class.

Task.Run(() => SomeEvent?.Invoke)

The issue is that the same COM component in .NET Framework 4.7.2 would result in the events working as intended. I would expect that the events should run in .NET 6 just like they used to in .NET Framework 4.7.2.

The code needed to reproduce this issue can be found in this Github repository. It contains the .NET 6 version and the .NET Framework 4.7.2 version of the COM component as well as the COM client as an Excel workbook with macros.

To reproduce the issue just use the COM components as described in the ReadMe file of the repository.

Configuration

  • The COM component is created with .NET 6
  • OS: Microsoft Windows 10 Enterprise
  • The architecture is x64, however the COM component is built in x86 since the local Excel’s bit version is x86 and it requires the same bit version

Regression?

As mentioned above this was working in .NET Framework 4.7.2. However, it may be important to mention that .NET 6 imports the ‘Action’ and the ‘Task’ class from the assembly ‘System.Threading.Tasks’, while .NET Framework 4.7.2 imports those classes from the assembly mscorlib.

Other information

The events don’t work, when Tasks are used to invoke them. Invoking the event without using a Task works for the .NET 6 Version of the COM component as well.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 18 (10 by maintainers)

Most upvoted comments

@Spikxzy I did miss this, apologies. This looks like the same issue as in Excel. The issue is the cross-apartment marshalling logic. The Python and MATLAB code are going to need to do the same thing as Excel to work around this issue. I will try and make some time to figure out if there is another way to enable this.

TL;DR The issue is the implicit cross apartment operation that is occurring - operating on an STA object (VBA) from an MTA context (Threadpool thread). This is by-design. A workaround is to register a marshaller for the .NET event interface being used.

The crux of the problem is .NET Remoting is not supported in .NET Core and was being used to make this scenario work in .NET Framework. Speaking specifically about the repo, a QueryInterface() is taking place for the CalculatorEvents interface and is failing. It is failing because the runtime is creating a proxy to the VBA object instance (the callback) since it is being used from an MTA (that is, Threadpool thread via Task.Run()). The CalculatorEvents interface is unknown to COM and hence the QueryInterface() fails with E_NOINTERFACE.

See the call to SafeQueryInterface() below.

https://github.com/dotnet/runtime/blob/3c0c801056c285965097692bfb13a4a53afa2462/src/coreclr/vm/runtimecallablewrapper.cpp#L2050-L2094