diff --git a/src/WinRT.Runtime/Context.cs b/src/WinRT.Runtime/Context.cs index d1dd426c4..1055f67e1 100644 --- a/src/WinRT.Runtime/Context.cs +++ b/src/WinRT.Runtime/Context.cs @@ -33,7 +33,25 @@ public unsafe static void CallInContext(IntPtr contextCallbackPtr, IntPtr contex return; } +#if NET && CsWinRT_LANG_11_FEATURES IContextCallbackVftbl.ContextCallback(contextCallbackPtr, callback, onFailCallback); +#else + ComCallData data = default; + var contextCallback = new ABI.WinRT.Interop.IContextCallback(ObjectReference.FromAbi(contextCallbackPtr)); + + try + { + contextCallback.ContextCallback(_ => + { + callback(); + return 0; + }, &data, InterfaceIIDs.ICallbackWithNoReentrancyToApplicationSTA_IID, 5); + } + catch(Exception) + { + onFailCallback?.Invoke(); + } +#endif } public static void DisposeContextCallback(IntPtr contextCallbackPtr) diff --git a/src/WinRT.Runtime/Interop/IContextCallback.cs b/src/WinRT.Runtime/Interop/IContextCallback.cs index c99c481ed..49dd3db59 100644 --- a/src/WinRT.Runtime/Interop/IContextCallback.cs +++ b/src/WinRT.Runtime/Interop/IContextCallback.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using WinRT; @@ -17,14 +16,9 @@ internal struct ComCallData public IntPtr pUserDefined; } -#if !(NET && CsWinRT_LANG_11_FEATURES) - internal unsafe delegate int PFNCONTEXTCALL(ComCallData* data); -#endif - +#if NET && CsWinRT_LANG_11_FEATURES internal unsafe struct IContextCallbackVftbl { - public static readonly Guid IID_ICallbackWithNoReentrancyToApplicationSTA = new(0x0A299774, 0x3E4E, 0xFC42, 0x1D, 0x9D, 0x72, 0xCE, 0xE1, 0x05, 0xCA, 0x57); - private global::WinRT.Interop.IUnknownVftbl IUnknownVftbl; private delegate* unmanaged[Stdcall] ContextCallback_4; @@ -32,8 +26,7 @@ public static void ContextCallback(IntPtr contextCallbackPtr, Action callback, A { ComCallData comCallData; comCallData.dwDispid = 0; - comCallData.dwReserved = 0; -#if NET && CsWinRT_LANG_11_FEATURES + comCallData.dwReserved = 0; // Copy the callback into a local to make sure it really is a local that // gets marked as address taken, rather than something that could potentially @@ -65,37 +58,16 @@ static int InvokeCallback(ComCallData* comCallData) return e.HResult; } } -#else - comCallData.pUserDefined = IntPtr.Zero; -#endif - Guid iid = IID_ICallbackWithNoReentrancyToApplicationSTA; - int hresult; -#if NET && CsWinRT_LANG_11_FEATURES - hresult = (*(IContextCallbackVftbl**)contextCallbackPtr)->ContextCallback_4( - contextCallbackPtr, - (IntPtr)(delegate* unmanaged)&InvokeCallback, - &comCallData, - &iid, - /* iMethod */ 5, - IntPtr.Zero); -#else - PFNCONTEXTCALL nativeCallback = _ => - { - callback(); - return 0; - }; + Guid iid = InterfaceIIDs.ICallbackWithNoReentrancyToApplicationSTA_IID; - hresult = (*(IContextCallbackVftbl**)contextCallbackPtr)->ContextCallback_4( + int hresult = (*(IContextCallbackVftbl**)contextCallbackPtr)->ContextCallback_4( contextCallbackPtr, - Marshal.GetFunctionPointerForDelegate(nativeCallback), + (IntPtr)(delegate* unmanaged)&InvokeCallback, &comCallData, &iid, /* iMethod */ 5, IntPtr.Zero); - - GC.KeepAlive(nativeCallback); -#endif if (hresult < 0) { @@ -103,4 +75,46 @@ static int InvokeCallback(ComCallData* comCallData) } } } +#else + internal unsafe delegate int PFNCONTEXTCALL(ComCallData* data); + + [Guid("000001da-0000-0000-C000-000000000046")] + internal sealed unsafe class IContextCallback + { + internal static readonly Guid IID = InterfaceIIDs.IContextCallback_IID; + + [Guid("000001da-0000-0000-C000-000000000046")] + public struct Vftbl + { + global::WinRT.Interop.IUnknownVftbl IUnknownVftbl; + private void* _ContextCallback; + public delegate* unmanaged[Stdcall] ContextCallback_4 + { + get => (delegate* unmanaged[Stdcall])_ContextCallback; + set => _ContextCallback = (void*)value; + } + } + public static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); + + public static implicit operator IContextCallback(IObjectReference obj) => (obj != null) ? new IContextCallback(obj) : null; + public static implicit operator IContextCallback(ObjectReference obj) => (obj != null) ? new IContextCallback(obj) : null; + private readonly ObjectReference _obj; + public IntPtr ThisPtr => _obj.ThisPtr; + public ObjectReference AsInterface() => _obj.As(); + public A As() => _obj.AsType(); + public IContextCallback(IObjectReference obj) : this(obj.As()) { } + public IContextCallback(ObjectReference obj) + { + _obj = obj; + } + + public unsafe void ContextCallback(PFNCONTEXTCALL pfnCallback, ComCallData* pParam, Guid riid, int iMethod) + { + var callback = Marshal.GetFunctionPointerForDelegate(pfnCallback); + var result = _obj.Vftbl.ContextCallback_4(ThisPtr, callback, pParam, &riid, iMethod, IntPtr.Zero); + GC.KeepAlive(pfnCallback); + Marshal.ThrowExceptionForHR(result); + } + } +#endif } \ No newline at end of file diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index 430a13778..0b58a872b 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -1122,6 +1122,7 @@ internal static class InterfaceIIDs internal static readonly Guid IAgileObject_IID = new Guid(new global::System.ReadOnlySpan(new byte[] { 0x94, 0x2B, 0xEA, 0x94, 0xCC, 0xE9, 0xE0, 0x49, 0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90 })); internal static readonly Guid IMarshal_IID = new Guid(new global::System.ReadOnlySpan(new byte[] { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 })); internal static readonly Guid IContextCallback_IID = new Guid(new global::System.ReadOnlySpan(new byte[] { 0xDA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 })); + internal static readonly Guid ICallbackWithNoReentrancyToApplicationSTA_IID = new Guid(new global::System.ReadOnlySpan(new byte[] { 0x74, 0x97, 0x29, 0x0A, 0x4E, 0x3E, 0x42, 0xFC, 0x1D, 0x9D, 0x72, 0xCE, 0xE1, 0x05, 0xCA, 0x57 })); #else internal static readonly Guid IInspectable_IID = new(0xAF86E2E0, 0xB12D, 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90); internal static readonly Guid IUnknown_IID = new(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); @@ -1131,6 +1132,7 @@ internal static class InterfaceIIDs internal static readonly Guid IAgileObject_IID = new(0x94ea2b94, 0xe9cc, 0x49e0, 0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90); internal static readonly Guid IMarshal_IID = new(0x00000003, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46); internal static readonly Guid IContextCallback_IID = new(0x000001da, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); + internal static readonly Guid ICallbackWithNoReentrancyToApplicationSTA_IID = new(0x0A299774, 0x3E4E, 0xFC42, 0x1D, 0x9D, 0x72, 0xCE, 0xE1, 0x05, 0xCA, 0x57); #endif } }