Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System / compmod / system / collections / specialized / marshalinghelpers.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 //
7 // <OWNER>[....]</OWNER>
8
9 using System.Security;
10 using System.Collections;
11 using System.ComponentModel;
12 using System.Diagnostics.Contracts;
13 using System.Collections.Specialized;
14 using System.Runtime.CompilerServices;
15 using System.Windows.Input;
16
17 namespace System.Runtime.InteropServices.WindowsRuntime
18 {
19     // Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChangedEventArgs
20     [ComImport]
21     [Guid("4cf68d33-e3f2-4964-b85e-945b4f7e2f21")]
22     [WindowsRuntimeImport]
23     internal interface INotifyCollectionChangedEventArgs
24     {
25         NotifyCollectionChangedAction Action { get; }
26         IList NewItems { get; }
27         IList OldItems { get; }
28         int NewStartingIndex { get; }
29         int OldStartingIndex { get; }
30     }
31
32     // Local definition of Windows.UI.Xaml.Data.IPropertyChangedEventArgs
33     [ComImport]
34     [Guid("4f33a9a0-5cf4-47a4-b16f-d7faaf17457e")]
35     [WindowsRuntimeImport]
36     internal interface IPropertyChangedEventArgs
37     {
38         string PropertyName { get; }
39     }
40
41     // Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChanged
42     [ComImport]
43     [Guid("28b167d5-1a31-465b-9b25-d5c3ae686c40")]
44     [WindowsRuntimeImport]
45     internal interface INotifyCollectionChanged_WinRT
46     {
47         EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value);
48         void remove_CollectionChanged(EventRegistrationToken token);
49     }
50
51     // Local definition of Windows.UI.Xaml.Data.INotifyPropertyChanged
52     [ComImport]
53     [Guid("cf75d69c-f2f4-486b-b302-bb4c09baebfa")]
54     [WindowsRuntimeImport]
55     internal interface INotifyPropertyChanged_WinRT
56     {
57         EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value);
58         void remove_PropertyChanged(EventRegistrationToken token);
59     }
60
61     // Local definition of Windows.UI.Xaml.Input.ICommand
62     [ComImport]
63     [Guid("e5af3542-ca67-4081-995b-709dd13792df")]
64     [WindowsRuntimeImport]
65     internal interface ICommand_WinRT
66     {
67         EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value);
68         void remove_CanExecuteChanged(EventRegistrationToken token);
69         bool CanExecute(object parameter);
70         void Execute(object parameter);
71     }
72
73     // Local definition of Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler
74     [Guid("ca10b37c-f382-4591-8557-5e24965279b0")]
75     [WindowsRuntimeImport]
76     internal delegate void NotifyCollectionChangedEventHandler_WinRT(object sender, NotifyCollectionChangedEventArgs e);
77
78     // Local definition of Windows.UI.Xaml.Data.PropertyChangedEventHandler
79     [Guid("50f19c16-0a22-4d8e-a089-1ea9951657d2")]
80     [WindowsRuntimeImport]
81     internal delegate void PropertyChangedEventHandler_WinRT(object sender, PropertyChangedEventArgs e);
82
83     internal static class NotifyCollectionChangedEventArgsMarshaler
84     {
85         // Extracts properties from a managed NotifyCollectionChangedEventArgs and passes them to
86         // a VM-implemented helper that creates a WinRT NotifyCollectionChangedEventArgs instance.
87         // This method is called from IL stubs and needs to have its token stabilized.
88         [SecurityCritical]
89         static internal IntPtr ConvertToNative(NotifyCollectionChangedEventArgs managedArgs)
90         {
91             if (managedArgs == null)
92                 return IntPtr.Zero;
93
94             return System.StubHelpers.EventArgsMarshaler.CreateNativeNCCEventArgsInstance(
95                         (int)managedArgs.Action,
96                         managedArgs.NewItems,
97                         managedArgs.OldItems,
98                         managedArgs.NewStartingIndex,
99                         managedArgs.OldStartingIndex);
100         }
101
102         // Extracts properties from a WinRT NotifyCollectionChangedEventArgs and creates a new
103         // managed NotifyCollectionChangedEventArgs instance.
104         // This method is called from IL stubs and needs to have its token stabilized.
105         [SecurityCritical]
106         static internal NotifyCollectionChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
107         {
108             if (nativeArgsIP == IntPtr.Zero)
109                 return null;
110
111             object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
112             INotifyCollectionChangedEventArgs nativeArgs = (INotifyCollectionChangedEventArgs)obj;
113
114             return new NotifyCollectionChangedEventArgs(
115                         nativeArgs.Action,
116                         nativeArgs.NewItems,
117                         nativeArgs.OldItems,
118                         nativeArgs.NewStartingIndex,
119                         nativeArgs.OldStartingIndex);
120         }
121     }
122
123     internal static class PropertyChangedEventArgsMarshaler
124     {
125         // Extracts PropertyName from a managed PropertyChangedEventArgs and passes them to
126         // a VM-implemented helper that creates a WinRT PropertyChangedEventArgs instance.
127         // This method is called from IL stubs and needs to have its token stabilized.
128         [SecurityCritical]
129         static internal IntPtr ConvertToNative(PropertyChangedEventArgs managedArgs)
130         {
131             if (managedArgs == null)
132                 return IntPtr.Zero;
133
134             return System.StubHelpers.EventArgsMarshaler.CreateNativePCEventArgsInstance(managedArgs.PropertyName);
135         }
136
137         // Extracts properties from a WinRT PropertyChangedEventArgs and creates a new
138         // managed PropertyChangedEventArgs instance.
139         // This method is called from IL stubs and needs to have its token stabilized.
140         [SecurityCritical]
141         static internal PropertyChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
142         {
143             if (nativeArgsIP == IntPtr.Zero)
144                 return null;
145
146             object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
147             IPropertyChangedEventArgs nativeArgs = (IPropertyChangedEventArgs)obj;
148
149             return new PropertyChangedEventArgs(nativeArgs.PropertyName);
150         }
151     }
152
153     // This is a set of stub methods implementing the support for the managed INotifyCollectionChanged
154     // interface on WinRT objects that support the WinRT INotifyCollectionChanged. Used by the interop
155     // mashaling infrastructure.
156     internal sealed class NotifyCollectionChangedToManagedAdapter
157     {
158         private NotifyCollectionChangedToManagedAdapter()
159         {
160             Contract.Assert(false, "This class is never instantiated");
161         }
162
163         internal event NotifyCollectionChangedEventHandler CollectionChanged
164         {
165             // void CollectionChanged.add(NotifyCollectionChangedEventHandler)
166             [SecurityCritical]
167             add
168             {
169                 INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
170
171                 // call the WinRT eventing support in mscorlib to subscribe the event
172                 Func<NotifyCollectionChangedEventHandler, EventRegistrationToken> addMethod =
173                     new Func<NotifyCollectionChangedEventHandler, EventRegistrationToken>(_this.add_CollectionChanged);
174                 Action<EventRegistrationToken> removeMethod =
175                     new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
176
177                 WindowsRuntimeMarshal.AddEventHandler<NotifyCollectionChangedEventHandler>(addMethod, removeMethod, value);
178             }
179
180             // void CollectionChanged.remove(NotifyCollectionChangedEventHandler)
181             [SecurityCritical]
182             remove
183             {
184                 INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
185
186                 // call the WinRT eventing support in mscorlib to unsubscribe the event
187                 Action<EventRegistrationToken> removeMethod =
188                     new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
189
190                 WindowsRuntimeMarshal.RemoveEventHandler<NotifyCollectionChangedEventHandler>(removeMethod, value);
191             }
192         }
193     }
194
195     // This is a set of stub methods implementing the support for the WinRT INotifyCollectionChanged
196     // interface on managed objects that support the managed INotifyCollectionChanged. Used by the interop
197     // mashaling infrastructure.
198     internal sealed class NotifyCollectionChangedToWinRTAdapter
199     {
200         private NotifyCollectionChangedToWinRTAdapter()
201         {
202             Contract.Assert(false, "This class is never instantiated");
203         }
204
205         // An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
206         // Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
207         // separately, associated with the implementations using ConditionalWeakTable.
208         private static ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>> m_weakTable =
209             new ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>>();
210
211         // EventRegistrationToken CollectionChanged.add(NotifyCollectionChangedEventHandler value)
212         [SecurityCritical]
213         internal EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value)
214         {
215             INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
216             EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
217
218             EventRegistrationToken token = table.AddEventHandler(value);
219             _this.CollectionChanged += value;
220
221             return token;
222         }
223
224         // void CollectionChanged.remove(EventRegistrationToken token)
225         [SecurityCritical]
226         internal void remove_CollectionChanged(EventRegistrationToken token)
227         {
228             INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
229             EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
230
231             NotifyCollectionChangedEventHandler handler = table.ExtractHandler(token);
232             if (handler != null)
233             {
234                 _this.CollectionChanged -= handler;
235             }
236         }
237     }
238
239     // This is a set of stub methods implementing the support for the managed INotifyPropertyChanged
240     // interface on WinRT objects that support the WinRT INotifyPropertyChanged. Used by the interop
241     // mashaling infrastructure.
242     internal sealed class NotifyPropertyChangedToManagedAdapter
243     {
244         private NotifyPropertyChangedToManagedAdapter()
245         {
246             Contract.Assert(false, "This class is never instantiated");
247         }
248
249         internal event PropertyChangedEventHandler PropertyChanged
250         {
251             // void PropertyChanged.add(PropertyChangedEventHandler)
252             [SecurityCritical]
253             add
254             {
255                 INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
256
257                 // call the WinRT eventing support in mscorlib to subscribe the event
258                 Func<PropertyChangedEventHandler, EventRegistrationToken> addMethod =
259                     new Func<PropertyChangedEventHandler, EventRegistrationToken>(_this.add_PropertyChanged);
260                 Action<EventRegistrationToken> removeMethod =
261                     new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
262
263                 WindowsRuntimeMarshal.AddEventHandler<PropertyChangedEventHandler>(addMethod, removeMethod, value);
264             }
265
266             // void PropertyChanged.remove(PropertyChangedEventHandler)
267             [SecurityCritical]
268             remove
269             {
270                 INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
271
272                 // call the WinRT eventing support in mscorlib to unsubscribe the event
273                 Action<EventRegistrationToken> removeMethod =
274                     new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
275
276                 WindowsRuntimeMarshal.RemoveEventHandler<PropertyChangedEventHandler>(removeMethod, value);
277             }
278         }
279     }
280
281     // This is a set of stub methods implementing the support for the WinRT INotifyPropertyChanged
282     // interface on managed objects that support the managed INotifyPropertyChanged. Used by the interop
283     // mashaling infrastructure.
284     internal sealed class NotifyPropertyChangedToWinRTAdapter
285     {
286         private NotifyPropertyChangedToWinRTAdapter()
287         {
288             Contract.Assert(false, "This class is never instantiated");
289         }
290
291         // An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
292         // Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
293         // separately, associated with the implementations using ConditionalWeakTable.
294         private static ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>> m_weakTable =
295             new ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>>();
296
297         // EventRegistrationToken PropertyChanged.add(PropertyChangedEventHandler value)
298         [SecurityCritical]
299         internal EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value)
300         {
301             INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
302             EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
303
304             EventRegistrationToken token = table.AddEventHandler(value);
305             _this.PropertyChanged += value;
306
307             return token;
308         }
309
310         // void PropertyChanged.remove(EventRegistrationToken token)
311         [SecurityCritical]
312         internal void remove_PropertyChanged(EventRegistrationToken token)
313         {
314             INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
315             EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
316
317             PropertyChangedEventHandler handler = table.ExtractHandler(token);
318             if (handler != null)
319             {
320                 _this.PropertyChanged -= handler;
321             }
322         }
323     }
324
325     // This is a set of stub methods implementing the support for the managed ICommand
326     // interface on WinRT objects that support the WinRT ICommand_WinRT. 
327     // Used by the interop mashaling infrastructure.
328     // Instances of this are really RCWs of ICommand_WinRT (not ICommandToManagedAdapter or any ICommand).
329     [SecurityCritical]
330     internal sealed class ICommandToManagedAdapter /*: System.Windows.Input.ICommand*/
331     {
332         private static ConditionalWeakTable<EventHandler, EventHandler<object>> m_weakTable =
333             new ConditionalWeakTable<EventHandler, EventHandler<object>>();
334
335         private ICommandToManagedAdapter()
336         {
337             Contract.Assert(false, "This class is never instantiated");
338         }
339
340         private event EventHandler CanExecuteChanged
341         {
342             // void CanExecuteChanged.add(EventHandler)
343             add
344             {
345                 ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
346
347                 // call the WinRT eventing support in mscorlib to subscribe the event
348                 Func<EventHandler<object>, EventRegistrationToken> addMethod =
349                     new Func<EventHandler<object>, EventRegistrationToken>(_this.add_CanExecuteChanged);
350                 Action<EventRegistrationToken> removeMethod =
351                     new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
352
353                 // value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.AddEventHandler)
354                 // expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
355                 EventHandler<object> handler_WinRT = m_weakTable.GetValue(value, ICommandAdapterHelpers.CreateWrapperHandler);
356                 WindowsRuntimeMarshal.AddEventHandler<EventHandler<object>>(addMethod, removeMethod, handler_WinRT);
357             }
358
359             // void CanExecuteChanged.remove(EventHandler)
360             remove
361             {
362                 ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
363
364                 // call the WinRT eventing support in mscorlib to unsubscribe the event
365                 Action<EventRegistrationToken> removeMethod =
366                     new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
367
368                 // value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.RemoveEventHandler)
369                 // expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
370
371                 // Also we do a value check rather than an instance check to ensure that different instances of the same delegates are treated equal.
372                 EventHandler<object> handler_WinRT = ICommandAdapterHelpers.GetValueFromEquivalentKey(m_weakTable , value, ICommandAdapterHelpers.CreateWrapperHandler);
373                 WindowsRuntimeMarshal.RemoveEventHandler<EventHandler<object>>(removeMethod, handler_WinRT);
374             }
375         }
376
377         private bool CanExecute(object parameter)
378         {
379             ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
380             return _this.CanExecute(parameter);
381         }
382
383         private void Execute(object parameter)
384         {
385             ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
386             _this.Execute(parameter);
387         }
388     }
389
390     // This is a set of stub methods implementing the support for the WinRT ICommand_WinRT
391     // interface on managed objects that support the managed ICommand interface.
392     // Used by the interop mashaling infrastructure.
393     // Instances of this are really CCWs of ICommand (not ICommandToWinRTAdapter or any ICommand_WinRT).
394     [SecurityCritical]
395     internal sealed class ICommandToWinRTAdapter /*: ICommand_WinRT*/
396     {
397         private ICommandToWinRTAdapter()
398         {
399             Contract.Assert(false, "This class is never instantiated");
400         }
401
402         // An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
403         // Since here the class can be an arbitrary implementation of ICommand, we have to keep the EventRegistrationTokenTable's
404         // separately, associated with the implementations using ConditionalWeakTable.
405         private static ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>> m_weakTable =
406             new ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>>();
407
408         // EventRegistrationToken PropertyChanged.add(EventHandler<object> value)
409         private EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value)
410         {
411             ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
412             EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
413
414             EventHandler handler = ICommandAdapterHelpers.CreateWrapperHandler(value);
415             EventRegistrationToken token = table.AddEventHandler(handler);
416             _this.CanExecuteChanged += handler;
417
418             return token;
419         }
420
421         // void PropertyChanged.remove(EventRegistrationToken token)
422         private void remove_CanExecuteChanged(EventRegistrationToken token)
423         {
424             ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
425             EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
426
427             EventHandler handler = table.ExtractHandler(token);
428             if (handler != null)
429             {
430                 _this.CanExecuteChanged -= handler;
431             }
432         }
433
434         private bool CanExecute(object parameter)
435         {
436             ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
437             return _this.CanExecute(parameter);
438         }
439
440         private void Execute(object parameter)
441         {
442             ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
443             _this.Execute(parameter);
444         }
445
446     }
447
448     // A couple of ICommand adapter helpers need to be transparent, and so are in their own type
449     internal static class ICommandAdapterHelpers
450     {
451         internal static EventHandler<object> CreateWrapperHandler(EventHandler handler)
452         {
453             // Check whether it is a round-tripping case i.e. the sender is of the type eventArgs,
454             // If so we use it else we pass EventArgs.Empty
455             return (object sender, object e) =>
456                 {
457                     EventArgs eventArgs = e as EventArgs;
458                     handler(sender, (eventArgs == null ? System.EventArgs.Empty : eventArgs));
459                 };
460         }
461
462         internal static EventHandler CreateWrapperHandler(EventHandler<object> handler)
463         {
464             return (object sender, EventArgs e) => handler(sender, e);
465         }
466
467         internal static EventHandler<object> GetValueFromEquivalentKey(
468             ConditionalWeakTable<EventHandler, EventHandler<object>> table,
469             EventHandler key,
470             ConditionalWeakTable<EventHandler, EventHandler<object>>.CreateValueCallback callback)
471         {
472             EventHandler<object> value;
473
474             // Find the key in the table using a value check rather than an instance check.
475             EventHandler existingKey = table.FindEquivalentKeyUnsafe(key, out value);
476             if (existingKey == null)
477             {
478                 value = callback(key);
479                 table.Add(key, value);
480             }
481
482             return value;
483         }
484     }
485 }