diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2017-10-25 12:11:09 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-25 12:11:09 +0300 |
commit | 41ab3cc38c1837a4cb152fb47d5a9fe82395db79 (patch) | |
tree | 572671723d66f293771c1bc6f5d27ef7be988e00 /src/System.Private.Interop | |
parent | ba17d2e3a904d46f4973c2e31cf668fd06432aa0 (diff) | |
parent | a4bb592487fcf5af1d9f98484de904facd8d8c39 (diff) |
Merge pull request #4790 from dotnet/nmirror
Merge nmirror to master
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 + |