1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
8 using System.Collections;
9 using System.Diagnostics;
10 using System.Reflection;
11 using System.Security;
13 namespace System.Runtime.InteropServices.WindowsRuntime
15 internal sealed class CLRIReferenceImpl<T> : CLRIPropertyValueImpl, IReference<T>, IGetProxyTarget
19 public CLRIReferenceImpl(PropertyType type, T obj)
22 Debug.Assert(obj != null, "Must not be null");
28 get { return _value; }
31 public override string ToString()
35 return _value.ToString();
39 return base.ToString();
43 object IGetProxyTarget.GetTarget()
45 return (object)_value;
48 // We have T in an IReference<T>. Need to QI for IReference<T> with the appropriate GUID, call
49 // the get_Value property, allocate an appropriately-sized managed object, marshal the native object
50 // to the managed object, and free the native method. Also we want the return value boxed (aka normal value type boxing).
52 // This method is called by VM.
53 internal static Object UnboxHelper(Object wrapper)
55 Debug.Assert(wrapper != null);
56 IReference<T> reference = (IReference<T>)wrapper;
57 Debug.Assert(reference != null, "CLRIReferenceImpl::UnboxHelper - QI'ed for IReference<" + typeof(T) + ">, but that failed.");
58 return reference.Value;
62 // T can be any WinRT-compatible type
63 internal sealed class CLRIReferenceArrayImpl<T> : CLRIPropertyValueImpl,
66 IList // Jupiter data binding needs IList/IEnumerable
71 public CLRIReferenceArrayImpl(PropertyType type, T[] obj)
74 Debug.Assert(obj != null, "Must not be null");
78 _list = (IList)_value;
83 get { return _value; }
86 public override string ToString()
90 return _value.ToString();
94 return base.ToString();
99 // IEnumerable methods. Used by data-binding in Jupiter when you try to data bind
100 // against a managed array
102 IEnumerator IEnumerable.GetEnumerator()
104 return ((IEnumerable)_value).GetEnumerator();
108 // IList & ICollection methods.
109 // This enables two-way data binding and index access in Jupiter
111 Object IList.this[int index]
120 _list[index] = value;
124 int IList.Add(Object value)
126 return _list.Add(value);
129 bool IList.Contains(Object value)
131 return _list.Contains(value);
139 bool IList.IsReadOnly
143 return _list.IsReadOnly;
147 bool IList.IsFixedSize
151 return _list.IsFixedSize;
155 int IList.IndexOf(Object value)
157 return _list.IndexOf(value);
160 void IList.Insert(int index, Object value)
162 _list.Insert(index, value);
165 void IList.Remove(Object value)
170 void IList.RemoveAt(int index)
172 _list.RemoveAt(index);
175 void ICollection.CopyTo(Array array, int index)
177 _list.CopyTo(array, index);
180 int ICollection.Count
188 Object ICollection.SyncRoot
192 return _list.SyncRoot;
196 bool ICollection.IsSynchronized
200 return _list.IsSynchronized;
204 object IGetProxyTarget.GetTarget()
206 return (object)_value;
209 // We have T in an IReferenceArray<T>. Need to QI for IReferenceArray<T> with the appropriate GUID, call
210 // the get_Value property, allocate an appropriately-sized managed object, marshal the native object
211 // to the managed object, and free the native method.
213 // This method is called by VM.
214 internal static Object UnboxHelper(Object wrapper)
216 Debug.Assert(wrapper != null);
217 IReferenceArray<T> reference = (IReferenceArray<T>)wrapper;
218 Debug.Assert(reference != null, "CLRIReferenceArrayImpl::UnboxHelper - QI'ed for IReferenceArray<" + typeof(T) + ">, but that failed.");
219 T[] marshaled = reference.Value;
224 // For creating instances of Windows Runtime's IReference<T> and IReferenceArray<T>.
225 internal static class IReferenceFactory
227 internal static readonly Type s_pointType = Type.GetType("Windows.Foundation.Point, " + AssemblyRef.SystemRuntimeWindowsRuntime);
228 internal static readonly Type s_rectType = Type.GetType("Windows.Foundation.Rect, " + AssemblyRef.SystemRuntimeWindowsRuntime);
229 internal static readonly Type s_sizeType = Type.GetType("Windows.Foundation.Size, " + AssemblyRef.SystemRuntimeWindowsRuntime);
231 internal static Object CreateIReference(Object obj)
233 Debug.Assert(obj != null, "Null should not be boxed.");
235 Type type = obj.GetType();
238 return CreateIReferenceArray((Array)obj);
240 if (type == typeof(int))
241 return new CLRIReferenceImpl<int>(PropertyType.Int32, (int)obj);
242 if (type == typeof(String))
243 return new CLRIReferenceImpl<String>(PropertyType.String, (String)obj);
244 if (type == typeof(byte))
245 return new CLRIReferenceImpl<byte>(PropertyType.UInt8, (byte)obj);
246 if (type == typeof(short))
247 return new CLRIReferenceImpl<short>(PropertyType.Int16, (short)obj);
248 if (type == typeof(ushort))
249 return new CLRIReferenceImpl<ushort>(PropertyType.UInt16, (ushort)obj);
250 if (type == typeof(uint))
251 return new CLRIReferenceImpl<uint>(PropertyType.UInt32, (uint)obj);
252 if (type == typeof(long))
253 return new CLRIReferenceImpl<long>(PropertyType.Int64, (long)obj);
254 if (type == typeof(ulong))
255 return new CLRIReferenceImpl<ulong>(PropertyType.UInt64, (ulong)obj);
256 if (type == typeof(float))
257 return new CLRIReferenceImpl<float>(PropertyType.Single, (float)obj);
258 if (type == typeof(double))
259 return new CLRIReferenceImpl<double>(PropertyType.Double, (double)obj);
260 if (type == typeof(char))
261 return new CLRIReferenceImpl<char>(PropertyType.Char16, (char)obj);
262 if (type == typeof(bool))
263 return new CLRIReferenceImpl<bool>(PropertyType.Boolean, (bool)obj);
264 if (type == typeof(Guid))
265 return new CLRIReferenceImpl<Guid>(PropertyType.Guid, (Guid)obj);
266 if (type == typeof(DateTimeOffset))
267 return new CLRIReferenceImpl<DateTimeOffset>(PropertyType.DateTime, (DateTimeOffset)obj);
268 if (type == typeof(TimeSpan))
269 return new CLRIReferenceImpl<TimeSpan>(PropertyType.TimeSpan, (TimeSpan)obj);
270 if (type == typeof(Object))
271 return new CLRIReferenceImpl<Object>(PropertyType.Inspectable, (Object)obj);
272 if (type == typeof(RuntimeType))
273 { // If the type is System.RuntimeType, we want to use System.Type marshaler (it's parent of the type)
274 return new CLRIReferenceImpl<Type>(PropertyType.Other, (Type)obj);
277 // Handle arbitrary WinRT-compatible value types, and recognize a few special types.
278 PropertyType? propType = null;
279 if (type == s_pointType)
281 propType = PropertyType.Point;
283 else if (type == s_rectType)
285 propType = PropertyType.Rect;
287 else if (type == s_sizeType)
289 propType = PropertyType.Size;
291 else if (type.IsValueType || obj is Delegate)
293 propType = PropertyType.Other;
296 if (propType.HasValue)
298 Type specificType = typeof(CLRIReferenceImpl<>).MakeGenericType(type);
299 return Activator.CreateInstance(specificType, new Object[] { propType.Value, obj });
302 Debug.Fail("We should not see non-WinRT type here");
306 internal static Object CreateIReferenceArray(Array obj)
308 Debug.Assert(obj != null);
309 Debug.Assert(obj.GetType().IsArray);
311 Type type = obj.GetType().GetElementType();
313 Debug.Assert(obj.Rank == 1 && obj.GetLowerBound(0) == 0 && !type.IsArray);
315 if (type == typeof(int))
316 return new CLRIReferenceArrayImpl<int>(PropertyType.Int32Array, (int[])obj);
317 if (type == typeof(String))
318 return new CLRIReferenceArrayImpl<String>(PropertyType.StringArray, (String[])obj);
319 if (type == typeof(byte))
320 return new CLRIReferenceArrayImpl<byte>(PropertyType.UInt8Array, (byte[])obj);
321 if (type == typeof(short))
322 return new CLRIReferenceArrayImpl<short>(PropertyType.Int16Array, (short[])obj);
323 if (type == typeof(ushort))
324 return new CLRIReferenceArrayImpl<ushort>(PropertyType.UInt16Array, (ushort[])obj);
325 if (type == typeof(uint))
326 return new CLRIReferenceArrayImpl<uint>(PropertyType.UInt32Array, (uint[])obj);
327 if (type == typeof(long))
328 return new CLRIReferenceArrayImpl<long>(PropertyType.Int64Array, (long[])obj);
329 if (type == typeof(ulong))
330 return new CLRIReferenceArrayImpl<ulong>(PropertyType.UInt64Array, (ulong[])obj);
331 if (type == typeof(float))
332 return new CLRIReferenceArrayImpl<float>(PropertyType.SingleArray, (float[])obj);
333 if (type == typeof(double))
334 return new CLRIReferenceArrayImpl<double>(PropertyType.DoubleArray, (double[])obj);
335 if (type == typeof(char))
336 return new CLRIReferenceArrayImpl<char>(PropertyType.Char16Array, (char[])obj);
337 if (type == typeof(bool))
338 return new CLRIReferenceArrayImpl<bool>(PropertyType.BooleanArray, (bool[])obj);
339 if (type == typeof(Guid))
340 return new CLRIReferenceArrayImpl<Guid>(PropertyType.GuidArray, (Guid[])obj);
341 if (type == typeof(DateTimeOffset))
342 return new CLRIReferenceArrayImpl<DateTimeOffset>(PropertyType.DateTimeArray, (DateTimeOffset[])obj);
343 if (type == typeof(TimeSpan))
344 return new CLRIReferenceArrayImpl<TimeSpan>(PropertyType.TimeSpanArray, (TimeSpan[])obj);
345 if (type == typeof(Type))
346 { // Note: The array type will be System.Type, not System.RuntimeType
347 return new CLRIReferenceArrayImpl<Type>(PropertyType.OtherArray, (Type[])obj);
350 PropertyType? propType = null;
351 if (type == s_pointType)
353 propType = PropertyType.PointArray;
355 else if (type == s_rectType)
357 propType = PropertyType.RectArray;
359 else if (type == s_sizeType)
361 propType = PropertyType.SizeArray;
363 else if (type.IsValueType)
365 // note that KeyValuePair`2 is a reference type on the WinRT side so the array
366 // must be wrapped with CLRIReferenceArrayImpl<Object>
367 if (type.IsGenericType &&
368 type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>))
370 Object[] objArray = new Object[obj.Length];
371 for (int i = 0; i < objArray.Length; i++)
373 objArray[i] = obj.GetValue(i);
379 propType = PropertyType.OtherArray;
382 else if (typeof(Delegate).IsAssignableFrom(type))
384 propType = PropertyType.OtherArray;
388 if (propType.HasValue)
390 // All WinRT value type will be Property.Other
391 Type specificType = typeof(CLRIReferenceArrayImpl<>).MakeGenericType(type);
392 return Activator.CreateInstance(specificType, new Object[] { propType.Value, obj });
396 // All WinRT reference type (including arbitary managed type) will be PropertyType.ObjectArray
397 return new CLRIReferenceArrayImpl<Object>(PropertyType.InspectableArray, (Object[])obj);