Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / interopservices / windowsruntime / icustompropertyprovider.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 //
7 // <OWNER>Microsoft</OWNER>
8
9 using System;
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;
18
19 namespace System.Runtime.InteropServices.WindowsRuntime
20 {
21     [ComImport]
22     [Guid("7C925755-3E48-42B4-8677-76372267033F")]
23     [WindowsRuntimeImport]
24     internal interface ICustomPropertyProvider 
25     {    
26         [Pure]
27         ICustomProperty GetCustomProperty(string name);
28
29         [Pure]
30         ICustomProperty GetIndexedProperty(string name, Type indexParameterType);
31
32         [Pure]
33         string GetStringRepresentation();
34
35         Type Type 
36         { 
37             [Pure]        
38             get; 
39         }
40     }
41
42     //
43     // Implementation helpers
44     //
45     internal static class ICustomPropertyProviderImpl
46     {
47         //
48         // Creates a ICustomProperty implementation for Jupiter
49         // Called from ICustomPropertyProvider_GetProperty from within runtime
50         //
51         static internal ICustomProperty CreateProperty(object target, string propertyName)
52         {
53             Contract.Requires(target != null);
54             Contract.Requires(propertyName != null);
55
56             // Only return public instance/static properties
57             PropertyInfo propertyInfo = target.GetType().GetProperty(
58                 propertyName,
59                 BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
60
61             if (propertyInfo == null)
62                 return null;
63             else
64                 return new CustomPropertyImpl(propertyInfo);
65         }
66
67         //
68         // Creates a ICustomProperty implementation for Jupiter
69         // Called from ICustomPropertyProvider_GetIndexedProperty from within runtime
70         //               
71         [System.Security.SecurityCritical]
72         static internal unsafe ICustomProperty CreateIndexedProperty(object target, string propertyName, TypeNameNative *pIndexedParamType)
73         {
74             Contract.Requires(target != null);
75             Contract.Requires(propertyName != null);
76
77             Type indexedParamType = null;
78             SystemTypeMarshaler.ConvertToManaged(pIndexedParamType, ref indexedParamType);
79
80             return CreateIndexedProperty(target, propertyName, indexedParamType);        
81         }
82
83         static internal ICustomProperty CreateIndexedProperty(object target, string propertyName, Type indexedParamType)
84         {
85             Contract.Requires(target != null);
86             Contract.Requires(propertyName != null);
87
88             // Only return public instance/static properties
89             PropertyInfo propertyInfo = target.GetType().GetProperty(
90                 propertyName,
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
96                 );
97
98             if (propertyInfo == null)
99                 return null;
100             else
101                 return new CustomPropertyImpl(propertyInfo);
102         }
103
104         [System.Security.SecurityCritical]
105         static internal unsafe void GetType(object target, TypeNameNative *pIndexedParamType)
106         {            
107             SystemTypeMarshaler.ConvertToNative(target.GetType(), pIndexedParamType);
108         }        
109     }
110
111     [Flags]
112     enum InterfaceForwardingSupport
113     {
114         None                        = 0,
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>
120     }
121
122     //
123     // Interface for data binding code (CustomPropertyImpl) to retreive the target object
124     // See CustomPropertyImpl.InvokeInternal for details
125     //
126     internal interface IGetProxyTarget
127     {
128         object GetTarget();            
129     }
130     
131     //
132     // Proxy that supports data binding on another object
133     //
134     // This serves two purposes:
135     //
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)
140     //
141     // 2. ICLRServices.CreateManagedReference will hand out ICCW* of a new instance of this object
142     // and will hold the other object alive
143     //
144     //
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>
151     {
152         private object _target;
153         private InterfaceForwardingSupport _flags;
154
155         internal ICustomPropertyProviderProxy(object target, InterfaceForwardingSupport flags)
156         {
157             _target = target;
158             _flags = flags;
159         }
160
161         //
162         // Creates a new instance of ICustomPropertyProviderProxy<T1, T2> and assign appropriate
163         // flags
164         //
165         internal static object CreateInstance(object target)
166         {
167             InterfaceForwardingSupport supportFlags = InterfaceForwardingSupport.None;
168
169             //
170             // QI and figure out the right flags
171             //
172             if (target as IList != null)
173                 supportFlags |= InterfaceForwardingSupport.IBindableVector;
174
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;
180             
181             if (target as IBindableVectorView != null)
182                 supportFlags |= InterfaceForwardingSupport.IBindableVectorView;
183
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;
189
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;
197             
198             return new ICustomPropertyProviderProxy<T1, T2>(target, supportFlags);                
199         }
200
201         //
202         // ICustomPropertyProvider implementation
203         //
204         ICustomProperty ICustomPropertyProvider.GetCustomProperty(string name)
205         {
206             return ICustomPropertyProviderImpl.CreateProperty(_target, name);
207         }
208
209         ICustomProperty ICustomPropertyProvider.GetIndexedProperty(string name, Type indexParameterType)
210         {
211             return ICustomPropertyProviderImpl.CreateIndexedProperty(_target, name, indexParameterType);
212         }
213
214         string ICustomPropertyProvider.GetStringRepresentation()
215         {
216             return WindowsRuntime.IStringableHelper.ToString(_target);
217         }
218
219         Type ICustomPropertyProvider.Type 
220         { 
221             get
222             {
223                 return _target.GetType();
224             }
225         }
226
227         //
228         // override ToString() to make sure callers get correct IStringable.ToString() behavior in native code
229         //
230         public override string ToString()
231         {
232             return WindowsRuntime.IStringableHelper.ToString(_target);
233         }
234
235         //
236         // IGetProxyTarget - unwraps the target object and use it for data binding
237         // 
238         object IGetProxyTarget.GetTarget()
239         {
240             return _target;
241         }
242
243         // 
244         // ICustomQueryInterface methods
245         //    
246         [System.Security.SecurityCritical]
247         public CustomQueryInterfaceResult GetInterface([In]ref Guid iid, out IntPtr ppv)
248         {
249             ppv = IntPtr.Zero;
250
251             if (iid == typeof(IBindableIterable).GUID)
252             {
253                 // Reject the QI if target doesn't implement IEnumerable
254                 if ((_flags & (InterfaceForwardingSupport.IBindableIterableOrIIterable)) == 0)
255                     return CustomQueryInterfaceResult.Failed;                    
256             }
257
258             if (iid == typeof(IBindableVector).GUID)
259             {
260                 // Reject the QI if target doesn't implement IBindableVector/IVector
261                 if ((_flags & (InterfaceForwardingSupport.IBindableVector | InterfaceForwardingSupport.IVector)) == 0)
262                     return CustomQueryInterfaceResult.Failed;                    
263             }
264
265             if (iid == typeof(IBindableVectorView).GUID)
266             {
267                 // Reject the QI if target doesn't implement IBindableVectorView/IVectorView
268                 if ((_flags & (InterfaceForwardingSupport.IBindableVectorView | InterfaceForwardingSupport.IVectorView)) == 0)
269                     return CustomQueryInterfaceResult.Failed;                
270             }
271             
272             return CustomQueryInterfaceResult.NotHandled;
273         }
274     
275         //
276         // IEnumerable methods
277         //
278         public IEnumerator GetEnumerator()
279         {
280             return ((IEnumerable)_target).GetEnumerator();
281         }
282
283         //
284         // IBindableVector implementation (forwards to IBindableVector / IVector<T>)
285         //        
286         [Pure]
287         object IBindableVector.GetAt(uint index)
288         {
289             IBindableVector bindableVector = GetIBindableVectorNoThrow();
290             if (bindableVector != null)
291             {
292                 // IBindableVector -> IBindableVector
293                 return bindableVector.GetAt(index);
294             }
295             else
296             {
297                 // IBindableVector -> IVector<T>
298                 return GetVectorOfT().GetAt(index);
299             }            
300         }
301         
302         [Pure]
303         uint IBindableVector.Size 
304         { 
305             get
306             {            
307                 IBindableVector bindableVector = GetIBindableVectorNoThrow();
308                 if (bindableVector != null)
309                 {
310                     // IBindableVector -> IBindableVector
311                     return bindableVector.Size;
312                 }
313                 else
314                 {
315                     // IBindableVector -> IVector<T>
316                     return GetVectorOfT().Size;
317                 }            
318             }
319         }
320         
321         [Pure]
322         IBindableVectorView IBindableVector.GetView()
323         {
324             IBindableVector bindableVector = GetIBindableVectorNoThrow();
325             if (bindableVector != null)
326             {
327                 // IBindableVector -> IBindableVector
328                 return bindableVector.GetView();
329             }
330             else
331             {
332                 // IBindableVector -> IVector<T>
333                 return new IVectorViewToIBindableVectorViewAdapter<T1>(GetVectorOfT().GetView());
334             }        
335         }
336
337         private sealed class IVectorViewToIBindableVectorViewAdapter<T> : IBindableVectorView
338         {
339             private IVectorView<T> _vectorView;
340
341             public IVectorViewToIBindableVectorViewAdapter(IVectorView<T> vectorView)
342             { 
343                 this._vectorView = vectorView; 
344             }
345
346             [Pure]
347             object IBindableVectorView.GetAt(uint index)
348             {
349                 return _vectorView.GetAt(index);
350             }
351             
352             [Pure]
353             uint IBindableVectorView.Size
354             { 
355                 get
356                 {
357                     return _vectorView.Size;
358                 }
359             }
360             
361             [Pure]
362             bool IBindableVectorView.IndexOf(object value, out uint index)
363             {
364                 return _vectorView.IndexOf(ConvertTo<T>(value), out index);
365             }
366
367             IBindableIterator IBindableIterable.First()
368             {
369                 return new IteratorOfTToIteratorAdapter<T>(_vectorView.First());
370             }
371
372         }         
373         
374         [Pure]
375         bool IBindableVector.IndexOf(object value, out uint index)
376         {
377             IBindableVector bindableVector = GetIBindableVectorNoThrow();
378             if (bindableVector != null)
379             {
380                 // IBindableVector -> IBindableVector
381                 return bindableVector.IndexOf(value, out index);
382             }
383             else
384             {
385                 // IBindableVector -> IVector<T>
386                 return GetVectorOfT().IndexOf(ConvertTo<T1>(value), out index);
387             }            
388         }
389         
390         void IBindableVector.SetAt(uint index, object value)
391         {
392             IBindableVector bindableVector = GetIBindableVectorNoThrow();
393             if (bindableVector != null)
394             {
395                 // IBindableVector -> IBindableVector
396                 bindableVector.SetAt(index, value);
397             }
398             else
399             {
400                 // IBindableVector -> IVector<T>
401                 GetVectorOfT().SetAt(index, ConvertTo<T1>(value));
402             }            
403         }
404         
405         void IBindableVector.InsertAt(uint index, object value)
406         {
407             IBindableVector bindableVector = GetIBindableVectorNoThrow();
408             if (bindableVector != null)
409             {
410                 // IBindableVector -> IBindableVector
411                 bindableVector.InsertAt(index, value);
412             }
413             else
414             {
415                 // IBindableVector -> IVector<T>
416                 GetVectorOfT().InsertAt(index, ConvertTo<T1>(value));
417             }            
418         }
419         
420         void IBindableVector.RemoveAt(uint index)
421         {
422             IBindableVector bindableVector = GetIBindableVectorNoThrow();
423             if (bindableVector != null)
424             {
425                 // IBindableVector -> IBindableVector
426                 bindableVector.RemoveAt(index);
427             }
428             else
429             {
430                 // IBindableVector -> IVector<T>
431                 GetVectorOfT().RemoveAt(index);
432             }            
433         }
434         
435         void IBindableVector.Append(object value)
436         {
437             IBindableVector bindableVector = GetIBindableVectorNoThrow();
438             if (bindableVector != null)
439             {
440                 // IBindableVector -> IBindableVector
441                 bindableVector.Append(value);
442             }
443             else
444             {
445                 // IBindableVector -> IVector<T>
446                 GetVectorOfT().Append(ConvertTo<T1>(value));
447             }            
448         }        
449         
450         void IBindableVector.RemoveAtEnd()
451         {
452             IBindableVector bindableVector = GetIBindableVectorNoThrow();
453             if (bindableVector != null)
454             {
455                 // IBindableVector -> IBindableVector
456                 bindableVector.RemoveAtEnd();
457             }
458             else
459             {
460                 // IBindableVector -> IVector<T>
461                 GetVectorOfT().RemoveAtEnd();
462             }            
463         }
464         
465         void IBindableVector.Clear()
466         {
467             IBindableVector bindableVector = GetIBindableVectorNoThrow();
468             if (bindableVector != null)
469             {
470                 // IBindableVector -> IBindableVector
471                 bindableVector.Clear();
472             }
473             else
474             {
475                 // IBindableVector -> IVector<T>
476                 GetVectorOfT().Clear();
477             }            
478         }
479
480         [SecuritySafeCritical]
481         private IBindableVector GetIBindableVectorNoThrow()
482         {
483             if ((_flags & InterfaceForwardingSupport.IBindableVector) != 0)
484                 return JitHelpers.UnsafeCast<IBindableVector>(_target);
485             else
486                 return null;
487         }
488
489         [SecuritySafeCritical]
490         private IVector_Raw<T1> GetVectorOfT()
491         {
492             if ((_flags & InterfaceForwardingSupport.IVector) != 0)
493                 return JitHelpers.UnsafeCast<IVector_Raw<T1>>(_target);
494             else
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
497         }
498         
499         //
500         // IBindableVectorView implementation (forwarding to IBindableVectorView or IVectorView<T>)
501         //
502         [Pure]
503         object IBindableVectorView.GetAt(uint index)
504         {
505             IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
506             if (bindableVectorView != null)
507                 return bindableVectorView.GetAt(index);
508             else
509                 return GetVectorViewOfT().GetAt(index);
510         }
511         
512         [Pure]
513         uint IBindableVectorView.Size
514         { 
515             get
516             {
517                 IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
518                 if (bindableVectorView != null)
519                     return bindableVectorView.Size;
520                 else
521                     return GetVectorViewOfT().Size;
522             }
523         }
524         
525         [Pure]
526         bool IBindableVectorView.IndexOf(object value, out uint index)
527         {
528             IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
529             if (bindableVectorView != null)
530                 return bindableVectorView.IndexOf(value, out index);
531             else
532                 return GetVectorViewOfT().IndexOf(ConvertTo<T2>(value), out index);
533         }
534
535         IBindableIterator IBindableIterable.First()
536         {
537             IBindableVectorView bindableVectorView = GetIBindableVectorViewNoThrow();
538             if (bindableVectorView != null)
539                 return bindableVectorView.First();
540             else
541                 return new IteratorOfTToIteratorAdapter<T2>(GetVectorViewOfT().First());
542         }
543
544         private sealed class IteratorOfTToIteratorAdapter<T> : IBindableIterator
545         {
546             private IIterator<T> _iterator;
547
548             public IteratorOfTToIteratorAdapter(IIterator<T> iterator)
549             { this._iterator = iterator; }
550
551             public bool HasCurrent { get { return _iterator.HasCurrent; } }
552             public object Current  { get { return (object)_iterator.Current; } }
553             public bool MoveNext() { return _iterator.MoveNext(); }
554         }         
555
556         [SecuritySafeCritical]
557         private IBindableVectorView GetIBindableVectorViewNoThrow()
558         {
559             if ((_flags & InterfaceForwardingSupport.IBindableVectorView) != 0)
560                 return JitHelpers.UnsafeCast<IBindableVectorView>(_target);
561             else
562                 return null;
563         }
564
565         [SecuritySafeCritical]
566         private IVectorView<T2> GetVectorViewOfT()
567         {
568             if ((_flags & InterfaceForwardingSupport.IVectorView) != 0)
569                 return JitHelpers.UnsafeCast<IVectorView<T2>>(_target);
570             else
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
573         }
574
575         //
576         // Convert to type T
577         //
578         private static T ConvertTo<T>(object value)
579         {
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);
583         
584             // No coersion support needed. If we need coersion later, this is the place
585             return (T) value;
586         }
587     }
588 }
589