Skip to content

Commit 541747c

Browse files
authored
Fix IL2087 trim warning in 'ObjectReferenceWithContext<T>' (#1577)
* Fix trim warning for '_iid' in 'ObjectReference<T>' * Remove duplicate IID definition * Validate that input 'iid' arguments are not empty * Optimize 'CreateForCurrentContext' on NAOT * Fix generated 'ActivateInstance<I>' method * Fix trim warning in 'IMarshal' in Windows SDK * Skip closure allocation in ObjectReferenceWithContext<T> (#1587) * Skip closure allocation in ObjectReferenceWithContext<T> * Remove even more closure allocations in ObjectReferenceWithContext<T> (#1589) * Skip closures for 'Context.CallInContext' calls * Use function pointers instead of delegates * Move context lambda to FOH
1 parent 7551da2 commit 541747c

34 files changed

+1175
-825
lines changed

src/WinRT.Runtime/ActivationFactory.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private DllModule(string fileName, IntPtr moduleHandle, void* getActivationFacto
110110
int hr = _GetActivationFactory(MarshalString.GetAbi(ref __runtimeClassId), &instancePtr);
111111
if (hr == 0)
112112
{
113-
var objRef = ObjectReference<IUnknownVftbl>.Attach(ref instancePtr);
113+
var objRef = ObjectReference<IUnknownVftbl>.Attach(ref instancePtr, IID.IID_IUnknown);
114114
return (objRef, hr);
115115
}
116116
else
@@ -169,7 +169,7 @@ public static unsafe (ObjectReference<I> obj, int hr) GetActivationFactory<I>(st
169169
int hr = Platform.RoGetActivationFactory(MarshalString.GetAbi(ref __runtimeClassId), &iid, &instancePtr);
170170
if (hr == 0)
171171
{
172-
var objRef = ObjectReference<I>.Attach(ref instancePtr);
172+
var objRef = ObjectReference<I>.Attach(ref instancePtr, iid);
173173
return (objRef, hr);
174174
}
175175
else
@@ -327,7 +327,7 @@ private static IObjectReference GetFromActivationHandler(string typeName, Guid i
327327
instancePtr = activationHandler(typeName, iid);
328328
if (instancePtr != IntPtr.Zero)
329329
{
330-
return ObjectReference<IUnknownVftbl>.Attach(ref instancePtr);
330+
return ObjectReference<IUnknownVftbl>.Attach(ref instancePtr, iid);
331331
}
332332
}
333333
finally

src/WinRT.Runtime/AgileReference.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ internal unsafe AgileReference(IntPtr thisPtr)
6767
&iid,
6868
thisPtr,
6969
&agileReference));
70-
_agileReference = ObjectReference<IUnknownVftbl>.Attach(ref agileReference);
70+
_agileReference = ObjectReference<IUnknownVftbl>.Attach(ref agileReference, IID.IID_IUnknown);
7171
}
7272
catch (TypeLoadException)
7373
{
@@ -94,7 +94,7 @@ protected virtual void Dispose(bool disposing)
9494
{
9595
Git.RevokeInterfaceFromGlobal(_cookie);
9696
}
97-
catch(ArgumentException)
97+
catch (ArgumentException)
9898
{
9999
// Revoking cookie from GIT table may fail if apartment is gone.
100100
}
@@ -106,7 +106,7 @@ protected virtual void Dispose(bool disposing)
106106
private static unsafe IGlobalInterfaceTable GetGitTable()
107107
{
108108
Guid gitClsid = CLSID_StdGlobalInterfaceTable;
109-
Guid gitIid = ABI.WinRT.Interop.IGlobalInterfaceTable.IID;
109+
Guid gitIid = IID.IID_IGlobalInterfaceTable;
110110
IntPtr gitPtr = default;
111111

112112
try

src/WinRT.Runtime/ComWrappersSupport.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,12 @@ internal unsafe static bool IsFreeThreaded(IObjectReference objRef)
113113

114114
public static IObjectReference GetObjectReferenceForInterface(IntPtr externalComObject)
115115
{
116-
return GetObjectReferenceForInterface<IUnknownVftbl>(externalComObject);
116+
return GetObjectReferenceForInterface<IUnknownVftbl>(externalComObject, IID.IID_IUnknown);
117117
}
118118

119+
#if NET
120+
[RequiresUnreferencedCode(AttributeMessages.GenericRequiresUnreferencedCodeMessage)]
121+
#endif
119122
public static ObjectReference<T> GetObjectReferenceForInterface<T>(IntPtr externalComObject)
120123
{
121124
if (externalComObject == IntPtr.Zero)
@@ -1162,7 +1165,7 @@ internal InspectableInfo(Type type, Guid[] iids)
11621165
internal static ObjectReference<T> CreateCCWForObject<T>(object obj, Guid iid)
11631166
{
11641167
IntPtr ccw = CreateCCWForObjectForABI(obj, iid);
1165-
return ObjectReference<T>.Attach(ref ccw);
1168+
return ObjectReference<T>.Attach(ref ccw, iid);
11661169
}
11671170

11681171
internal static ObjectReferenceValue CreateCCWForObjectForMarshaling(object obj, Guid iid)

src/WinRT.Runtime/ComWrappersSupport.net5.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ private static object CreateObject(IntPtr externalComObject)
616616
}
617617
else if (Marshal.QueryInterface(externalComObject, ref inspectableIID, out ptr) == 0)
618618
{
619-
var inspectableObjRef = ComWrappersSupport.GetObjectReferenceForInterface<IInspectable.Vftbl>(ptr);
619+
var inspectableObjRef = ComWrappersSupport.GetObjectReferenceForInterface<IInspectable.Vftbl>(ptr, IID.IID_IInspectable);
620620
ComWrappersHelper.Init(inspectableObjRef);
621621

622622
IInspectable inspectable = new IInspectable(inspectableObjRef);

src/WinRT.Runtime/Context.cs

+20-6
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,31 @@ public static unsafe IntPtr GetContextCallback()
2929
// On any exception, calls onFail callback if any set.
3030
// If not set, exception is handled due to today we don't
3131
// have any scenario to propagate it from here.
32-
public unsafe static void CallInContext(IntPtr contextCallbackPtr, IntPtr contextToken, Action callback, Action onFailCallback)
32+
//
33+
// On modern .NET, we can use function pointers to avoid the
34+
// small binary size increase from all generated fields and
35+
// logic to cache delegates, since we don't need any of that.
36+
public unsafe static void CallInContext(
37+
IntPtr contextCallbackPtr,
38+
IntPtr contextToken,
39+
#if NET && CsWinRT_LANG_11_FEATURES
40+
delegate*<object, void> callback,
41+
delegate*<object, void> onFailCallback,
42+
#else
43+
Action<object> callback,
44+
Action<object> onFailCallback,
45+
#endif
46+
object state)
3347
{
3448
// Check if we are already on the same context, if so we do not need to switch.
3549
if(contextCallbackPtr == IntPtr.Zero || GetContextToken() == contextToken)
3650
{
37-
callback();
51+
callback(state);
3852
return;
3953
}
4054

4155
#if NET && CsWinRT_LANG_11_FEATURES
42-
IContextCallbackVftbl.ContextCallback(contextCallbackPtr, callback, onFailCallback);
56+
IContextCallbackVftbl.ContextCallback(contextCallbackPtr, callback, onFailCallback, state);
4357
#else
4458
ComCallData data = default;
4559
var contextCallback = new ABI.WinRT.Interop.IContextCallback(ObjectReference<ABI.WinRT.Interop.IContextCallback.Vftbl>.FromAbi(contextCallbackPtr));
@@ -48,13 +62,13 @@ public unsafe static void CallInContext(IntPtr contextCallbackPtr, IntPtr contex
4862
{
4963
contextCallback.ContextCallback(_ =>
5064
{
51-
callback();
65+
callback(state);
5266
return 0;
5367
}, &data, IID.IID_ICallbackWithNoReentrancyToApplicationSTA, 5);
5468
}
55-
catch(Exception)
69+
catch (Exception)
5670
{
57-
onFailCallback?.Invoke();
71+
onFailCallback?.Invoke(state);
5872
}
5973
#endif
6074
}

src/WinRT.Runtime/IInspectable.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ private static int Do_Abi_GetTrustLevel(IntPtr pThis, TrustLevel* trustLevel)
122122
}
123123

124124
public static IInspectable FromAbi(IntPtr thisPtr) =>
125-
new IInspectable(ObjectReference<Vftbl>.FromAbi(thisPtr));
125+
new IInspectable(ObjectReference<Vftbl>.FromAbi(thisPtr, IID.IID_IInspectable));
126126

127127
private readonly ObjectReference<Vftbl> _obj;
128128
public IntPtr ThisPtr => _obj.ThisPtr;

src/WinRT.Runtime/Interop/ExceptionErrorInfo.net5.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public static unsafe IObjectReference GetLanguageException(ObjectReference<IUnkn
242242

243243
GC.KeepAlive(obj);
244244

245-
return ObjectReference<IUnknownVftbl>.Attach(ref __return_value__);
245+
return ObjectReference<IUnknownVftbl>.Attach(ref __return_value__, IID.IID_IUnknown);
246246
}
247247
finally
248248
{

src/WinRT.Runtime/Interop/IActivationFactory.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static unsafe IObjectReference ActivateInstanceUnsafe(IObjectReference ob
7070

7171
try
7272
{
73-
return ComWrappersSupport.GetObjectReferenceForInterface<IUnknownVftbl>(instancePtr);
73+
return ComWrappersSupport.GetObjectReferenceForInterface<IUnknownVftbl>(instancePtr, global::WinRT.Interop.IID.IID_IUnknown);
7474
}
7575
finally
7676
{
@@ -142,7 +142,7 @@ private static unsafe int Do_Abi_ActivateInstance_0(IntPtr thisPtr, IntPtr* resu
142142
return 0;
143143
}
144144
}
145-
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
145+
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr, IID.IID_IActivationFactory);
146146

147147
public static implicit operator IActivationFactory(IObjectReference obj) => (obj != null) ? new IActivationFactory(obj) : null;
148148
protected readonly ObjectReference<Vftbl> _obj;

src/WinRT.Runtime/Interop/IAgileReference.net5.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public static unsafe ObjectReference<T> Resolve<T>(IObjectReference _obj, Guid r
7272
ThisPtr, &riid, &ptr));
7373
try
7474
{
75-
return ComWrappersSupport.GetObjectReferenceForInterface<T>(ptr);
75+
return ComWrappersSupport.GetObjectReferenceForInterface<T>(ptr, riid);
7676
}
7777
finally
7878
{
@@ -134,7 +134,7 @@ static unsafe IAgileObject()
134134
[Guid("00000146-0000-0000-C000-000000000046")]
135135
internal sealed unsafe class IGlobalInterfaceTable : global::WinRT.Interop.IGlobalInterfaceTable
136136
{
137-
internal static readonly Guid IID = new(0x00000146, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
137+
internal static readonly Guid IID = global::WinRT.Interop.IID.IID_IGlobalInterfaceTable;
138138

139139
[Guid("00000146-0000-0000-C000-000000000046")]
140140
[StructLayout(LayoutKind.Sequential)]
@@ -149,7 +149,7 @@ public struct Vftbl
149149
public delegate* unmanaged[Stdcall]<IntPtr, IntPtr, Guid*, IntPtr*, int> GetInterfaceFromGlobal => (delegate* unmanaged[Stdcall]<IntPtr, IntPtr, Guid*, IntPtr*, int>)_GetInterfaceFromGlobal;
150150
}
151151

152-
public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
152+
public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr, global::WinRT.Interop.IID.IID_IGlobalInterfaceTable);
153153

154154
public static implicit operator IGlobalInterfaceTable(IObjectReference obj) => (obj != null) ? new IGlobalInterfaceTable(obj) : null;
155155
public static implicit operator IGlobalInterfaceTable(ObjectReference<Vftbl> obj) => (obj != null) ? new IGlobalInterfaceTable(obj) : null;

src/WinRT.Runtime/Interop/IContextCallback.cs

+20-12
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ internal struct ComCallData
1717
public IntPtr pUserDefined;
1818
}
1919

20+
#if NET && CsWinRT_LANG_11_FEATURES
21+
internal unsafe struct CallbackData
22+
{
23+
public delegate*<object, void> Callback;
24+
public object State;
25+
}
26+
#endif
27+
2028
#if NET && CsWinRT_LANG_11_FEATURES
2129
internal unsafe struct IContextCallbackVftbl
2230
{
@@ -25,34 +33,31 @@ internal unsafe struct IContextCallbackVftbl
2533
private delegate* unmanaged[Stdcall]<IntPtr, IntPtr, ComCallData*, Guid*, int, IntPtr, int> ContextCallback_4;
2634
#pragma warning restore CS0649
2735

28-
public static void ContextCallback(IntPtr contextCallbackPtr, Action callback, Action onFailCallback)
36+
public static void ContextCallback(IntPtr contextCallbackPtr, delegate*<object, void> callback, delegate*<object, void> onFailCallback, object state)
2937
{
3038
ComCallData comCallData;
3139
comCallData.dwDispid = 0;
3240
comCallData.dwReserved = 0;
3341

34-
// Copy the callback into a local to make sure it really is a local that
35-
// gets marked as address taken, rather than something that could potentially
36-
// be inlined into the caller into some state machine or anything else not safe.
37-
Action callbackAddressTaken = callback;
42+
CallbackData callbackData;
43+
callbackData.Callback = callback;
44+
callbackData.State = state;
3845

3946
// We can just store a pointer to the callback to invoke in the context,
4047
// so we don't need to allocate another closure or anything. The callback
4148
// will be kept alive automatically, because 'comCallData' is address exposed.
4249
// We only do this if we can use C# 11, and if we're on modern .NET, to be safe.
4350
// In the callback below, we can then just retrieve the Action again to invoke it.
44-
comCallData.pUserDefined = (IntPtr)(void*)&callbackAddressTaken;
51+
comCallData.pUserDefined = (IntPtr)(void*)&callbackData;
4552

4653
[UnmanagedCallersOnly]
4754
static int InvokeCallback(ComCallData* comCallData)
4855
{
4956
try
5057
{
51-
// Dereference the pointer to Action and invoke it (see notes above).
52-
// Once again, the pointer is not to the Action object, but just to the
53-
// local *reference* to the object, which is pinned (as it's a local).
54-
// That means that there's no pinning to worry about either.
55-
((Action*)comCallData->pUserDefined)->Invoke();
58+
CallbackData* callbackData = (CallbackData*)comCallData->pUserDefined;
59+
60+
callbackData->Callback(callbackData->State);
5661

5762
return 0; // S_OK
5863
}
@@ -74,7 +79,10 @@ static int InvokeCallback(ComCallData* comCallData)
7479

7580
if (hresult < 0)
7681
{
77-
onFailCallback?.Invoke();
82+
if (onFailCallback is not null)
83+
{
84+
onFailCallback(state);
85+
}
7886
}
7987
}
8088
}

0 commit comments

Comments
 (0)