Skip to content

Commit

Permalink
Restore .NET Standard context callback logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Jan 24, 2024
1 parent 0a432ce commit 5c81749
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 33 deletions.
18 changes: 18 additions & 0 deletions src/WinRT.Runtime/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ABI.WinRT.Interop.IContextCallback.Vftbl>.FromAbi(contextCallbackPtr));

try
{
contextCallback.ContextCallback(_ =>
{
callback();
return 0;
}, &data, InterfaceIIDs.ICallbackWithNoReentrancyToApplicationSTA_IID, 5);
}
catch(Exception)
{
onFailCallback?.Invoke();
}
#endif
}

public static void DisposeContextCallback(IntPtr contextCallbackPtr)
Expand Down
80 changes: 47 additions & 33 deletions src/WinRT.Runtime/Interop/IContextCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using WinRT;

Expand All @@ -17,23 +16,17 @@ 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]<IntPtr, IntPtr, ComCallData*, Guid*, int, IntPtr, int> ContextCallback_4;

public static void ContextCallback(IntPtr contextCallbackPtr, Action callback, Action onFailCallback)
{
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
Expand Down Expand Up @@ -65,42 +58,63 @@ 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<ComCallData*, int>)&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<ComCallData*, int>)&InvokeCallback,
&comCallData,
&iid,
/* iMethod */ 5,
IntPtr.Zero);

GC.KeepAlive(nativeCallback);
#endif

if (hresult < 0)
{
onFailCallback?.Invoke();
}
}
}
#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]<IntPtr, IntPtr, ComCallData*, Guid*, int, IntPtr, int> ContextCallback_4
{
get => (delegate* unmanaged[Stdcall]<IntPtr, IntPtr, ComCallData*, Guid*, int, IntPtr, int>)_ContextCallback;
set => _ContextCallback = (void*)value;
}
}
public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);

public static implicit operator IContextCallback(IObjectReference obj) => (obj != null) ? new IContextCallback(obj) : null;
public static implicit operator IContextCallback(ObjectReference<Vftbl> obj) => (obj != null) ? new IContextCallback(obj) : null;
private readonly ObjectReference<Vftbl> _obj;
public IntPtr ThisPtr => _obj.ThisPtr;
public ObjectReference<I> AsInterface<I>() => _obj.As<I>();
public A As<A>() => _obj.AsType<A>();
public IContextCallback(IObjectReference obj) : this(obj.As<Vftbl>()) { }
public IContextCallback(ObjectReference<Vftbl> 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
}
2 changes: 2 additions & 0 deletions src/cswinrt/strings/WinRT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ internal static class InterfaceIIDs
internal static readonly Guid IAgileObject_IID = new Guid(new global::System.ReadOnlySpan<byte>(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<byte>(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<byte>(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<byte>(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);
Expand All @@ -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
}
}
Expand Down

0 comments on commit 5c81749

Please sign in to comment.