forked from microsoft/CsWinRT
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCastExtensions.cs
More file actions
134 lines (125 loc) · 5.18 KB
/
CastExtensions.cs
File metadata and controls
134 lines (125 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Reflection;
using WinRT.Interop;
namespace WinRT
{
#if EMBED
internal
#else
public
#endif
static class CastExtensions
{
/// <summary>
/// Cast a WinRT object to an interface type it implements in its implementation
/// even if it doesn't implement it in metadata.
/// </summary>
/// <typeparam name="TInterface">The interface type to cast to.</typeparam>
/// <param name="value">The object.</param>
/// <returns>
/// If <typeparamref name="TInterface"/> is <see cref="object"/>, returns the "default" wrapper for this WinRT object that implements all of the types that this object implements in metadata.
/// If <paramref name="value"/> implements <typeparamref name="TInterface"/> in metadata, casts <paramref name="value"/> to <typeparamref name="TInterface"/>.
/// Otherwise, creates a new wrapper of the underlying WinRT object that implements <typeparamref name="TInterface"/>.
/// </returns>
/// <exception cref="ArgumentException">Thrown if the runtime type of <paramref name="value"/> is not a projected type (if the object is a managed object).</exception>
public static TInterface As<TInterface>(this object value)
{
if (typeof(TInterface) == typeof(object))
{
if (TryGetRefForObject(value, allowComposed: false, out IObjectReference objRef))
{
using (objRef)
{
return ComWrappersSupport.CreateRcwForComObject<TInterface>(objRef.ThisPtr);
}
}
}
if (value is TInterface convertableInMetadata)
{
return convertableInMetadata;
}
using (var objRef = GetRefForObject(value))
{
return objRef.AsInterface<TInterface>();
}
}
/// <summary>
/// Create an agile reference for a given WinRT object. The agile reference can be passed to another apartment
/// within the process from which the original object can be retrieved even if it wasn't agile.
/// </summary>
/// <typeparam name="T">Type of WinRT object.</typeparam>
/// <param name="value">The object.</param>
/// <returns>
/// If <paramref name="value"/> is a WinRT object, returns a AgileReference for it.
/// Otherwise, returns null.
/// </returns>
/// <exception cref="InvalidOperationException">Thrown if the runtime type of <paramref name="value"/> is not a projected type.</exception>
public static AgileReference<T> AsAgile<T>(this T value) where T : class
{
if(value == null)
{
return new AgileReference<T>(null);
}
var marshal = Marshaler<T>.CreateMarshaler2(value);
try
{
if (marshal is IObjectReference objref)
{
return new AgileReference<T>(objref);
}
else if (marshal is ObjectReferenceValue objrefValue)
{
return new AgileReference<T>(objrefValue);
}
}
finally
{
Marshaler<T>.DisposeMarshaler(marshal);
}
throw new InvalidOperationException($"Object type is not a projected type: {nameof(value)}.");
}
private static bool TryGetRefForObject(object value, bool allowComposed, out IObjectReference reference)
{
if (ComWrappersSupport.TryUnwrapObject(value, out var objRef))
{
reference = objRef.As<IUnknownVftbl>();
return true;
}
else if (allowComposed && TryGetComposedRefForQI(value, out objRef))
{
reference = objRef.As<IUnknownVftbl>();
return true;
}
reference = null;
return false;
}
private static IObjectReference GetRefForObject(object value)
{
return TryGetRefForObject(value, allowComposed: true, out var objRef) ? objRef
: throw new ArgumentException("Source object type is not a projected type and does not inherit from a projected type.", nameof(value));
}
private static bool TryGetComposedRefForQI(object value, out IObjectReference objRef)
{
#if !NET
var getReferenceMethod = value.GetType().GetMethod("GetDefaultReference", BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(typeof(IUnknownVftbl));
if (getReferenceMethod is null)
{
objRef = null;
return false;
}
objRef = (IObjectReference)getReferenceMethod.Invoke(value, Array.Empty<object>());
return true;
#else
if(value is IWinRTObject winrtObj)
{
objRef = winrtObj.NativeObject;
return true;
}
objRef = null;
return false;
#endif
}
}
}