Win32/Variant.cs (365 lines of code) (raw):

// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Globalization; using System.Runtime.InteropServices; using System.Reflection; namespace SharpGen.Runtime.Win32 { /// <summary> /// Variant COM. /// </summary> /// <unmanaged>PROPVARIANT</unmanaged> [StructLayout(LayoutKind.Sequential)] public struct Variant { private ushort vt; private ushort reserved1; private ushort reserved2; private ushort reserved3; private VariantValue variantValue; /// <summary> /// Gets the type of the element. /// </summary> /// <value> /// The type of the element. /// </value> public VariantElementType ElementType { get { return (VariantElementType)(vt & 0x0fff); } set { vt = (ushort)((vt & 0xf000) | (ushort)value); } } /// <summary> /// Gets the type. /// </summary> public VariantType Type { get { return (VariantType)(vt & 0xf000); } set { vt = (ushort)((vt & 0x0fff) | (ushort)value); } } /// <summary> /// Gets or sets the value. /// </summary> /// <value> /// The value. /// </value> public unsafe object Value { get { switch (Type) { case VariantType.Default: switch (ElementType) { case VariantElementType.Empty: case VariantElementType.Null: return null; case VariantElementType.Blob: { var buffer = new byte[(int)variantValue.recordValue.RecordInfo]; if (buffer.Length > 0) { MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<byte>(buffer), buffer.Length); } return buffer; } case VariantElementType.Bool: return variantValue.intValue != 0; case VariantElementType.Byte: return variantValue.signedByteValue; case VariantElementType.UByte: return variantValue.byteValue; case VariantElementType.UShort: return variantValue.ushortValue; case VariantElementType.Short: return variantValue.shortValue; case VariantElementType.UInt: case VariantElementType.UInt1: return variantValue.uintValue; case VariantElementType.Int: case VariantElementType.Int1: return variantValue.intValue; case VariantElementType.ULong: return variantValue.ulongValue; case VariantElementType.Long: return variantValue.longValue; case VariantElementType.Float: return variantValue.floatValue; case VariantElementType.Double: return variantValue.doubleValue; case VariantElementType.BinaryString: throw new NotSupportedException(); case VariantElementType.StringPointer: return Marshal.PtrToStringAnsi(variantValue.pointerValue); case VariantElementType.WStringPointer: return Marshal.PtrToStringUni(variantValue.pointerValue); case VariantElementType.ComUnknown: case VariantElementType.Dispatch: return new ComObject(variantValue.pointerValue); case VariantElementType.IntPointer: case VariantElementType.Pointer: return variantValue.pointerValue; case VariantElementType.FileTime: return DateTime.FromFileTime(variantValue.longValue); default: return null; } case VariantType.Vector: var size = (int)variantValue.recordValue.RecordInfo; switch (ElementType) { case VariantElementType.Bool: unsafe { var array = stackalloc RawBool[size]; var span = new ReadOnlySpan<RawBool>(array, size); MemoryHelpers.Read(variantValue.recordValue.RecordPointer, span, size); return RawBoolHelpers.ConvertToBoolArray(span); } case VariantElementType.Byte: { var array = new sbyte[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<sbyte>(array), size); return array; } case VariantElementType.UByte: { var array = new byte[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<byte>(array), size); return array; } case VariantElementType.UShort: { var array = new ushort[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<ushort>(array), size); return array; } case VariantElementType.Short: { var array = new short[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<short>(array), size); return array; } case VariantElementType.UInt: case VariantElementType.UInt1: { var array = new uint[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<uint>(array), size); return array; } case VariantElementType.Int: case VariantElementType.Int1: { var array = new int[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<int>(array), size); return array; } case VariantElementType.ULong: { var array = new ulong[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<ulong>(array), size); return array; } case VariantElementType.Long: { var array = new long[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<long>(array), size); return array; } case VariantElementType.Float: { var array = new float[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<float>(array), size); return array; } case VariantElementType.Double: { var array = new double[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<double>(array), size); return array; } case VariantElementType.BinaryString: { throw new NotSupportedException(); } case VariantElementType.StringPointer: { var array = new string[size]; for (int i = 0; i < size; i++) array[i] = Marshal.PtrToStringAnsi(((IntPtr*)variantValue.recordValue.RecordPointer)[i]); return array; } case VariantElementType.WStringPointer: { var array = new string[size]; for (int i = 0; i < size; i++) array[i] = Marshal.PtrToStringUni(((IntPtr*)variantValue.recordValue.RecordPointer)[i]); return array; } case VariantElementType.ComUnknown: case VariantElementType.Dispatch: { var comArray = new ComObject[size]; for (int i = 0; i < size; i++) comArray[i] = new ComObject(((IntPtr*)variantValue.recordValue.RecordPointer)[i]); return comArray; } case VariantElementType.IntPointer: case VariantElementType.Pointer: { var array = new IntPtr[size]; MemoryHelpers.Read(variantValue.recordValue.RecordPointer, new ReadOnlySpan<IntPtr>(array), size); return array; } case VariantElementType.FileTime: { var fileTimeArray = new DateTime[size]; for (int i = 0; i < size; i++) fileTimeArray[i] = DateTime.FromFileTime(((long*)variantValue.recordValue.RecordPointer)[i]); return fileTimeArray; } default: return null; } } return null; } set { if (value == null) { Type = VariantType.Default; ElementType = VariantElementType.Null; return; } var type = value.GetType(); Type = VariantType.Default; if (type.GetTypeInfo().IsPrimitive) { if (type == typeof(byte)) { ElementType = VariantElementType.UByte; variantValue.byteValue = (byte)value; return; } if (type == typeof(sbyte)) { ElementType = VariantElementType.Byte; variantValue.signedByteValue = (sbyte)value; return; } if (type == typeof(int)) { ElementType = VariantElementType.Int; variantValue.intValue = (int)value; return; } if (type == typeof(uint)) { ElementType = VariantElementType.UInt; variantValue.uintValue = (uint)value; return; } if (type == typeof(long)) { ElementType = VariantElementType.Long; variantValue.longValue= (long)value; return; } if (type == typeof(ulong)) { ElementType = VariantElementType.ULong; variantValue.ulongValue = (ulong)value; return; } if (type == typeof(short)) { ElementType = VariantElementType.Short; variantValue.shortValue= (short)value; return; } if (type == typeof(ushort)) { ElementType = VariantElementType.UShort; variantValue.ushortValue = (ushort)value; return; } if (type == typeof(float)) { ElementType = VariantElementType.Float; variantValue.floatValue = (float)value; return; } if (type == typeof(double)) { ElementType = VariantElementType.Double; variantValue.doubleValue = (double)value; return; } } else if (value is ComObject obj) { ElementType = VariantElementType.ComUnknown; variantValue.pointerValue = obj.NativePointer; return; } else if (value is DateTime dateTime) { ElementType = VariantElementType.FileTime; variantValue.longValue = dateTime.ToFileTime(); return; } else if (value is string str) { ElementType = VariantElementType.WStringPointer; variantValue.pointerValue = Marshal.StringToCoTaskMemUni(str); return; } throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Type [{0}] is not handled", type.Name)); } } [StructLayout(LayoutKind.Explicit)] private struct VariantValue { [FieldOffset(0)] public byte byteValue; [FieldOffset(0)] public sbyte signedByteValue; [FieldOffset(0)] public ushort ushortValue; [FieldOffset(0)] public short shortValue; [FieldOffset(0)] public uint uintValue; [FieldOffset(0)] public int intValue; [FieldOffset(0)] public ulong ulongValue; [FieldOffset(0)] public long longValue; [FieldOffset(0)] public float floatValue; [FieldOffset(0)] public double doubleValue; [FieldOffset(0)] public IntPtr pointerValue; [FieldOffset(0)] public CurrencyValue currencyValue; [FieldOffset(0)] public RecordValue recordValue; [StructLayout(LayoutKind.Sequential)] public struct CurrencyLowHigh { public uint LowValue; public int HighValue; } [StructLayout(LayoutKind.Explicit)] public struct CurrencyValue { [FieldOffset(0)] public CurrencyLowHigh LowHigh; [FieldOffset(0)] public long longValue; } [StructLayout(LayoutKind.Sequential)] public struct RecordValue { public IntPtr RecordInfo; public IntPtr RecordPointer; } }; } }