3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // <OWNER>Microsoft</OWNER>
10 using System.StubHelpers;
11 using System.Reflection;
12 using System.Diagnostics.Contracts;
13 using System.Runtime.InteropServices;
14 using System.Collections;
15 using System.Collections.Generic;
16 using System.Runtime.CompilerServices;
17 using System.Security;
19 namespace System.Runtime.InteropServices.WindowsRuntime
22 [Guid("7C925755-3E48-42B4-8677-76372267033F")]
23 [WindowsRuntimeImport]
24 internal interface ICustomPropertyProvider
27 ICustomProperty GetCustomProperty(string name);
30 ICustomProperty GetIndexedProperty(string name, Type indexParameterType);
33 string GetStringRepresentation();
43 // Implementation helpers
45 internal static class ICustomPropertyProviderImpl
48 // Creates a ICustomProperty implementation for Jupiter
49 // Called from ICustomPropertyProvider_GetProperty from within runtime
51 static internal ICustomProperty CreateProperty(object target, string propertyName)
53 Contract.Requires(target != null);
54 Contract.Requires(propertyName != null);
56 // Only return public instance/static properties
57 PropertyInfo propertyInfo = target.GetType().GetProperty(
59 BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
61 if (propertyInfo == null)
64 return new CustomPropertyImpl(propertyInfo);
68 // Creates a ICustomProperty implementation for Jupiter
69 // Called from ICustomPropertyProvider_GetIndexedProperty from within runtime
71 [System.Security.SecurityCritical]
72 static internal unsafe ICustomProperty CreateIndexedProperty(object target, string propertyName, TypeNameNative *pIndexedParamType)
74 Contract.Requires(target != null);
75 Contract.Requires(propertyName != null);
77 Type indexedParamType = null;
78 SystemTypeMarshaler.ConvertToManaged(pIndexedParamType, ref indexedParamType);
80 return CreateIndexedProperty(target, propertyName, indexedParamType);
83 static internal ICustomProperty CreateIndexedProperty(object target, string propertyName, Type indexedParamType)
85 Contract.Requires(target != null);
86 Contract.Requires(propertyName != null);
88 // Only return public instance/static properties
89 PropertyInfo propertyInfo = target.GetType().GetProperty(
91 BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public,
92 null, // default binder
93 null, // ignore return type
94 new Type[] { indexedParamType }, // indexed parameter type
95 null // ignore type modifier
98 if (propertyInfo == null)
101 return new CustomPropertyImpl(propertyInfo);
104 [System.Security.SecurityCritical]
105 static internal unsafe void GetType(object target, TypeNameNative *pIndexedParamType)
107 SystemTypeMarshaler.ConvertToNative(target.GetType(), pIndexedParamType);
112 enum InterfaceForwardingSupport
115 IBindableVector = 0x1, // IBindableVector -> IBindableVector
116 IVector = 0x2, // IBindableVector -> IVector<T>
117 IBindableVectorView = 0x4, // IBindableVectorView -> IBindableVectorView
118 IVectorView = 0x8, // IBindableVectorView -> IVectorView<T>
119 IBindableIterableOrIIterable= 0x10 // IBindableIterable -> IBindableIterable/IIterable<T>
123 // Interface for data binding code (CustomPropertyImpl) to retreive the target object
124 // See CustomPropertyImpl.InvokeInternal for details
126 internal interface IGetProxyTarget
132 // Proxy that supports data binding on another object
134 // This serves two purposes:
136 // 1. Delegate data binding interfaces to another object
137 // Note that this proxy implements the native interfaces directly to avoid unnecessary overhead
138 // (such as the adapter code that addresses behavior differences between IBindableVector & List
139 // as well as simplify forwarding code (except for IEnumerable)
141 // 2. ICLRServices.CreateManagedReference will hand out ICCW* of a new instance of this object
142 // and will hold the other object alive
145 internal class ICustomPropertyProviderProxy<T1, T2> : IGetProxyTarget,
146 ICustomPropertyProvider,
147 ICustomQueryInterface,
148 IEnumerable, // IBindableIterable -> IBindableIterable/IIterable<T>
149 IBindableVector, // IBindableVector -> IBindableVector/IVector<T>
150 IBindableVectorView // IBindableVectorView -> IBindableVectorView/IVectorView<T>
152 private object _target;
153 private InterfaceForwardingSupport _flags;
155 internal ICustomPropertyProviderProxy(object target, InterfaceForwardingSupport flags)
162 // Creates a new instance of ICustomPropertyProviderProxy<T1, T2> and assign appropriate
165 internal static object CreateInstance(object target)
167 InterfaceForwardingSupport supportFlags = InterfaceForwardingSupport.None;
170 // QI and figure out the right flags
172 if (target as IList != null)
173 supportFlags |= InterfaceForwardingSupport.IBindableVector;
175 // NOTE: We need to use the directed type here
176 // If we use IVector_Raw<T1> here, it derives from a different IIterable<T> which the runtime
177 // doesn't recognize, and therefore IEnumerable cast won't be able to take advantage of this QI
178 if (target as IList<T1> != null)
179 supportFlags |= InterfaceForwardingSupport.IVector;
181 if (target as IBindableVectorView != null)
182 supportFlags |= InterfaceForwardingSupport.IBindableVectorView;
184 // NOTE: We need to use the redirected type here
185 // If we use IVector_Raw<T1> here, it derives from a different IIterable<T> which the runtime
186 // doesn't recognize, and therefore IEnumerable cast won't be able to take advantage of this QI
187 if (target as IReadOnlyList<T2> != null)
188 supportFlags |= InterfaceForwardingSupport.IVectorView;
190 // Verify IEnumerable last because the first few QIs might succeed and we need
191 // IEnumerable cast to use that cache (instead of having ICustomPropertyProvider to
192 // forward it manually)
193 // For example, if we try to shoot in the dark by trying IVector<IInspectable> and it
194 // succeeded, IEnumerable needs to know that
195 if (target as IEnumerable != null)
196 supportFlags |= InterfaceForwardingSupport.IBindableIterableOrIIterable;
198 return new ICustomPropertyProviderProxy<T1, T2>(target, supportFlags);
202 // ICustomPropertyProvider implementation
204 ICustomProperty ICustomPropertyProvider.GetCustomProperty(string name)
206 return ICustomPropertyProviderImpl.CreateProperty(_target, name);
209 ICustomProperty ICustomPropertyProvider.GetIndexedProperty(string name, Type indexParameterType)
211 return ICustomPropertyProviderImpl.CreateIndexedProperty(_target, name, indexParameterType);
214 string ICustomPropertyProvider.GetStringRepresentation()
216 return WindowsRuntime.IStringableHelper.ToString(_target);
219 Type ICustomPropertyProvider.Type
223 return _target.GetType();
228 // override ToString() to make sure callers get correct IStringable.ToString() behavior in native code
230 public override string ToString()
232 return WindowsRuntime.IStringableHelper.ToString(_target);
236 // IGetProxyTarget - unwraps the target object and use it for data binding
238 object IGetProxyTarget.GetTarget()
244 // ICustomQueryInterface methods
246 [System.Security.SecurityCritical]
247 public CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv)
251 if (iid == typeof(IBindableIterable).GUID)
253 // Reject the QI if target doesn't implement IEnumerable
254 if ((_flags & (InterfaceForwardingSupport.IBindableIterableOrIIterable)) == 0)
255 return CustomQueryInterfaceResult.Failed;
258 if (iid == typeof(IBindableVector).GUID)
260 // Reject the QI if target doesn't implement IBindableVector/IVector
261 if ((_flags & (InterfaceForwardingSupport.IBindableVector | InterfaceForwardingSupport.IVector)) == 0)
262 return CustomQueryInterfaceResult.Failed;
265 if (iid == typeof(IBindableVectorView).GUID)
267 // Reject the QI if target doesn't implement IBindableVectorView/IVectorView
268 if ((_flags & (InterfaceForwardingSupport.IBindableVectorView | InterfaceForwardingSupport.IVectorView)) == 0)
269 return CustomQueryInterfaceResult.Failed;
272 return CustomQueryInterfaceResult.NotHandled;
276 // IEnumerable methods
278 public IEnumerator GetEnumerator()
280 return ((IEnumerable)_target).GetEnumerator();
284 // IBindableVector implementation (forwards to IBindableVector / IVector<T>)
287 object IBindableVector.GetAt(uint index)
289 IBindableVector bindableVector = GetIBindableVectorNoThrow();
290 if (bindableVector != null)
292 // IBindableVector -> IBindableVector
293 return bindableVector.GetAt(index);
297 // IBindableVector -> IVector<T>
298 return GetVectorOfT().GetAt(index);
303 uint IBindableVector.Size
307 IBindableVector bindableVector = GetIBindableVectorNoThrow();
308 if (bindableVector != null)
310 // IBindableVector -> IBindableVector
311 return bindableVector.Size;
315 // IBindableVector -> IVector<T>
316 return GetVectorOfT().Size;
322 IBindableVectorView IBindableVector.GetView()
324 IBindableVector bindableVector = GetIBindableVectorNoThrow();
325 if (bindableVector != null)
327 // IBindableVector -> IBindableVector
328 return bindableVector.GetView();
332 // IBindableVector -> IVector<T>
333 return new IVectorViewToIBindableVectorViewAdapter<T1>(GetVectorOfT().GetView());
337 private sealed class IVectorViewToIBindableVectorViewAdapter<T> : IBindableVectorView
339 private IVectorView<T> _vectorView;
341 public IVectorViewToIBindableVectorViewAdapter(IVectorView<T> vectorView)
343 this._vectorView = vectorView;
347 object IBindableVectorView.GetAt(uint index)
349 return _vectorView.GetAt(index);
353 uint IBindableVectorView.Size
357 return _vectorView.Size;
362 bool IBindableVectorView.IndexOf(object value, out uint index)
364 return _vectorView.IndexOf(ConvertTo<T>(value), out index);
367 IBindableIterator IBindableIterable.First()
369 return new IteratorOfTToIteratorAdapter<T>(_vectorView.First());
375 bool IBindableVector.IndexOf(object value, out uint index)
377 IBindableVector bindableVector = GetIBindableVectorNoThrow();
378 if (bindableVector != null)
380 // IBindableVector -> IBindableVector
381 return bindableVector.IndexOf(value, out index);
385 // IBindableVector -> IVector<T>
386 return GetVectorOfT().IndexOf(ConvertTo<T1>(value), out index);
390 void IBindableVector.SetAt(uint index, object value)
392 IBindableVector bindableVector = GetIBindableVectorNoThrow();
393 if (bindableVector != null)
395 // IBindableVector -> IBindableVector
396 bindableVector.SetAt(index, value);
400 // IBindableVector -> IVector<T>
401 GetVectorOfT().SetAt(index, ConvertTo<T1>(value));
405 void IBindableVector.InsertAt(uint index, object value)
407 IBindableVector bindableVector = GetIBindableVectorNoThrow();
408 if (bindableVector != null)
410 // IBindableVector -> IBindableVector
411 bindableVector.InsertAt(index, value);
415 // IBindableVector -> IVector<T>
416 GetVectorOfT().InsertAt(index, ConvertTo<T1>(value));
420 void IBindableVector.RemoveAt(uint index)
422 IBindableVector bindableVector = GetIBindableVectorNoThrow();
423 if (bindableVector != null)
425 // IBindableVector -> IBindableVector
426 bindableVector.RemoveAt(index);
430 // IBindableVector -> IVector<T>
431 GetVectorOfT().RemoveAt(index);
435 void IBindableVector.Append(object value)
437 IBindableVector bindableVector = GetIBindableVectorNoThrow();
438 if (bindableVector != null)
440 // IBindableVector -> IBindableVector
441 bindableVector.Append(value);
445 // IBindableVector -> IVector<T>
446 GetVectorOfT().Append(ConvertTo<T1>(value));
450 void IBindableVector.RemoveAtEnd()
452 IBindableVector bindableVector = GetIBindableVectorNoThrow();
453 if (bindableVector != null)
455 // IBindableVector -> IBindableVector
456 bindableVector.RemoveAtEnd();
460 // IBindableVector -> IVector<T>
461 GetVectorOfT().RemoveAtEnd();
465 void IBindableVector.Clear()
467 IBindableVector bindableVector = GetIBindableVectorNoThrow();
468 if (bindableVector != null)
470 // IBindableVector -> IBindableVector
471 bindableVector.Clear();
475 // IBindableVector -> IVector<T>
476 GetVectorOfT().Clear();
480 [SecuritySafeCritical]
481 private IBindableVector GetIBindableVectorNoThrow()
483 if ((_flags & InterfaceForwardingSupport.IBindableVector) != 0)
484 return JitHelpers.UnsafeCast<IBindableVector>(_target);
489 [SecuritySafeCritical]
490 private IVector_Raw<T1> GetVectorOfT()
492 if ((_flags & InterfaceForwardingSupport.IVector) != 0)
493 return JitHelpers.UnsafeCast<IVector_Raw<T1>>(_target);
495 throw new InvalidOperationException(); // We should not go down this path, unless Jupiter pass this out to managed code
496 // and managed code use reflection to do the cast
500 // IBindableVectorView implementation (forwarding to IBindableVectorView or IVectorView<T>)
503 object IBindableVectorView.GetAt(uint index)
505 IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
506 if (bindableVectorView != null)
507 return bindableVectorView.GetAt(index);
509 return GetVectorViewOfT().GetAt(index);
513 uint IBindableVectorView.Size
517 IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
518 if (bindableVectorView != null)
519 return bindableVectorView.Size;
521 return GetVectorViewOfT().Size;
526 bool IBindableVectorView.IndexOf(object value, out uint index)
528 IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
529 if (bindableVectorView != null)
530 return bindableVectorView.IndexOf(value, out index);
532 return GetVectorViewOfT().IndexOf(ConvertTo<T2>(value), out index);
535 IBindableIterator IBindableIterable.First()
537 IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
538 if (bindableVectorView != null)
539 return bindableVectorView.First();
541 return new IteratorOfTToIteratorAdapter<T2>(GetVectorViewOfT().First());
544 private sealed class IteratorOfTToIteratorAdapter<T> : IBindableIterator
546 private IIterator<T> _iterator;
548 public IteratorOfTToIteratorAdapter(IIterator<T> iterator)
549 { this._iterator = iterator; }
551 public bool HasCurrent { get { return _iterator.HasCurrent; } }
552 public object Current { get { return (object)_iterator.Current; } }
553 public bool MoveNext() { return _iterator.MoveNext(); }
556 [SecuritySafeCritical]
557 private IBindableVectorView GetIBindableVectorViewNoThrow()
559 if ((_flags & InterfaceForwardingSupport.IBindableVectorView) != 0)
560 return JitHelpers.UnsafeCast<IBindableVectorView>(_target);
565 [SecuritySafeCritical]
566 private IVectorView<T2> GetVectorViewOfT()
568 if ((_flags & InterfaceForwardingSupport.IVectorView) != 0)
569 return JitHelpers.UnsafeCast<IVectorView<T2>>(_target);
571 throw new InvalidOperationException(); // We should not go down this path, unless Jupiter pass this out to managed code
572 // and managed code use reflection to do the cast
578 private static T ConvertTo<T>(object value)
580 // Throw ArgumentNullException if value is null (otherwise we'll throw NullReferenceException
581 // when casting value to T)
582 ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value);
584 // No coersion support needed. If we need coersion later, this is the place