C# AccessViolationException with interop callbacks in .NET 4.5 or above

I'm investigating screen reader technology in C# and experiencing an issue regarding the capturing of events using an interop library written in C++ (Java Access Bridge - https://github.com/openjdk/jdk/tree/05a764f4ffb8030d6b768f2d362c388e5aabd92d/src/jdk.accessibility/windows/native/libwindowsaccessbridge) when compiled using .NET 4.5+ (64-bit). It crashes in both Debug and Release build configurations. The functionality works fine in .NET 4.0 however.
Whenever an event occurs that should trigger the registered callback, an AccessViolationException occurs, crashing the application. I suspect it has something to do with the Garbage Collector changes introduced in .NET 4.5 but would appreciate assistance in being able to track down the exact issue.
There is a complete minimal reproducible code project located here that subscribes to a mouseclick event -> https://github.com/needmoreraminbrainnow/screenreadertest.
When this is compiled with .NET 4.5 it will crash when a mouseclick event occurs within a Java-based application
The delegate is created as a class variable to maintain a reference. The two important methods on the C# side are...
[DllImport(WINDOWS_ACCESS_BRIDGE, SetLastError = true, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private static extern void setMouseClickedFP(MouseClickedDelegate fp);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MouseClickedDelegate(System.Int64 vmID, IntPtr jevent, IntPtr ac);
I believe the relevant C++ methods are...
void fireMouseClicked(long vmID, JOBJECT64 event, JOBJECT64 source);
and...
void AccessBridgeEventHandler::method(long vmID, JOBJECT64 event, JOBJECT64 source) { \
DEBUG_CODE(char debugBuf[255]); \
DEBUG_CODE(sprintf(debugBuf, fireEventDebugString, #method, event, source, vmID)); \
DEBUG_CODE(AppendToCallInfo(debugBuf)); \
if (eventFP != (FPprototype) 0) { \
eventFP(vmID, event, source); \
} else { \
DEBUG_CODE(AppendToCallInfo("[ERROR]: eventFP == 0")); \
} \
}
All I can find that corresponds to setMouseClicked is in C code here...
void SetMouseClicked(AccessBridge_MouseClickedFP fp) {
if (theAccessBridgeInitializedFlag == TRUE) {
theAccessBridge.SetMouseClicked(fp);
}
}
and also...
#define CALL_SET_EVENT_FP(function, callbackFP) \
void WinAccessBridge::function(callbackFP fp) { \
eventHandler->function(fp, this); \
/* eventHandler calls back to winAccessBridgeDLL to set eventMask */ \
}
CALL_SET_EVENT_FP(setMouseClickedFP, AccessBridge_MouseClickedFP)
I've tried pinning the delegate using GCHandle.Alloc(_mouseClickDelegate, GCHandleType.Pinned);
but when run this results in a Object contains non-primitive or non-blittable data error. And based on research of similar questions and Microsoft articles it appears this should not be necessary.
I've tried using GC.KeepAlive
for the delegate
I have also tried changes related to Marshalling of the delegate when setting the callback and using a different calling convention but to no avail.
I have also tried using the following struct as the callback argument type instead of IntPtr...
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class JOBJECT64
{
public static JOBJECT64 Zero = default(JOBJECT64);
private readonly long _value;
public JOBJECT64(long value)
{
_value = value;
}
public long Value
{
get { return _value; }
}
public static bool operator ==(JOBJECT64 x, JOBJECT64 y)
{
return x._value == y._value;
}
public static bool operator !=(JOBJECT64 x, JOBJECT64 y)
{
return x._value == y._value;
}
public override bool Equals(object obj)
{
if (obj is JOBJECT64)
{
return this == (JOBJECT64) obj;
}
return false;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
}
How can I confirm that it is a problem with the delegate being moved or inaccessible?