// // System.Variant // // Authors: // Jonathan Chambers // // Copyright (C) 2006 Novell (http://www.novell.com) // // // 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.Runtime.InteropServices; namespace System { [StructLayout(LayoutKind.Explicit)] internal unsafe struct Variant { [FieldOffset(0)] public short vt; [FieldOffset(2)] public ushort wReserved1; [FieldOffset(4)] public ushort wReserved2; [FieldOffset(6)] public ushort wReserved3; [FieldOffset(8)] public long llVal; [FieldOffset(8)] public int lVal; [FieldOffset(8)] public byte bVal; [FieldOffset(8)] public short iVal; [FieldOffset(8)] public float fltVal; [FieldOffset(8)] public double dblVal; [FieldOffset(8)] public short boolVal; [FieldOffset(8)] public IntPtr bstrVal; [FieldOffset(8)] public sbyte cVal; [FieldOffset(8)] public ushort uiVal; [FieldOffset(8)] public uint ulVal; [FieldOffset(8)] public ulong ullVal; [FieldOffset(8)] public int intVal; [FieldOffset(8)] public uint uintVal; [FieldOffset(8)] public IntPtr pdispVal; [FieldOffset(8)] public BRECORD bRecord; public void SetValue(object obj) { vt = (short)VarEnum.VT_EMPTY; if (obj == null) return; Type t = obj.GetType(); if (t.IsEnum) t = Enum.GetUnderlyingType (t); if (t == typeof(sbyte)) { vt = (short)VarEnum.VT_I1; cVal = (sbyte)obj; } else if (t == typeof(byte)) { vt = (short)VarEnum.VT_UI1; bVal = (byte)obj; } else if (t == typeof(short)) { vt = (short)VarEnum.VT_I2; iVal = (short)obj; } else if (t == typeof(ushort)) { vt = (short)VarEnum.VT_UI2; uiVal = (ushort)obj; } else if (t == typeof(int)) { vt = (short)VarEnum.VT_I4; lVal = (int)obj; } else if (t == typeof(uint)) { vt = (short)VarEnum.VT_UI4; ulVal = (uint)obj; } else if (t == typeof(long)) { vt = (short)VarEnum.VT_I8; llVal = (long)obj; } else if (t == typeof(ulong)) { vt = (short)VarEnum.VT_UI8; ullVal = (ulong)obj; } else if (t == typeof(float)) { vt = (short)VarEnum.VT_R4; fltVal = (float)obj; } else if (t == typeof(double)) { vt = (short)VarEnum.VT_R8; dblVal = (double)obj; } else if (t == typeof(string)) { vt = (short)VarEnum.VT_BSTR; bstrVal = Marshal.StringToBSTR((string)obj); } else if (t == typeof(bool)) { vt = (short)VarEnum.VT_BOOL; lVal = ((bool)obj) ? -1 : 0; } else if (t == typeof (BStrWrapper)) { vt = (short)VarEnum.VT_BSTR; bstrVal = Marshal.StringToBSTR(((BStrWrapper)obj).WrappedObject); } #if FEATURE_COMINTEROP else if (t == typeof (UnknownWrapper)) { vt = (short)VarEnum.VT_UNKNOWN; pdispVal = Marshal.GetIUnknownForObject(((UnknownWrapper)obj).WrappedObject); } else if (t == typeof (DispatchWrapper)) { vt = (short)VarEnum.VT_DISPATCH; pdispVal = Marshal.GetIDispatchForObject(((DispatchWrapper)obj).WrappedObject); } #endif else { #if !FEATURE_COMINTEROP throw new NotImplementedException(string.Format("Variant couldn't handle object of type {0}", obj.GetType())); #else try { pdispVal = Marshal.GetIDispatchForObject(obj); vt = (short)VarEnum.VT_DISPATCH; return; } catch { } try { vt = (short)VarEnum.VT_UNKNOWN; pdispVal = Marshal.GetIUnknownForObject(obj); } catch (Exception ex) { throw new NotImplementedException(string.Format("Variant couldn't handle object of type {0}", obj.GetType()), ex); } #endif } } public static object GetValueAt(int vt, IntPtr addr) { object obj = null; switch ((VarEnum)vt) { case VarEnum.VT_I1: obj = (sbyte)Marshal.ReadByte(addr); break; case VarEnum.VT_UI1: obj = Marshal.ReadByte(addr); break; case VarEnum.VT_I2: obj = Marshal.ReadInt16(addr); break; case VarEnum.VT_UI2: obj = (ushort)Marshal.ReadInt16(addr); break; case VarEnum.VT_I4: obj = Marshal.ReadInt32(addr); break; case VarEnum.VT_UI4: obj = (uint)Marshal.ReadInt32(addr); break; case VarEnum.VT_I8: obj = Marshal.ReadInt64(addr); break; case VarEnum.VT_UI8: obj = (ulong)Marshal.ReadInt64(addr); break; case VarEnum.VT_R4: obj = Marshal.PtrToStructure(addr, typeof(float)); break; case VarEnum.VT_R8: obj = Marshal.PtrToStructure(addr, typeof(double)); break; case VarEnum.VT_BOOL: obj = !(Marshal.ReadInt16(addr) == 0); break; case VarEnum.VT_BSTR: obj = Marshal.PtrToStringBSTR(Marshal.ReadIntPtr(addr)); break; // GetObjectForIUnknown is excluded from Marshal using FULL_AOT_RUNTIME #if !DISABLE_COM case VarEnum.VT_UNKNOWN: case VarEnum.VT_DISPATCH: { IntPtr ifaceaddr = Marshal.ReadIntPtr(addr); if (ifaceaddr != IntPtr.Zero) obj = Marshal.GetObjectForIUnknown(ifaceaddr); break; } #endif } return obj; } public object GetValue() { object obj = null; switch ((VarEnum)vt) { case VarEnum.VT_I1: obj = cVal; break; case VarEnum.VT_UI1: obj = bVal; break; case VarEnum.VT_I2: obj = iVal; break; case VarEnum.VT_UI2: obj = uiVal; break; case VarEnum.VT_I4: obj = lVal; break; case VarEnum.VT_UI4: obj = ulVal; break; case VarEnum.VT_I8: obj = llVal; break; case VarEnum.VT_UI8: obj = ullVal; break; case VarEnum.VT_R4: obj = fltVal; break; case VarEnum.VT_R8: obj = dblVal; break; case VarEnum.VT_BOOL: obj = !(boolVal == 0); break; case VarEnum.VT_BSTR: obj = Marshal.PtrToStringBSTR(bstrVal); break; #if FEATURE_COMINTEROP case VarEnum.VT_UNKNOWN: case VarEnum.VT_DISPATCH: if (pdispVal != IntPtr.Zero) obj = Marshal.GetObjectForIUnknown(pdispVal); break; #endif default: if (((VarEnum)vt & VarEnum.VT_BYREF) == VarEnum.VT_BYREF && pdispVal != IntPtr.Zero) { obj = GetValueAt(vt & ~(short)VarEnum.VT_BYREF, pdispVal); } break; } return obj; } public void Clear () { if ((VarEnum)vt == VarEnum.VT_BSTR) { Marshal.FreeBSTR (bstrVal); } #if !DISABLE_COM else if ((VarEnum)vt == VarEnum.VT_DISPATCH || (VarEnum)vt == VarEnum.VT_UNKNOWN) { if (pdispVal != IntPtr.Zero) Marshal.Release (pdispVal); } #endif } } [StructLayout(LayoutKind.Sequential)] internal unsafe struct BRECORD { #pragma warning disable 169 IntPtr pvRecord; IntPtr pRecInfo; #pragma warning restore 169 } }