diff options
author | Luqun Lou <luqunl@microsoft.com> | 2017-10-24 00:49:07 +0300 |
---|---|---|
committer | Luqun Lou <luqunl@microsoft.com> | 2017-10-24 00:49:07 +0300 |
commit | d9844b8e3ea2f47e527c607acec9bf1fc190dd4c (patch) | |
tree | 9538d74f0e4f5fa48ba941ea8a28746f5c4960c6 /src/System.Private.Interop | |
parent | 5a49c4381d471f6a0b49cc0a5e5f4316a724ed6e (diff) |
Add some WellKnown WinRT Types for MiniWinRT
The change is to add some "wellknown" winrt types and these winrt types( are treated specially by MCG/Interop due to projection. The reason to add them type into System.Private.Interop is that dynamic interop need these "wellknown" winrt type to compare with given type. such as if(type is typeof(IReference)) {//do something special}
Details:
1. System.Private.Interop.CoreCLR.csproj: add $(DefineConstants) to avoid override other Constants
2. System.Private.Interop.Mono.csproj: add all of these well known winrt types
3. DebugAnnotations.cs: this attribute is consumed only by debugger
4. DependencyReductionRootAttribute: add other attribute Usage
5. InteropExtensions.cs/PInvokeMarshal.cs: default implementation for methods referenced in McgMarshal
6. McgIntrinsics.cs: make necessary #ifdef change to compile new added winrt Types
7. System\Runtime\InteropServices\WindowsRuntime: Wellknown WinRT Type
8. Windows\Foundation\: Wellknown WinRT Type
[tfs-changeset: 1678923]
Diffstat (limited to 'src/System.Private.Interop')
25 files changed, 1829 insertions, 12 deletions
diff --git a/src/System.Private.Interop/src/InteropExtensions/DebugAnnotations.cs b/src/System.Private.Interop/src/InteropExtensions/DebugAnnotations.cs new file mode 100644 index 000000000..ad8ad4f7f --- /dev/null +++ b/src/System.Private.Interop/src/InteropExtensions/DebugAnnotations.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics +{ + /// <summary> + /// Annotations used by debugger + /// </summary> + public static class DebugAnnotations + { + /// <summary> + /// Informs debugger that previous line contains code that debugger needs to dive deeper inside. + /// </summary> + public static void PreviousCallContainsDebuggerStepInCode() + { + // This is a marker method and has no code in method body + } + } +}
\ No newline at end of file diff --git a/src/System.Private.Interop/src/InteropExtensions/DependencyReductionRootAttribute.cs b/src/System.Private.Interop/src/InteropExtensions/DependencyReductionRootAttribute.cs index bb697727c..417cdb841 100644 --- a/src/System.Private.Interop/src/InteropExtensions/DependencyReductionRootAttribute.cs +++ b/src/System.Private.Interop/src/InteropExtensions/DependencyReductionRootAttribute.cs @@ -6,7 +6,7 @@ namespace System.Runtime.CompilerServices { // When applied to a type this custom attribute will cause the type to become a new dependency // reduction root. - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)] public class DependencyReductionRootAttribute : Attribute { } diff --git a/src/System.Private.Interop/src/InteropExtensions/InteropExtensions.cs b/src/System.Private.Interop/src/InteropExtensions/InteropExtensions.cs index 5341a4554..93c46d95b 100644 --- a/src/System.Private.Interop/src/InteropExtensions/InteropExtensions.cs +++ b/src/System.Private.Interop/src/InteropExtensions/InteropExtensions.cs @@ -447,6 +447,16 @@ namespace System.Runtime.InteropServices { //Nop } + + public static IntPtr GetCriticalHandle(CriticalHandle criticalHandle) + { + throw new NotSupportedException("GetCriticalHandle"); + } + + public static void SetCriticalHandle(CriticalHandle criticalHandle, IntPtr handle) + { + throw new NotSupportedException("SetCriticalHandle"); + } } public class GCHelpers diff --git a/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs b/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs index 0a88205f3..46da09e11 100644 --- a/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs +++ b/src/System.Private.Interop/src/InteropExtensions/PInvokeMarshal.cs @@ -199,5 +199,10 @@ namespace System.Runtime.InteropServices { return default(String); } + + public static unsafe void CopyToNative(Array source, int startIndex, IntPtr destination, int length) + { + // nop + } } } diff --git a/src/System.Private.Interop/src/Shared/McgIntrinsics.cs b/src/System.Private.Interop/src/Shared/McgIntrinsics.cs index 8334feeb9..4bd120511 100644 --- a/src/System.Private.Interop/src/Shared/McgIntrinsics.cs +++ b/src/System.Private.Interop/src/Shared/McgIntrinsics.cs @@ -487,7 +487,7 @@ namespace System.Runtime.InteropServices return default(T); } -#if ENABLE_WINRT +#if ENABLE_MIN_WINRT // For SharedCCW_IVector/SharedCCW_IVectorView internal static T Call<T>(IntPtr pfn, object list, Toolbox.IList_Oper oper, int index, ref object item) { @@ -505,8 +505,7 @@ namespace System.Runtime.InteropServices return default(T); } -#if !RHTESTCL && !CORECLR - +#if ENABLE_WINRT // For SharedCcw_AsyncOperationCompletedHandler internal static T Call<T>(IntPtr pfn, object handler, object asyncInfo, global::Windows.Foundation.AsyncStatus status) { @@ -518,7 +517,7 @@ namespace System.Runtime.InteropServices { return default(T); } -#endif // ENABLE_WINRT +#endif // ENABLE_MIN_WINRT // For ForwardDelegateCreationStub internal static Delegate Call__Delegate(System.IntPtr pfn, System.IntPtr pStub) { @@ -623,7 +622,7 @@ namespace System.Runtime.InteropServices #endif } -#if !CORECLR && ENABLE_WINRT +#if ENABLE_MIN_WINRT [McgIntrinsics] internal class WinRTAddrOfIntrinsics { @@ -631,7 +630,7 @@ namespace System.Runtime.InteropServices internal delegate int AddrOfGetIndexedProperty(System.IntPtr pComThis, HSTRING unsafe_name, TypeName unsafe_type, IntPtr __IntPtr__unsafe_customProperty); internal delegate int AddrOfTarget19(IntPtr p0, IntPtr p1, int p2); } -#endif // !CORECLR && ENABLE_WINRT +#endif // ENABLE_MIN_WINRT public delegate IntPtr AddrOfGetCCWVtable(); public delegate int AddrOfRelease(IntPtr pComThis); diff --git a/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj b/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj index e8967228e..6c1648e5f 100644 --- a/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj +++ b/src/System.Private.Interop/src/System.Private.Interop.CoreCLR.csproj @@ -7,7 +7,7 @@ <OutputType>Library</OutputType> <ProjectGuid>{A85709C9-22D5-4704-8B7A-73751BB4386A}</ProjectGuid> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <DefineConstants>TARGET_CORE_API_SET;CORECLR</DefineConstants> + <DefineConstants>$(DefineConstants);TARGET_CORE_API_SET;CORECLR</DefineConstants> <!-- Disable warning about CLSCompliant attributes on members not being needed. --> <NoWarn>$(NoWarn);3021</NoWarn> <!-- Use MSFT assembly key for compatibility with uapaot targeting pack --> diff --git a/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj b/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj index b89420b88..25c4f62a6 100644 --- a/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj +++ b/src/System.Private.Interop/src/System.Private.Interop.Mono.csproj @@ -5,7 +5,35 @@ <TargetName>$(AssemblyName)</TargetName> <DefineConstants>$(DefineConstants);ENABLE_MIN_WINRT</DefineConstants> <OutputPath>$(OutputPath)\mono</OutputPath> - </PropertyGroup> - + </PropertyGroup> + + <ItemGroup> + <Compile Include="InteropExtensions\DebugAnnotations.cs" /> + </ItemGroup> + + <ItemGroup> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\__IUnboxInternal.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\CLRIKeyValuePairImpl.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\IPropertyValue.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\IReadOnlyListAdapter.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\IReferenceArray.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\PropertyValueImpl.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\ReferenceArrayImpl.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\ReferenceArrayImplBase.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\ReferenceImpl.cs" /> + <Compile Include="System\Runtime\InteropServices\WindowsRuntime\WindowsRuntimeImportAttribute.cs" /> + + </ItemGroup> + + <ItemGroup> + <Compile Include="Windows\Foundation\IKeyValuePair.cs" /> + <Compile Include="Windows\Foundation\IReference.cs" /> + <Compile Include="Windows\Foundation\Point.cs" /> + <Compile Include="Windows\Foundation\PropertyType.cs" /> + <Compile Include="Windows\Foundation\Rect.cs" /> + <Compile Include="Windows\Foundation\Size.cs" /> + <Compile Include="Windows\Foundation\TokenizerHelper.cs" /> + </ItemGroup> + <Import Project="System.Private.Interop.CoreCLR.csproj" /> </Project> diff --git a/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems b/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems index 5b104807a..cb6e6c613 100644 --- a/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems +++ b/src/System.Private.Interop/src/System.Private.Interop.Shared.projitems @@ -32,6 +32,7 @@ <Compile Include="Shared\McgGeneratedMarshallingCodeAttribute.cs" /> <Compile Include="Shared\McgHelpers.cs" /> <Compile Include="Shared\McgIntrinsics.cs" /> + <Compile Include="Shared\McgInternalTypeAttribute.cs" /> <Compile Include="Shared\McgMarshal.cs" /> <Compile Include="Shared\McgMethodNameAttribute.cs" /> <Compile Include="Shared\McgModule.cs" /> @@ -73,4 +74,4 @@ <Compile Include="Interop\Interop.Common.Unix.cs" /> <Compile Include="Interop\Interop.String.Unix.cs" /> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/src/System.Private.Interop/src/System.Private.Interop.csproj b/src/System.Private.Interop/src/System.Private.Interop.csproj index 525f210c3..aeadd885e 100644 --- a/src/System.Private.Interop/src/System.Private.Interop.csproj +++ b/src/System.Private.Interop/src/System.Private.Interop.csproj @@ -41,7 +41,6 @@ </Compile> <Compile Include="Shared\ComException.cs" /> <Compile Include="Shared\Marshal.cs" /> - <Compile Include="Shared\McgInternalTypeAttribute.cs" /> <Compile Condition="'$(EnableWinRT)'=='true'" Include="Shared\WindowsRuntimeMarshal.cs" /> <Compile Include="System\Runtime\InteropServices\AllowReversePInvokeCallsAttribute.cs" /> <Compile Include="System\Runtime\InteropServices\ArrayWithOffset.cs" /> diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CLRIKeyValuePairImpl.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CLRIKeyValuePairImpl.cs new file mode 100644 index 000000000..cd2f1b17e --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/CLRIKeyValuePairImpl.cs @@ -0,0 +1,124 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Windows.Foundation.Collections; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + [McgInternalTypeAttribute] + public sealed class CLRIKeyValuePairImpl<K, V> : + global::System.Runtime.InteropServices.BoxedKeyValuePair, + IKeyValuePair<K, V>, // Use IKeyValuePair<K, V> from S.P.Interop instead of Windows.winmd to loose the dependency between S.P.Interop and Windows.winmd + __IUnboxInternal + { + private global::System.Collections.Generic.KeyValuePair<K, V> _pair; + + public CLRIKeyValuePairImpl(ref global::System.Collections.Generic.KeyValuePair<K, V> pair) + { + _pair = pair; + } + + public K get_Key() + { + return _pair.Key; + } + + [global::System.Runtime.InteropServices.McgAccessor(global::System.Runtime.InteropServices.McgAccessorKind.PropertyGet, "Value")] + public V get_Value() + { + return _pair.Value; + } + + public override object GetTarget() + { + return (object)_pair; + } + + /// <summary> + /// Called by public object McgModule.Box(object obj, int boxingIndex) after allocating instance + /// </summary> + /// <param name="pair">KeyValuePair<K, V></param> + /// <returns>IKeyValuePair<K,V> instance</returns> + public override object Initialize(object pair) + { + _pair = (global::System.Collections.Generic.KeyValuePair<K, V>)pair; + + return this; + } + + /// <summary> + /// Get unboxed value + /// This method is used by dynamic interop. + /// The reason for adding this instance method instead of using static Unbox is to avoid reflection + /// </summary> + /// <param name="obj">native winrt object or our own boxed KeyValuePair<K,V></K></param> + /// <returns>unboxed value as object</returns> + public object get_Value(object obj) + { + return Unbox(obj); + } + + /// <summary> + /// This method is called from ComInterop.cs in the Unboxing code. + /// </summary> + /// <param name="wrapper">native winrt object or our own boxed KeyValuePair<K,V></param> + /// <returns>unboxed value as object</returns> + public static object Unbox(object wrapper) + { + CLRIKeyValuePairImpl<K, V> reference = wrapper as CLRIKeyValuePairImpl<K, V>; + + if (reference != null) + { + return reference._pair; + } + else + { + // We could just have the native IKeyValuePair in which case we simply return wrapper as IKeyValuePair. + global::Windows.Foundation.Collections.IKeyValuePair<K, V> iPair = wrapper as global::Windows.Foundation.Collections.IKeyValuePair<K, V>; + return new System.Collections.Generic.KeyValuePair<K, V>(iPair.get_Key(), iPair.get_Value()); + } + } + + public override string ToString() + { + return _pair.ToString(); + } + } + + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + [McgInternalTypeAttribute] + public sealed class CLRIKeyValuePairArrayImpl<K, V> : global::System.Runtime.InteropServices.BoxedKeyValuePair + { + private object _pairs; + + /// <summary> + /// Called by public object McgModule.Box(object obj, int boxingIndex) after allocating instance + /// </summary> + /// <param name="pairs">KeyValuePair<K,V>[]</param> + /// <returns>IReferenceArrayImpl<K,V> instance</K></returns> + public override object Initialize(object pairs) + { + _pairs = pairs; + + global::System.Collections.Generic.KeyValuePair<K, V>[] unboxedPairArray = pairs as global::System.Collections.Generic.KeyValuePair<K, V>[]; + + object[] boxedKeyValuePairs = new object[unboxedPairArray.Length]; + + for (int i = 0; i < unboxedPairArray.Length; i++) + { + boxedKeyValuePairs[i] = new CLRIKeyValuePairImpl<K, V>(ref unboxedPairArray[i]); + } + + // Lets create the IReferenceArrayImpl of the type. + return new ReferenceArrayImpl<object>(boxedKeyValuePairs, global::Windows.Foundation.PropertyType.InspectableArray); + } + + public override object GetTarget() + { + return (object)_pairs; + } + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IPropertyValue.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IPropertyValue.cs new file mode 100644 index 000000000..fe48ecf89 --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IPropertyValue.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Windows.Foundation; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("4bd682dd-7554-40e9-9a9b-82654ede7e62")] + [WindowsRuntimeImport] + public interface IPropertyValue + { + PropertyType Type + { + get; + } + + bool IsNumericScalar + { + get; + } + + Byte GetUInt8(); + Int16 GetInt16(); + UInt16 GetUInt16(); + Int32 GetInt32(); + UInt32 GetUInt32(); + Int64 GetInt64(); + UInt64 GetUInt64(); + Single GetSingle(); + Double GetDouble(); + char GetChar16(); + Boolean GetBoolean(); + String GetString(); + Guid GetGuid(); + DateTimeOffset GetDateTime(); + TimeSpan GetTimeSpan(); + Point GetPoint(); + Size GetSize(); + Rect GetRect(); + void GetUInt8Array(out byte[] array); + void GetInt16Array(out Int16[] array); + void GetUInt16Array(out UInt16[] array); + void GetInt32Array(out Int32[] array); + void GetUInt32Array(out UInt32[] array); + void GetInt64Array(out Int64[] array); + void GetUInt64Array(out UInt64[] array); + void GetSingleArray(out Single[] array); + void GetDoubleArray(out Double[] array); + void GetChar16Array(out char[] array); + void GetBooleanArray(out Boolean[] array); + void GetStringArray(out String[] array); + void GetInspectableArray(out object[] array); + void GetGuidArray(out Guid[] array); + void GetDateTimeArray(out DateTimeOffset[] array); + void GetTimeSpanArray(out TimeSpan[] array); + void GetPointArray(out Point[] array); + void GetSizeArray(out Size[] array); + void GetRectArray(out Rect[] array); + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListAdapter.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListAdapter.cs new file mode 100644 index 000000000..bd082361a --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListAdapter.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + /// <summary> + /// IReadOnlyCollection is generic, so we can't invoke Count without knowing T. Instead, we + // introduce a new non-generic interface for our adapters, so we can have a non-generic helper + // for the call. + /// </summary> + public interface IReadOnlyCollectionAdapter + { + int Count { get; } + } + + public interface IReadOnlyListAdapter<out T> : IReadOnlyCollectionAdapter + { + T this[int index] { get; } + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IReferenceArray.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IReferenceArray.cs new file mode 100644 index 000000000..d10421bd6 --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/IReferenceArray.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [ComImport] + [Guid("61c17707-2d65-11e0-9ae8-d48564015472")] + [WindowsRuntimeImport] + // T can be any WinRT-compatible type, including reference types. + public interface IReferenceArray<T> : IPropertyValue + { + T[] get_Value(); + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/PropertyValueImpl.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/PropertyValueImpl.cs new file mode 100644 index 000000000..e4302be2f --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/PropertyValueImpl.cs @@ -0,0 +1,480 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.WindowsRuntime; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + [McgInternalTypeAttribute] + public class PropertyValueImpl : BoxedValue, IPropertyValue + { + internal PropertyValueImpl(object val, int type) : base(val, type) + { + } + + public global::Windows.Foundation.PropertyType Type + { + get + { + return (global::Windows.Foundation.PropertyType)m_type; + } + } + + public bool IsNumericScalar + { + get + { + return IsNumericScalarImpl((global::Windows.Foundation.PropertyType)m_type, m_data); + } + } + + public byte GetUInt8() + { + return CoerceScalarValue<byte>(global::Windows.Foundation.PropertyType.UInt8); + } + + public short GetInt16() + { + return CoerceScalarValue<short>(global::Windows.Foundation.PropertyType.Int16); + } + + public ushort GetUInt16() + { + return CoerceScalarValue<ushort>(global::Windows.Foundation.PropertyType.UInt16); + } + + public int GetInt32() + { + return CoerceScalarValue<int>(global::Windows.Foundation.PropertyType.Int32); + } + + public uint GetUInt32() + { + return CoerceScalarValue<uint>(global::Windows.Foundation.PropertyType.UInt32); + } + + public long GetInt64() + { + return CoerceScalarValue<long>(global::Windows.Foundation.PropertyType.Int64); + } + + public ulong GetUInt64() + { + return CoerceScalarValue<ulong>(global::Windows.Foundation.PropertyType.UInt64); + } + + public float GetSingle() + { + return CoerceScalarValue<float>(global::Windows.Foundation.PropertyType.Single); + } + + public double GetDouble() + { + return CoerceScalarValue<double>(global::Windows.Foundation.PropertyType.Double); + } + + public char GetChar16() + { + CheckType(global::Windows.Foundation.PropertyType.Char16); + return (char)m_data; + } + + public bool GetBoolean() + { + CheckType(global::Windows.Foundation.PropertyType.Boolean); + return (bool)m_data; + } + + public string GetString() + { + return CoerceScalarValue<string>(global::Windows.Foundation.PropertyType.String); + } + + public object GetInspectable() + { + CheckType(global::Windows.Foundation.PropertyType.Inspectable); + return m_data; + } + + public System.Guid GetGuid() + { + return CoerceScalarValue<System.Guid>(global::Windows.Foundation.PropertyType.Guid); + } + + public System.DateTimeOffset GetDateTime() + { + CheckType(global::Windows.Foundation.PropertyType.DateTime); + return (System.DateTimeOffset)m_data; + } + + public System.TimeSpan GetTimeSpan() + { + CheckType(global::Windows.Foundation.PropertyType.TimeSpan); + return (System.TimeSpan)m_data; + } + + public global::Windows.Foundation.Point GetPoint() + { + CheckType(global::Windows.Foundation.PropertyType.Point); + return (global::Windows.Foundation.Point)m_data; + } + + public global::Windows.Foundation.Size GetSize() + { + CheckType(global::Windows.Foundation.PropertyType.Size); + return (global::Windows.Foundation.Size)m_data; + } + + public global::Windows.Foundation.Rect GetRect() + { + CheckType(global::Windows.Foundation.PropertyType.Rect); + return (global::Windows.Foundation.Rect)m_data; + } + + public void GetUInt8Array(out byte[] array) + { + array = CoerceArrayValue<byte>(global::Windows.Foundation.PropertyType.UInt8Array); + } + + public void GetInt16Array(out short[] array) + { + array = CoerceArrayValue<short>(global::Windows.Foundation.PropertyType.Int16Array); + } + + public void GetUInt16Array(out ushort[] array) + { + array = CoerceArrayValue<ushort>(global::Windows.Foundation.PropertyType.UInt16Array); + } + + public void GetInt32Array(out int[] array) + { + array = CoerceArrayValue<int>(global::Windows.Foundation.PropertyType.Int32Array); + } + + public void GetUInt32Array(out uint[] array) + { + array = CoerceArrayValue<uint>(global::Windows.Foundation.PropertyType.UInt32Array); + } + + public void GetInt64Array(out long[] array) + { + array = CoerceArrayValue<long>(global::Windows.Foundation.PropertyType.Int64Array); + } + + public void GetUInt64Array(out ulong[] array) + { + array = CoerceArrayValue<ulong>(global::Windows.Foundation.PropertyType.UInt64Array); + } + + public void GetSingleArray(out float[] array) + { + array = CoerceArrayValue<float>(global::Windows.Foundation.PropertyType.SingleArray); + } + + public void GetDoubleArray(out double[] array) + { + array = CoerceArrayValue<double>(global::Windows.Foundation.PropertyType.DoubleArray); + } + + public void GetChar16Array(out char[] array) + { + CheckType(global::Windows.Foundation.PropertyType.Char16Array); + array = (char[])m_data; + } + + public void GetBooleanArray(out bool[] array) + { + CheckType(global::Windows.Foundation.PropertyType.BooleanArray); + array = (bool[])m_data; + } + + public void GetStringArray(out string[] array) + { + array = CoerceArrayValue<string>(global::Windows.Foundation.PropertyType.StringArray); + } + + public void GetInspectableArray(out object[] array) + { + CheckType(global::Windows.Foundation.PropertyType.InspectableArray); + array = (object[])m_data; + } + + public void GetGuidArray(out System.Guid[] array) + { + array = CoerceArrayValue<System.Guid>(global::Windows.Foundation.PropertyType.GuidArray); + } + + public void GetDateTimeArray(out System.DateTimeOffset[] array) + { + CheckType(global::Windows.Foundation.PropertyType.DateTimeArray); + array = (System.DateTimeOffset[])m_data; + } + + public void GetTimeSpanArray(out System.TimeSpan[] array) + { + CheckType(global::Windows.Foundation.PropertyType.TimeSpanArray); + array = (System.TimeSpan[])m_data; + } + + public void GetPointArray(out global::Windows.Foundation.Point[] array) + { + CheckType(global::Windows.Foundation.PropertyType.PointArray); + array = (global::Windows.Foundation.Point[])m_data; + } + + public void GetSizeArray(out global::Windows.Foundation.Size[] array) + { + CheckType(global::Windows.Foundation.PropertyType.SizeArray); + array = (global::Windows.Foundation.Size[])m_data; + } + + public void GetRectArray(out global::Windows.Foundation.Rect[] array) + { + CheckType(global::Windows.Foundation.PropertyType.RectArray); + array = (global::Windows.Foundation.Rect[])m_data; + } + + private T[] CoerceArrayValue<T>(global::Windows.Foundation.PropertyType unboxType) + { + // If we contain the type being looked for directly, then take the fast-path + if (m_type == (int)unboxType) + { + return (T[])m_data; + } + + // Make sure we have an array to begin with + System.Array dataArray = m_data as System.Array; + + if (dataArray == null) + { + throw CreateExceptionForInvalidCast((global::Windows.Foundation.PropertyType)m_type, unboxType); + } + + // Array types are 1024 larger than their equivilent scalar counterpart + if ((m_type <= 1024) || ((int)unboxType <= 1024)) + { + throw CreateExceptionForInvalidCast((global::Windows.Foundation.PropertyType)m_type, unboxType); + } + + global::Windows.Foundation.PropertyType scalarType = (global::Windows.Foundation.PropertyType)(m_type - 1024); + global::Windows.Foundation.PropertyType unboxTypeT = unboxType - 1024; + + // If we do not have the correct array type, then we need to convert the array element-by-element + // to a new array of the requested type + T[] coercedArray = new T[dataArray.Length]; + + for (int i = 0; i < dataArray.Length; ++i) + { + coercedArray[i] = (T)CoerceScalarValue(scalarType, dataArray.GetValue(i), unboxTypeT); + } + + return coercedArray; + } + + [System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private T CoerceScalarValue<T>(global::Windows.Foundation.PropertyType unboxType) + { + object result = m_data; + + // If we are just a boxed version of the requested type, then take the fast path out + if (m_type != (int)unboxType) + { + result = CoerceScalarValue((global::Windows.Foundation.PropertyType)m_type, result, unboxType); + } + + return (T)result; + } + + static private object CoerceScalarValue(global::Windows.Foundation.PropertyType type, object value, global::Windows.Foundation.PropertyType unboxType) + { + // If the property type is neither one of the coercable numeric types nor IInspectable, we + // should not attempt coersion, even if the underlying value is technically convertable + if ((type == global::Windows.Foundation.PropertyType.Guid) && (unboxType == global::Windows.Foundation.PropertyType.String)) + { + // String <--> Guid is allowed + return ((System.Guid)value).ToString(); + } + else if ((type == global::Windows.Foundation.PropertyType.String) && (unboxType == global::Windows.Foundation.PropertyType.Guid)) + { + System.Guid result; + + if (System.Guid.TryParse((string)value, out result)) + { + return result; + } + } + else if (type == global::Windows.Foundation.PropertyType.Inspectable) + { + // If the property type is IInspectable, and we have a nested IPropertyValue, then we need + // to pass along the request to coerce the value. + IPropertyValue ipv = value as IPropertyValue; + + if (ipv != null) + { + object result = ReferenceUtility.GetWellKnownScalar(ipv, unboxType); + + if (result != null) + { + return result; + } + + Debug.Assert( + false, + "T in coersion function wasn't understood as a type that can be coerced - make sure that CoerceScalarValue and NumericScalarTypes are in sync" + ); + } + } + else if (type == global::Windows.Foundation.PropertyType.Boolean || type == global::Windows.Foundation.PropertyType.Char16) + { + throw CreateExceptionForInvalidCoersion(type, value, unboxType, Interop.COM.TYPE_E_TYPEMISMATCH); + } + + // + // Let Convert handle all possible conversions - this include + // 1. string - which desktop code accidentally allowed + // 2. object (IInspectable) + // + try + { + switch (unboxType) + { + case global::Windows.Foundation.PropertyType.UInt8: + return System.Convert.ToByte(value); + + case global::Windows.Foundation.PropertyType.Int16: + return System.Convert.ToInt16(value); + + case global::Windows.Foundation.PropertyType.UInt16: + return System.Convert.ToUInt16(value); + + case global::Windows.Foundation.PropertyType.Int32: + return System.Convert.ToInt32(value); + + case global::Windows.Foundation.PropertyType.UInt32: + return System.Convert.ToUInt32(value); + + case global::Windows.Foundation.PropertyType.Int64: + return System.Convert.ToInt64(value); + + case global::Windows.Foundation.PropertyType.UInt64: + return System.Convert.ToUInt64(value); + + case global::Windows.Foundation.PropertyType.Single: + return System.Convert.ToSingle(value); + + case global::Windows.Foundation.PropertyType.Double: + return System.Convert.ToDouble(value); + + default: + break; + } + } + catch (System.FormatException) + { + throw CreateExceptionForInvalidCoersion(type, value, unboxType, Interop.COM.TYPE_E_TYPEMISMATCH); + } + catch (System.InvalidCastException) + { + throw CreateExceptionForInvalidCoersion(type, value, unboxType, Interop.COM.TYPE_E_TYPEMISMATCH); + } + catch (System.OverflowException) + { + throw CreateExceptionForInvalidCoersion(type, value, unboxType, Interop.COM.DISP_E_OVERFLOW); + } + + throw CreateExceptionForInvalidCast(type, unboxType); + } + + private static bool IsNumericScalarImpl(global::Windows.Foundation.PropertyType type, object data) + { + switch (type) + { + case global::Windows.Foundation.PropertyType.UInt8: + case global::Windows.Foundation.PropertyType.Int16: + case global::Windows.Foundation.PropertyType.UInt16: + case global::Windows.Foundation.PropertyType.Int32: + case global::Windows.Foundation.PropertyType.UInt32: + case global::Windows.Foundation.PropertyType.Int64: + case global::Windows.Foundation.PropertyType.UInt64: + case global::Windows.Foundation.PropertyType.Single: + case global::Windows.Foundation.PropertyType.Double: + return true; + + default: + return McgMarshal.IsEnum(data); + } + } + + private void CheckType(global::Windows.Foundation.PropertyType unboxType) + { + if (this.Type != unboxType) + { + throw CreateExceptionForInvalidCast(this.Type, unboxType); + } + } + + private static System.InvalidCastException CreateExceptionForInvalidCast( + global::Windows.Foundation.PropertyType type, + global::Windows.Foundation.PropertyType unboxType) + { + System.InvalidCastException ex = new System.InvalidCastException(SR.Format(SR.PropertyValue_InvalidCast, type, unboxType)); + McgMarshal.SetExceptionErrorCode(ex, Interop.COM.TYPE_E_TYPEMISMATCH); + return ex; + } + + private static System.InvalidCastException CreateExceptionForInvalidCoersion( + global::Windows.Foundation.PropertyType type, + object value, + global::Windows.Foundation.PropertyType unboxType, + int hr) + { + InvalidCastException ex = new InvalidCastException(SR.Format(SR.PropertyValue_InvalidCoersion, type, value, unboxType)); + McgMarshal.SetExceptionErrorCode(ex, hr); + return ex; + } + } + + internal class ReferenceUtility + { + internal static object GetWellKnownScalar(IPropertyValue ipv, global::Windows.Foundation.PropertyType type) + { + switch (type) + { + case global::Windows.Foundation.PropertyType.UInt8: + return ipv.GetUInt8(); + + case global::Windows.Foundation.PropertyType.Int16: + return ipv.GetInt16(); + + case global::Windows.Foundation.PropertyType.UInt16: + return ipv.GetUInt16(); + + case global::Windows.Foundation.PropertyType.Int32: + return ipv.GetInt32(); + + case global::Windows.Foundation.PropertyType.UInt32: + return ipv.GetUInt32(); + + case global::Windows.Foundation.PropertyType.Int64: + return ipv.GetInt64(); + + case global::Windows.Foundation.PropertyType.UInt64: + return ipv.GetUInt64(); + + case global::Windows.Foundation.PropertyType.Single: + return ipv.GetSingle(); + + case global::Windows.Foundation.PropertyType.Double: + return ipv.GetDouble(); + } + + Debug.Assert(false); + return null; + } + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceArrayImpl.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceArrayImpl.cs new file mode 100644 index 000000000..4542d1372 --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceArrayImpl.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + /// <summary> + /// A managed wrapper of IReferenceArray<T> + /// </summary> + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + [McgInternalTypeAttribute] + public sealed class ReferenceArrayImpl<T> : ReferenceArrayImplBase, IReferenceArray<T> + { + private T[] _value; + + public ReferenceArrayImpl(T[] obj, global::Windows.Foundation.PropertyType type) : base(obj, type) + { + _value = obj; + m_unboxed = true; + } + + public T[] get_Value() + { + if (!m_unboxed) + { + _value = (T[])m_data; + m_unboxed = true; + } + + return _value; + } + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceArrayImplBase.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceArrayImplBase.cs new file mode 100644 index 000000000..8f0863a56 --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceArrayImplBase.cs @@ -0,0 +1,178 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + [McgInternalTypeAttribute] + public class ReferenceArrayImplBase : + PropertyValueImpl, + System.Collections.IList, + System.Collections.Generic.IEnumerable<object> +#if SUPPORTS_ICustomQueryInterface + ,System.Runtime.InteropServices.ICustomQueryInterface +#endif + { + // pinterface({faa585ea-6214-4217-afda-7f46de5869b3};cinterface(IInspectable)) + internal static System.Guid IID_IIterableOfObject = + new System.Guid(153846939, 24753, 21182, 0xA4, 0x4A, 0x6F, 0xE8, 0xE9, 0x33, 0xCB, 0xE4); + + private System.Collections.IList _list; + private System.Collections.Generic.IEnumerable<object> _enumerableOfObject; + + public override void Initialize(object val, int type) + { + m_data = val; + m_type = (short)type; + + // This should not fail but I'm making a cast here anyway just in case + // we have a bug or there is a runtime failure + _list = (System.Collections.IList)val; + + // Not every array implements IEnumerable<Object> + _enumerableOfObject = val as System.Collections.Generic.IEnumerable<object>; + } + + internal ReferenceArrayImplBase(object data, global::Windows.Foundation.PropertyType type) : base(data, (int)type) + { + Initialize(data, (int)type); + } + +#if SUPPORTS_ICustomQueryInterface + // + // Customize QI behavior: + // If this array type doesn't implement IEnumerable<Object>, reject IIterable<Object> + // + System.Runtime.InteropServices.CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref System.Guid iid, out System.IntPtr ppv) + { + ppv = default(System.IntPtr); + + if (System.Runtime.InteropServices.McgMarshal.GuidEquals(ref iid, ref IID_IIterableOfObject)) + { + if (_enumerableOfObject == null) + { + // This array type doesn't actually support IEnumerable<Object> + // Reject the QI + return System.Runtime.InteropServices.CustomQueryInterfaceResult.Failed; + } + } + + return System.Runtime.InteropServices.CustomQueryInterfaceResult.NotHandled; + } +#endif + // + // IEnumerable methods. Used by data-binding in Jupiter when you try to data bind + // against a managed array + // + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return ((System.Collections.IEnumerable)_list).GetEnumerator(); + } + + // + // IEnumerable<object> methods. We need this because System.Array implement this (implicitly) if it is castable to object[] + // + System.Collections.Generic.IEnumerator<object> System.Collections.Generic.IEnumerable<object>.GetEnumerator() + { + return _enumerableOfObject.GetEnumerator(); + } + + // + // IList & ICollection methods. + // This enables two-way data binding and index access in Jupiter + // + object System.Collections.IList.this[int index] + { + get + { + return _list[index]; + } + + set + { + _list[index] = value; + } + } + + int System.Collections.IList.Add(object value) + { + return _list.Add(value); + } + + bool System.Collections.IList.Contains(object value) + { + return _list.Contains(value); + } + + void System.Collections.IList.Clear() + { + _list.Clear(); + } + + bool System.Collections.IList.IsReadOnly + { + get + { + return _list.IsReadOnly; + } + } + + bool System.Collections.IList.IsFixedSize + { + get + { + return _list.IsFixedSize; + } + } + + int System.Collections.IList.IndexOf(object value) + { + return _list.IndexOf(value); + } + + void System.Collections.IList.Insert(int index, object value) + { + _list.Insert(index, value); + } + + void System.Collections.IList.Remove(object value) + { + _list.Remove(value); + } + + void System.Collections.IList.RemoveAt(int index) + { + _list.RemoveAt(index); + } + + void System.Collections.ICollection.CopyTo(System.Array array, int index) + { + _list.CopyTo(array, index); + } + + int System.Collections.ICollection.Count + { + get + { + return _list.Count; + } + } + + object System.Collections.ICollection.SyncRoot + { + get + { + return _list.SyncRoot; + } + } + + bool System.Collections.ICollection.IsSynchronized + { + get + { + return _list.IsSynchronized; + } + } + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceImpl.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceImpl.cs new file mode 100644 index 000000000..a1dce0b06 --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/ReferenceImpl.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + /// <summary> + /// A managed wrapper for IPropertyValue and IReference<T> + /// </summary> + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + [McgInternalTypeAttribute] + public class ReferenceImpl<T> : PropertyValueImpl, global::Windows.Foundation.IReference<T> + { + private T m_value; + + public ReferenceImpl(T data, int type) + : base(data, type) + { + m_unboxed = true; + m_value = data; + } + + internal ReferenceImpl(T data, global::Windows.Foundation.PropertyType type) + : base(data, (int)type) + { + m_unboxed = true; + m_value = data; + } + + public T get_Value() + { + if (!m_unboxed) + { + m_value = (T)m_data; + m_unboxed = true; + } + return m_value; + } + } +} diff --git a/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/__IUnboxInternal.cs b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/__IUnboxInternal.cs new file mode 100644 index 000000000..1cad7be84 --- /dev/null +++ b/src/System.Private.Interop/src/System/Runtime/InteropServices/WindowsRuntime/__IUnboxInternal.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +namespace System.Runtime.InteropServices.WindowsRuntime +{ + /// <summary> + /// Interface to help get unboxed value from IReference<T>/IReferenceArray<T>/IKeyValuePair<K,V> + /// </summary> + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + internal interface __IUnboxInternal + { + Object get_Value(Object obj); + } +} diff --git a/src/System.Private.Interop/src/Windows/Foundation/IKeyValuePair.cs b/src/System.Private.Interop/src/Windows/Foundation/IKeyValuePair.cs new file mode 100644 index 000000000..88ba75437 --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/IKeyValuePair.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.WindowsRuntime; + +namespace Windows.Foundation.Collections +{ + [ComImport] + [Guid("02b51929-c1c4-4a7e-8940-0312b5c18500")] + [WindowsRuntimeImport] + public unsafe interface IKeyValuePair<K, V> + { + K get_Key(); + V get_Value(); + } +} diff --git a/src/System.Private.Interop/src/Windows/Foundation/IReference.cs b/src/System.Private.Interop/src/Windows/Foundation/IReference.cs new file mode 100644 index 000000000..dc498b8f8 --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/IReference.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Windows.Foundation +{ + [System.Runtime.CompilerServices.DependencyReductionRootAttribute] + public interface IReference<T> + { + [System.Runtime.InteropServices.McgAccessor(System.Runtime.InteropServices.McgAccessorKind.PropertyGet, "Value")] + T get_Value(); + } +} diff --git a/src/System.Private.Interop/src/Windows/Foundation/Point.cs b/src/System.Private.Interop/src/Windows/Foundation/Point.cs new file mode 100644 index 000000000..aa96bbd36 --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/Point.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning disable 436 // Redefining types from Windows.Foundation +#endif // !FEATURE_SLJ_PROJECTION_COMPAT + +#if FEATURE_SLJ_PROJECTION_COMPAT +namespace System.Windows +#else // !FEATURE_SLJ_PROJECTION_COMPAT + + +namespace Windows.Foundation +#endif // FEATURE_SLJ_PROJECTION_COMPAT +{ + // + // Point is the managed projection of Windows.Foundation.Point. Any changes to the layout + // of this type must be exactly mirrored on the native WinRT side as well. + // + // Note that this type is owned by the Jupiter team. Please contact them before making any + // changes here. + // + [StructLayout(LayoutKind.Sequential)] + public struct Point : IFormattable + { + internal float _x; + internal float _y; + + public Point(double x, double y) + { + _x = (float)x; + _y = (float)y; + } + + public double X + { + get { return _x; } + set { _x = (float)value; } + } + + public double Y + { + get { return _y; } + set { _y = (float)value; } + } + + public override string ToString() + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, null /* format provider */); + } + + public string ToString(IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, provider); + } + + string IFormattable.ToString(string format, IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(format, provider); + } + + private string ConvertToString(string format, IFormatProvider provider) + { + // Helper to get the numeric list separator for a given culture. + char separator = TokenizerHelper.GetNumericListSeparator(provider); + return String.Format(provider, + "{1:" + format + "}{0}{2:" + format + "}", + separator, + _x, + _y); + } + + public static bool operator ==(Point point1, Point point2) + { + return point1.X == point2.X && + point1.Y == point2.Y; + } + + public static bool operator !=(Point point1, Point point2) + { + return !(point1 == point2); + } + + public override bool Equals(object o) + { + if ((null == o) || !(o is Point)) + { + return false; + } + + Point value = (Point)o; + return (this == value); + } + + public bool Equals(Point value) + { + return (this == value); + } + + public override int GetHashCode() + { + // Perform field-by-field XOR of HashCodes + return X.GetHashCode() ^ + Y.GetHashCode(); + } + } +} + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning restore 436 +#endif // !FEATURE_SLJ_PROJECTION_COMPAT + diff --git a/src/System.Private.Interop/src/Windows/Foundation/PropertyType.cs b/src/System.Private.Interop/src/Windows/Foundation/PropertyType.cs new file mode 100644 index 000000000..141511fbc --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/PropertyType.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Windows.Foundation +{ + public enum PropertyType + { + Empty = 0, + UInt8 = 1, + Int16 = 2, + UInt16 = 3, + Int32 = 4, + UInt32 = 5, + Int64 = 6, + UInt64 = 7, + Single = 8, + Double = 9, + Char16 = 10, + Boolean = 11, + String = 12, + Inspectable = 13, + DateTime = 14, + TimeSpan = 15, + Guid = 16, + Point = 17, + Size = 18, + Rect = 19, + Other = 20, + UInt8Array = 1025, + Int16Array = 1026, + UInt16Array = 1027, + Int32Array = 1028, + UInt32Array = 1029, + Int64Array = 1030, + UInt64Array = 1031, + SingleArray = 1032, + DoubleArray = 1033, + Char16Array = 1034, + BooleanArray = 1035, + StringArray = 1036, + InspectableArray = 1037, + DateTimeArray = 1038, + TimeSpanArray = 1039, + GuidArray = 1040, + PointArray = 1041, + SizeArray = 1042, + RectArray = 1043, + OtherArray = 1044 + } +} diff --git a/src/System.Private.Interop/src/Windows/Foundation/Rect.cs b/src/System.Private.Interop/src/Windows/Foundation/Rect.cs new file mode 100644 index 000000000..91e1ca46f --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/Rect.cs @@ -0,0 +1,367 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning disable 436 // Redefining types from Windows.Foundation +#endif // !FEATURE_SLJ_PROJECTION_COMPAT + +#if FEATURE_SLJ_PROJECTION_COMPAT +namespace System.Windows +#else // !FEATURE_SLJ_PROJECTION_COMPAT + + +namespace Windows.Foundation +#endif // FEATURE_SLJ_PROJECTION_COMPAT +{ + // + // Rect is the managed projection of Windows.Foundation.Rect. Any changes to the layout + // of this type must be exactly mirrored on the native WinRT side as well. + // + // Note that this type is owned by the Jupiter team. Please contact them before making any + // changes here. + // + [StructLayout(LayoutKind.Sequential)] + public struct Rect : IFormattable + { + private float _x; + private float _y; + private float _width; + private float _height; + + private const double EmptyX = Double.PositiveInfinity; + private const double EmptyY = Double.PositiveInfinity; + private const double EmptyWidth = Double.NegativeInfinity; + private const double EmptyHeight = Double.NegativeInfinity; + + private readonly static Rect s_empty = CreateEmptyRect(); + + public Rect(double x, + double y, + double width, + double height) + { + if (width < 0) + throw new ArgumentException("width"); + if (height < 0) + throw new ArgumentException("height"); + + _x = (float)x; + _y = (float)y; + _width = (float)width; + _height = (float)height; + } + + public Rect(Point point1, + Point point2) + { + _x = (float)Math.Min(point1.X, point2.X); + _y = (float)Math.Min(point1.Y, point2.Y); + + _width = (float)Math.Max(Math.Max(point1.X, point2.X) - _x, 0); + _height = (float)Math.Max(Math.Max(point1.Y, point2.Y) - _y, 0); + } + + public Rect(Point location, Size size) + { + if (size.IsEmpty) + { + this = s_empty; + } + else + { + _x = (float)location.X; + _y = (float)location.Y; + _width = (float)size.Width; + _height = (float)size.Height; + } + } + + internal static Rect Create(double x, + double y, + double width, + double height) + { + if (x == EmptyX && y == EmptyY && width == EmptyWidth && height == EmptyHeight) + { + return Rect.Empty; + } + else + { + return new Rect(x, y, width, height); + } + } + + + public double X + { + get { return _x; } + set { _x = (float)value; } + } + + public double Y + { + get { return _y; } + set { _y = (float)value; } + } + + public double Width + { + get { return _width; } + set + { + if (value < 0) + throw new ArgumentException("Width"); + + _width = (float)value; + } + } + + public double Height + { + get { return _height; } + set + { + if (value < 0) + throw new ArgumentException("Height"); + + _height = (float)value; + } + } + + public double Left + { + get { return _x; } + } + + public double Top + { + get { return _y; } + } + + public double Right + { + get + { + if (IsEmpty) + { + return Double.NegativeInfinity; + } + + return _x + _width; + } + } + + public double Bottom + { + get + { + if (IsEmpty) + { + return Double.NegativeInfinity; + } + + return _y + _height; + } + } + + public static Rect Empty + { + get { return s_empty; } + } + + public bool IsEmpty + { + get { return _width < 0; } + } + + public bool Contains(Point point) + { + return ContainsInternal(point.X, point.Y); + } + + public void Intersect(Rect rect) + { + if (!this.IntersectsWith(rect)) + { + this = s_empty; + } + else + { + double left = Math.Max(X, rect.X); + double top = Math.Max(Y, rect.Y); + + // Max with 0 to prevent double weirdness from causing us to be (-epsilon..0) + Width = Math.Max(Math.Min(X + Width, rect.X + rect.Width) - left, 0); + Height = Math.Max(Math.Min(Y + Height, rect.Y + rect.Height) - top, 0); + + X = left; + Y = top; + } + } + + public void Union(Rect rect) + { + if (IsEmpty) + { + this = rect; + } + else if (!rect.IsEmpty) + { + double left = Math.Min(Left, rect.Left); + double top = Math.Min(Top, rect.Top); + + + // We need this check so that the math does not result in NaN + if ((rect.Width == Double.PositiveInfinity) || (Width == Double.PositiveInfinity)) + { + Width = Double.PositiveInfinity; + } + else + { + // Max with 0 to prevent double weirdness from causing us to be (-epsilon..0) + double maxRight = Math.Max(Right, rect.Right); + Width = Math.Max(maxRight - left, 0); + } + + // We need this check so that the math does not result in NaN + if ((rect.Height == Double.PositiveInfinity) || (Height == Double.PositiveInfinity)) + { + Height = Double.PositiveInfinity; + } + else + { + // Max with 0 to prevent double weirdness from causing us to be (-epsilon..0) + double maxBottom = Math.Max(Bottom, rect.Bottom); + Height = Math.Max(maxBottom - top, 0); + } + + X = left; + Y = top; + } + } + + public void Union(Point point) + { + Union(new Rect(point, point)); + } + + private bool ContainsInternal(double x, double y) + { + return ((x >= X) && (x - Width <= X) && + (y >= Y) && (y - Height <= Y)); + } + + internal bool IntersectsWith(Rect rect) + { + if (Width < 0 || rect.Width < 0) + { + return false; + } + + return (rect.X <= X + Width) && + (rect.X + rect.Width >= X) && + (rect.Y <= Y + Height) && + (rect.Y + rect.Height >= Y); + } + + private static Rect CreateEmptyRect() + { + Rect rect = new Rect(); + + // TODO: for consistency with width/height we should change these + // to assign directly to the backing fields. + rect.X = EmptyX; + rect.Y = EmptyY; + + // the width and height properties prevent assignment of + // negative numbers so assign directly to the backing fields. + rect._width = (float)EmptyWidth; + rect._height = (float)EmptyHeight; + + return rect; + } + + public override string ToString() + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, null /* format provider */); + } + + public string ToString(IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(null /* format string */, provider); + } + + string IFormattable.ToString(string format, IFormatProvider provider) + { + // Delegate to the internal method which implements all ToString calls. + return ConvertToString(format, provider); + } + + internal string ConvertToString(string format, IFormatProvider provider) + { + if (IsEmpty) + { + return SR.DirectUI_Empty; + } + + // Helper to get the numeric list separator for a given culture. + char separator = TokenizerHelper.GetNumericListSeparator(provider); + return String.Format(provider, + "{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "}{0}{4:" + format + "}", + separator, + _x, + _y, + _width, + _height); + } + + public bool Equals(Rect value) + { + return (this == value); + } + + public static bool operator ==(Rect rect1, Rect rect2) + { + return rect1.X == rect2.X && + rect1.Y == rect2.Y && + rect1.Width == rect2.Width && + rect1.Height == rect2.Height; + } + + public static bool operator !=(Rect rect1, Rect rect2) + { + return !(rect1 == rect2); + } + + public override bool Equals(object o) + { + if ((null == o) || !(o is Rect)) + { + return false; + } + + Rect value = (Rect)o; + return (this == value); + } + + public override int GetHashCode() + { + // Perform field-by-field XOR of HashCodes + return X.GetHashCode() ^ + Y.GetHashCode() ^ + Width.GetHashCode() ^ + Height.GetHashCode(); + } + } +} + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning restore 436 +#endif // !FEATURE_SLJ_PROJECTION_COMPAT diff --git a/src/System.Private.Interop/src/Windows/Foundation/Size.cs b/src/System.Private.Interop/src/Windows/Foundation/Size.cs new file mode 100644 index 000000000..3e52f8036 --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/Size.cs @@ -0,0 +1,159 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning disable 436 // Redefining types from Windows.Foundation +#endif // !FEATURE_SLJ_PROJECTION_COMPAT + +#if FEATURE_SLJ_PROJECTION_COMPAT +namespace System.Windows +#else // !FEATURE_SLJ_PROJECTION_COMPAT + + +namespace Windows.Foundation +#endif // FEATURE_SLJ_PROJECTION_COMPAT +{ + // + // Size is the managed projection of Windows.Foundation.Size. Any changes to the layout + // of this type must be exactly mirrored on the native WinRT side as well. + // + // Note that this type is owned by the Jupiter team. Please contact them before making any + // changes here. + // + [StructLayout(LayoutKind.Sequential)] + public struct Size + { + private float _width; + private float _height; + + private readonly static Size s_empty = CreateEmptySize(); + + public Size(double width, double height) + { + if (width < 0) + throw new ArgumentException("width"); + if (height < 0) + throw new ArgumentException("height"); + + _width = (float)width; + _height = (float)height; + } + + public double Width + { + get { return _width; } + set + { + if (value < 0) + throw new ArgumentException("Width"); + + _width = (float)value; + } + } + + public double Height + { + get { return _height; } + set + { + if (value < 0) + throw new ArgumentException("Height"); + + _height = (float)value; + } + } + + public static Size Empty + { + get { return s_empty; } + } + + + public bool IsEmpty + { + get { return Width < 0; } + } + + static private Size CreateEmptySize() + { + Size size = new Size(); + // We can't set these via the property setters because negatives widths + // are rejected in those APIs. + size._width = Single.NegativeInfinity; + size._height = Single.NegativeInfinity; + return size; + } + + public static bool operator ==(Size size1, Size size2) + { + return size1.Width == size2.Width && + size1.Height == size2.Height; + } + + public static bool operator !=(Size size1, Size size2) + { + return !(size1 == size2); + } + + public override bool Equals(object o) + { + if ((null == o) || !(o is Size)) + { + return false; + } + + Size value = (Size)o; + return Size.Equals(this, value); + } + + public bool Equals(Size value) + { + return Size.Equals(this, value); + } + + public override int GetHashCode() + { + if (IsEmpty) + { + return 0; + } + else + { + // Perform field-by-field XOR of HashCodes + return Width.GetHashCode() ^ + Height.GetHashCode(); + } + } + + private static bool Equals(Size size1, Size size2) + { + if (size1.IsEmpty) + { + return size2.IsEmpty; + } + else + { + return size1.Width.Equals(size2.Width) && + size1.Height.Equals(size2.Height); + } + } + + public override string ToString() + { + if (IsEmpty) + { + return "Empty"; + } + + return String.Format("{0},{1}", _width, _height); + } + } +} + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning restore 436 +#endif // !FEATURE_SLJ_PROJECTION_COMPAT diff --git a/src/System.Private.Interop/src/Windows/Foundation/TokenizerHelper.cs b/src/System.Private.Interop/src/Windows/Foundation/TokenizerHelper.cs new file mode 100644 index 000000000..10242e5c8 --- /dev/null +++ b/src/System.Private.Interop/src/Windows/Foundation/TokenizerHelper.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning disable 436 // Redefining types from Windows.Foundation +#endif // !FEATURE_SLJ_PROJECTION_COMPAT + +#if FEATURE_SLJ_PROJECTION_COMPAT +namespace System.Windows +#else // !FEATURE_SLJ_PROJECTION_COMPAT + + +namespace Windows.Foundation +#endif // FEATURE_SLJ_PROJECTION_COMPAT +{ + // + // Note that this type is owned by the Jupiter team. Please contact them before making any + // changes here. + // + internal static class TokenizerHelper + { + internal static char GetNumericListSeparator(IFormatProvider provider) + { + char numericSeparator = ','; + + // Get the NumberFormatInfo out of the provider, if possible + // If the IFormatProvider doesn't not contain a NumberFormatInfo, then + // this method returns the current culture's NumberFormatInfo. + NumberFormatInfo numberFormat = NumberFormatInfo.GetInstance(provider); + + // Is the decimal separator is the same as the list separator? + // If so, we use the ";". + if ((numberFormat.NumberDecimalSeparator.Length > 0) && (numericSeparator == numberFormat.NumberDecimalSeparator[0])) + { + numericSeparator = ';'; + } + + return numericSeparator; + } + } +} + +#if !FEATURE_SLJ_PROJECTION_COMPAT +#pragma warning restore 436 +#endif // !FEATURE_SLJ_PROJECTION_COMPAT + |