-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consume IDynamicInterfaceCastable in the .NET 5 projection #369
Changes from 19 commits
4be3620
7ad98c8
58c590a
6e455f3
686cead
4fd093b
89a83ee
6511ae6
bcaf88e
cc30448
1f2efee
1f4d869
25e4e4b
b58f37d
a02a72c
b5c3c31
597a024
229fead
c38b4a2
471979e
ba117da
1cb8c01
4418c1b
80ccff5
94294d2
b06d2d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ public enum TrustLevel | |
// IInspectable | ||
[ObjectReferenceWrapper(nameof(_obj))] | ||
[Guid("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90")] | ||
public class IInspectable | ||
public partial class IInspectable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. partial only to combine with IInspectable.net5.cs? #if NET5_0 might be simpler There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that IInspectable implements an extra interface in .NET 5.0, we'd have to add quite a few |
||
{ | ||
[Guid("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90")] | ||
public unsafe struct Vftbl | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
|
||
namespace WinRT | ||
{ | ||
public partial class IInspectable : IWinRTObject | ||
{ | ||
IObjectReference IWinRTObject.NativeObject => _obj; | ||
|
||
ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> IWinRTObject.QueryInterfaceCache { get; } = new(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Runtime.InteropServices; | ||
using WinRT.Interop; | ||
|
||
namespace WinRT | ||
{ | ||
public interface IWinRTObject : IDynamicInterfaceCastable | ||
{ | ||
bool IDynamicInterfaceCastable.IsInterfaceImplemented(RuntimeTypeHandle interfaceType, bool throwIfNotImplemented) | ||
{ | ||
if (QueryInterfaceCache.ContainsKey(interfaceType)) | ||
{ | ||
return true; | ||
} | ||
Type type = Type.GetTypeFromHandle(interfaceType); | ||
Type helperType = type.FindHelperType(); | ||
if (helperType is null || !helperType.IsInterface) | ||
{ | ||
return false; | ||
} | ||
int hr = NativeObject.TryAs<IUnknownVftbl>(GuidGenerator.GetIID(helperType), out var objRef); | ||
if (hr < 0) | ||
{ | ||
if (throwIfNotImplemented) | ||
{ | ||
ExceptionHelpers.ThrowExceptionForHR(hr); | ||
} | ||
return false; | ||
} | ||
var vftblType = helperType.GetNestedType("Vftbl"); | ||
if (vftblType is null) | ||
{ | ||
// The helper type might not have a vftbl type if it was linked away. | ||
// The only time the Vftbl type would be linked away is when we don't actually use | ||
// any of the methods on the interface (it was just a type cast/"is Type" check). | ||
// In that case, we can use the IUnknownVftbl-typed ObjectReference since | ||
// it has all of the information we'll need. | ||
if (!QueryInterfaceCache.TryAdd(interfaceType, objRef)) | ||
{ | ||
objRef.Dispose(); | ||
} | ||
return true; | ||
} | ||
if (vftblType.IsGenericTypeDefinition) | ||
{ | ||
vftblType = vftblType.MakeGenericType(interfaceType.GetType().GetGenericArguments()); | ||
} | ||
using (objRef) | ||
{ | ||
IObjectReference typedObjRef = (IObjectReference)typeof(IObjectReference).GetMethod("As", Type.EmptyTypes).MakeGenericMethod(vftblType).Invoke(objRef, null); | ||
if (!QueryInterfaceCache.TryAdd(interfaceType, typedObjRef)) | ||
{ | ||
typedObjRef.Dispose(); | ||
} | ||
return true; | ||
} | ||
} | ||
|
||
RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(RuntimeTypeHandle interfaceType) | ||
{ | ||
var helperType = Type.GetTypeFromHandle(interfaceType).GetHelperType(); | ||
if (helperType.IsInterface) | ||
return helperType.TypeHandle; | ||
return default; | ||
} | ||
|
||
IObjectReference NativeObject { get; } | ||
|
||
protected ConcurrentDictionary<RuntimeTypeHandle, IObjectReference> QueryInterfaceCache { get; } | ||
|
||
IObjectReference GetObjectReferenceForType(RuntimeTypeHandle type) | ||
{ | ||
return QueryInterfaceCache[type]; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how come the ThisPtr check was removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no longer a
ThisPtr
property exposed because it makes the public surface area not match the WinMD contract and it isn't entirely accurate for composed types. There's no good reason to use theThisPtr
property, so I removed it early in the design.