-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
We've been porting quite a few applications from .NET Framework to .NET 6. Many of these use third party libraries for devices. Devices we need to support for 10+ years. Those libraries often don't get updated past some point. Regardless, we have in most cases been able to get these libraries running on .NET 6 despite these targeting .NET 4, 3.5 or even 2.0. However, recently we hit a weird issue that I don't fully understand, so trying to wrap my head around this.
In a mixed mode library (appears to be built with C++/CLI) targeting .NET Framework 2.0 everything works except one little thing. A managed event raised from native code. The code in question is basically:
public class IconBufferEventArgs : EventArgs
{
// Various properties
}
public delegate void IconBufferReceivedDelegate(object sender, IconBufferEventArgs args);
interface IFrameGrabber
{
event IconBufferReceivedDelegate IconBufferReceived;
}When IconBufferReceived is raised this fails with:
System.InvalidOperationException: Type 'IconBufferEventArgs' has a ComVisible(false) parent 'System.EventArgs'
in its hierarchy, therefore QueryInterface calls for IDispatch or class interfaces are disallowed.
and HResult -2146233079/0x80131509 with a call stack like:
at System.StubHelpers.InterfaceMarshaler.ConvertToNative(Object objSrc, IntPtr itfMT, IntPtr classMT, Int32 flags)
at XYZ.WrapperCallbackTranslator(IconBuffer* nativeIconBuffer, FrameGrabber* __unnamed001, Void* userdata, FrameGrabberStatus* nativeStatus)"
or in debug:
XYZ.dll!<Module>.Sick.Icon.WrapperCallbackTranslator(icon.IconBuffer* nativeIconBuffer, icon.FrameGrabber* __unnamed001, void* userdata, icon.FrameGrabberStatus* nativeStatus)
[Native to Managed Transition]
XYZ_51_x64.dll!00000000230dcf4b()
QtCore4_x64.dll!000000006721d415()
msvcr80.dll!000000006bfe37d7()
msvcr80.dll!000000006bfe3894()
kernel32.dll!00007ffe44b07614()
ntdll.dll!00007ffe44d626a1()
The exception and call stack indicate an issue with how EventArgs is defined e.g. no longer ComVisible(true) but ComVisible(false) and this being an issue for marshaling. And indeed if we run this in either .NET Fx 4.8 (everything works fine on .NET 4.8) or .NET 6.0 we will get something like:
net4.8: IsComVisible IconBufferEventsArgs False EventArgs True
net6.0: IsComVisible IconBufferEventsArgs False EventArgs False
The only issue I have been able to find related to this is #27974 (Seeing lots of InvalidOperationExceptions with Automation Peers), but this was closed as fixed by @jkotas in dotnet/coreclr#21137 (Change System.Object to ClassInterface.None), but none of this touches upon EventArgs.
So my question is what is going on here? Why does this fail despite as far as I can tell no COM being involved directly? Why has the definition of EventArgs changed i.e. no longer ComVisible(true)? And could this not be marked as ComVisible(true)? If not, what's the issue with applying this to EventArgs when it has had that for years? (if it even helps).
Links:
EventArgs does not have ComVisible(true) set in 6.0 release:
https://github.com/dotnet/runtime/blob/release/6.0/src/libraries/System.Private.CoreLib/src/System/EventArgs.cs
| [Serializable] | |
| [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] | |
| public class EventArgs |
Delegate however does so why not EventArgs?
https://github.com/dotnet/runtime/blob/release/6.0/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs
| [ClassInterface(ClassInterfaceType.None)] | |
| [ComVisible(true)] | |
| public abstract partial class Delegate : ICloneable, ISerializable |