// VARENUMs that are VARIANT only (e.g. not valid for PROPVARIANT) // // VT_DISPATCH // VT_UNKNOWN // VT_DECIMAL // VT_UINT // VT_ARRAY // VT_BYREF public override object?GetData() { VARENUM propertyType = RawVariantType; if ((propertyType & VARENUM.VT_BYREF) != 0 || (propertyType & VARENUM.VT_ARRAY) != 0) { // Not legit for PROPVARIANT throw new InvalidOleVariantTypeException(); } if ((propertyType & VARENUM.VT_VECTOR) != 0) { throw new NotImplementedException(); } propertyType &= VARENUM.VT_TYPEMASK; switch (propertyType) { case VARENUM.VT_DISPATCH: case VARENUM.VT_UNKNOWN: case VARENUM.VT_DECIMAL: case VARENUM.VT_UINT: throw new InvalidOleVariantTypeException(); } return(base.GetData()); }
public Type Test_ObjectConversion_IConvertible(VARENUM vt, TypeCode code) { var convertible = new ConvertibleTest(code); var result = VariantConverter.ChangeType(convertible, vt); return(result.GetType()); }
public void SAFEARRAY_CreateSingleDimension_GetProperties_Success(ushort vt, ushort expectedFeatures, uint expectedCbElements) { var saBound = new SAFEARRAYBOUND { cElements = 10, lLbound = 1 }; SAFEARRAY *psa = SafeArrayCreate((VARENUM)vt, 1, &saBound); Assert.True(psa != null); try { Assert.Equal(1u, psa->cDims); Assert.Equal((FADF)expectedFeatures, psa->fFeatures); Assert.Equal((uint)expectedCbElements, psa->cbElements); Assert.Equal(0u, psa->cLocks); Assert.True(psa->pvData != null); Assert.Equal(10u, psa->rgsabound[0].cElements); Assert.Equal(1, psa->rgsabound[0].lLbound); VARENUM arrayVt = VARENUM.EMPTY; HRESULT hr = SafeArrayGetVartype(psa, &arrayVt); Assert.Equal(HRESULT.S_OK, hr); Assert.Equal((VARENUM)vt, arrayVt); } finally { HRESULT hr = SafeArrayDestroy(psa); Assert.Equal(HRESULT.S_OK, hr); } }
// VARENUMs that are VARIANT only (e.g. not valid for PROPVARIANT) // // VT_DISPATCH // VT_UNKNOWN // VT_DECIMAL // VT_UINT // VT_ARRAY // VT_BYREF // protected virtual unsafe object GetCoreType(VARENUM propertyType, void *data) { switch (propertyType) { case VARENUM.VT_I4: case VARENUM.VT_INT: case VARENUM.VT_ERROR: // SCODE return(*((int *)data)); case VARENUM.VT_UI4: case VARENUM.VT_UINT: return(*((uint *)data)); case VARENUM.VT_I2: return(*((short *)data)); case VARENUM.VT_UI2: return(*((ushort *)data)); case VARENUM.VT_I1: return(*((sbyte *)data)); case VARENUM.VT_UI1: return(*((byte *)data)); case VARENUM.VT_CY: // Currency (long long) return(*((long *)data)); case VARENUM.VT_R4: return(*((float *)data)); case VARENUM.VT_R8: return(*((double *)data)); case VARENUM.VT_DECIMAL: return((*((DECIMAL *)data)).ToDecimal()); case VARENUM.VT_BOOL: // VARIANT_TRUE is -1 return(*((short *)data) == -1); case VARENUM.VT_BSTR: return(Marshal.PtrToStringBSTR((IntPtr)(*((void **)data)))); case VARENUM.VT_VARIANT: return(new VARIANT(new IntPtr(*((void **)data)), ownsHandle: false)); case VARENUM.VT_DATE: return(Conversion.VariantDateToDateTime(*((double *)data))); case VARENUM.VT_RECORD: case VARENUM.VT_DISPATCH: case VARENUM.VT_UNKNOWN: throw new NotImplementedException(); default: return(s_UnsupportedObject); } }
static void HeapTransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType) { var indices = new int[array.Rank]; var lower = new int[array.Rank]; var upper = new int[array.Rank]; InternalTransposeArray(psa, array, arrayType, indices, lower, upper); }
static void StackTransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType) { Span <int> indices = stackalloc int[array.Rank]; Span <int> lower = stackalloc int[array.Rank]; Span <int> upper = stackalloc int[array.Rank]; InternalTransposeArray(psa, array, arrayType, indices, lower, upper); }
public void Clear() { fixed(VARIANT *pThis = &this) { VariantClear(pThis); } vt = VARENUM.EMPTY; data1 = IntPtr.Zero; data2 = IntPtr.Zero; }
private static void TransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType) { if (array.Rank <= 32) { StackTransposeArray(psa, array, arrayType); } else { Debug.Fail("The CLR should not support arrays with more than 32 dimensions."); HeapTransposeArray(psa, array, arrayType); }
public static object ChangeType(object value, VARENUM vt, CultureInfo cultureInfo) { object result = null; var hr = cultureInfo == null ? VariantChangeType(ref result, ref value, VariantConversionFlags.NO_FLAGS, vt) : VariantChangeTypeEx(ref result, ref value, cultureInfo.LCID, VariantConversionFlags.NO_FLAGS, vt); if (HRESULT_FAILED(hr)) { throw Marshal.GetExceptionForHR(hr); } return(result); }
public void Clear() { if ((vt == VARENUM.UNKNOWN || vt == VARENUM.DISPATCH) && data1 != IntPtr.Zero) { Marshal.Release(data1); } if (vt == VARENUM.BSTR && data1 != IntPtr.Zero) { Oleaut32.SysFreeString(data1); } data1 = data2 = IntPtr.Zero; vt = VARENUM.EMPTY; }
public void SAFEARRAY_CreateSingleDimensionRECORD_GetProperties_Success() { var saBound = new SAFEARRAYBOUND { cElements = 10, lLbound = 1 }; var record = new CustomRecordInfo(); IntPtr pRecord = Marshal.GetComInterfaceForObject <CustomRecordInfo, IRecordInfo>(record); try { SAFEARRAY *psa = SafeArrayCreateEx(VARENUM.RECORD, 1, &saBound, pRecord); Assert.True(psa != null); try { Assert.Equal(1u, psa->cDims); Assert.Equal(FADF.RECORD, psa->fFeatures); Assert.Equal((uint)sizeof(int), psa->cbElements); Assert.Equal(0u, psa->cLocks); Assert.True(psa->pvData != null); Assert.Equal(10u, psa->rgsabound[0].cElements); Assert.Equal(1, psa->rgsabound[0].lLbound); VARENUM arrayVt = VARENUM.EMPTY; HRESULT hr = SafeArrayGetVartype(psa, &arrayVt); Assert.Equal(HRESULT.S_OK, hr); Assert.Equal(VARENUM.RECORD, arrayVt); } finally { HRESULT hr = SafeArrayDestroy(psa); Assert.Equal(HRESULT.S_OK, hr); } } finally { Marshal.Release(pRecord); } }
protected override unsafe object?GetCoreType(VARENUM propertyType, void *data) { object?value = base.GetCoreType(propertyType, data); if (!ReferenceEquals(value, s_UnsupportedObject)) { return(value); } switch (propertyType) { case VARENUM.VT_I8: return(*((long *)data)); case VARENUM.VT_UI8: return(*((ulong *)data)); case VARENUM.VT_LPSTR: return(Marshal.PtrToStringAnsi((IntPtr)data)); case VARENUM.VT_LPWSTR: return(Marshal.PtrToStringUni((IntPtr)data)); case VARENUM.VT_CLSID: return(Marshal.PtrToStructure <Guid>((IntPtr)(*((void **)data)))); case VARENUM.VT_FILETIME: case VARENUM.VT_BLOB: case VARENUM.VT_STREAM: case VARENUM.VT_STORAGE: case VARENUM.VT_STREAMED_OBJECT: case VARENUM.VT_STORED_OBJECT: case VARENUM.VT_VERSIONED_STREAM: case VARENUM.VT_BLOB_OBJECT: case VARENUM.VT_CF: case VARENUM.VT_VECTOR: default: return(s_UnsupportedObject); } }
public unsafe virtual object GetData() { VARENUM propertyType = VariantType; switch (propertyType) { case VARENUM.VT_EMPTY: case VARENUM.VT_NULL: return(null); } if (IsArray) { throw new NotImplementedException(); } void *data = handle.Offset(DataOffset); if (IsByRef) { data = *((void **)data); } else if (propertyType == VARENUM.VT_DECIMAL) { // DECIMAL starts at the beginning of the VARIANT, with the VARIANT's type occupying // the reserved ushort in the DECIMAL and the DECIMAL occupying the reserved WORDs // in the VARIANT. data = handle.ToPointer(); } object result = GetCoreType(propertyType, data); if (ReferenceEquals(result, s_UnsupportedObject)) { throw new InvalidOleVariantTypeException(); } return(result); }
static void InternalTransposeArray(SAFEARRAY *psa, Array array, VARENUM arrayType, Span <int> indices, Span <int> lower, Span <int> upper) { int lastIndex = array.Rank - 1; int i; for (i = 0; i < array.Rank; i++) { indices[i] = lower[i] = array.GetLowerBound(i); upper[i] = array.GetUpperBound(i); } // Loop through all the indices. while (true) { BeginMainLoop: SetArrayValue(psa, array, indices, lower, arrayType); for (i = lastIndex; i > 0;) { if (++indices[i] <= upper[i]) { goto BeginMainLoop; } indices[i] = lower[i]; --i; } // Special case for the first index, it must be enumerated only once if (++indices[0] > upper[0]) { break; } } }
public static object ChangeType(object value, VARENUM vt) { return(ChangeType(value, vt, null)); }
public void Clear() { PropVariantClear(ref this); vt = VARENUM.EMPTY; data = new VARIANTUnion(); }
private static object?ToArray(SAFEARRAY *psa, VARENUM vt) { if (psa is null) { return(null); } VARENUM arrayType = vt & ~VARENUM.ARRAY; Array array = CreateArrayFromSafeArray(psa, arrayType); HRESULT hr = SafeArrayLock(psa); Debug.Assert(hr == HRESULT.S_OK); try { if (array.Rank == 1) { switch (arrayType) { case VARENUM.I1: new Span <sbyte>(psa->pvData, array.Length) .CopyTo(GetSpan <sbyte>(array)); break; case VARENUM.UI1: new Span <byte>(psa->pvData, array.Length) .CopyTo(GetSpan <byte>(array)); break; case VARENUM.I2: new Span <short>(psa->pvData, array.Length) .CopyTo(GetSpan <short>(array)); break; case VARENUM.UI2: new Span <ushort>(psa->pvData, array.Length) .CopyTo(GetSpan <ushort>(array)); break; case VARENUM.I4: case VARENUM.INT: new Span <int>(psa->pvData, array.Length) .CopyTo(GetSpan <int>(array)); break; case VARENUM.UI4: case VARENUM.UINT: case VARENUM.ERROR: // Not explicitly mentioned in the docs but trivial to implement. new Span <uint>(psa->pvData, array.Length) .CopyTo(GetSpan <uint>(array)); break; case VARENUM.I8: new Span <long>(psa->pvData, array.Length) .CopyTo(GetSpan <long>(array)); break; case VARENUM.UI8: new Span <ulong>(psa->pvData, array.Length) .CopyTo(GetSpan <ulong>(array)); break; case VARENUM.R4: new Span <float>(psa->pvData, array.Length) .CopyTo(GetSpan <float>(array)); break; case VARENUM.R8: new Span <double>(psa->pvData, array.Length) .CopyTo(GetSpan <double>(array)); break; case VARENUM.BOOL: { var data = new Span <VARIANT_BOOL>(psa->pvData, array.Length); var result = GetSpan <bool>(array); for (int i = 0; i < data.Length; i++) { result[i] = data[i] != VARIANT_BOOL.FALSE; } break; } case VARENUM.DECIMAL: { var data = new Span <DECIMAL>(psa->pvData, array.Length); var result = GetSpan <decimal>(array); for (int i = 0; i < data.Length; i++) { result[i] = data[i].ToDecimal(); } break; } case VARENUM.CY: { var data = new Span <long>(psa->pvData, array.Length); var result = GetSpan <decimal>(array); for (int i = 0; i < data.Length; i++) { result[i] = decimal.FromOACurrency(data[i]); } break; } case VARENUM.DATE: { var data = new Span <double>(psa->pvData, array.Length); var result = GetSpan <DateTime>(array); for (int i = 0; i < data.Length; i++) { result[i] = DateTime.FromOADate(data[i]); } break; } case VARENUM.BSTR: { var data = new Span <IntPtr>(psa->pvData, array.Length); var result = GetSpan <string?>(array); for (int i = 0; i < data.Length; i++) { result[i] = Marshal.PtrToStringUni(data[i]); } break; } case VARENUM.DISPATCH: case VARENUM.UNKNOWN: { var data = new Span <IntPtr>(psa->pvData, array.Length); var result = GetSpan <object?>(array); for (int i = 0; i < data.Length; i++) { if (data[i] == IntPtr.Zero) { result[i] = null; } else { result[i] = Marshal.GetObjectForIUnknown(data[i]); } } break; } case VARENUM.VARIANT: { var data = new Span <VARIANT>(psa->pvData, array.Length); var result = GetSpan <object?>(array); for (int i = 0; i < data.Length; i++) { result[i] = data[i].ToObject(); } break; } case VARENUM.RECORD: throw new NotImplementedException(); default: throw new ArgumentException(string.Format(SR.COM2UnhandledVT, vt)); } } else if (array.Length != 0) { // CLR arrays are laid out in row-major order. // See CLI 8.9.1: https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf // However, SAFEARRAYs are laid out in column-major order. // See https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/array-manipulation-functions // Therefore, we need to transpose data. TransposeArray(psa, array, arrayType); } } finally { hr = SafeArrayUnlock(psa); Debug.Assert(hr == HRESULT.S_OK); } return(array); }
public static extern HRESULT PropVariantChangeType( [Out] IntPtr ppvDest, [In] IntPtr ppvIn, [In] int flags, // Reserved, must be zero [In] VARENUM vt);
public object ToObject() { IntPtr val = data1; long longVal; VARENUM vtType = vt & ~VARENUM.TYPEMASK; switch (vtType) { case VARENUM.EMPTY: return(null); case VARENUM.NULL: return(Convert.DBNull); case VARENUM.I1: if (Byref) { val = (IntPtr)Marshal.ReadByte(val); } return((sbyte)(0xFF & (sbyte)val)); case VARENUM.UI1: if (Byref) { val = (IntPtr)Marshal.ReadByte(val); } return((byte)(0xFF & (byte)val)); case VARENUM.I2: if (Byref) { val = (IntPtr)Marshal.ReadInt16(val); } return((short)(0xFFFF & (short)val)); case VARENUM.UI2: if (Byref) { val = (IntPtr)Marshal.ReadInt16(val); } return((ushort)(0xFFFF & (ushort)val)); case VARENUM.I4: case VARENUM.INT: if (Byref) { val = (IntPtr)Marshal.ReadInt32(val); } return((int)val); case VARENUM.UI4: case VARENUM.UINT: if (Byref) { val = (IntPtr)Marshal.ReadInt32(val); } return((uint)val); case VARENUM.I8: case VARENUM.UI8: if (Byref) { longVal = Marshal.ReadInt64(val); } else { longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32); } if (vt == VARENUM.I8) { return((long)longVal); } else { return((ulong)longVal); } } if (Byref) { val = GetRefInt(val); } switch (vtType) { case VARENUM.R4: case VARENUM.R8: // can I use unsafe here? throw new FormatException(SR.CannotConvertIntToFloat); case VARENUM.CY: // internally currency is 8-byte int scaled by 10,000 longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32); return(new decimal(longVal)); case VARENUM.DATE: throw new FormatException(SR.CannotConvertDoubleToDate); case VARENUM.BSTR: case VARENUM.LPWSTR: return(Marshal.PtrToStringUni(val)); case VARENUM.LPSTR: return(Marshal.PtrToStringAnsi(val)); case VARENUM.DISPATCH: case VARENUM.UNKNOWN: { return(Marshal.GetObjectForIUnknown(val)); } case VARENUM.HRESULT: return(val); case VARENUM.DECIMAL: longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32); return(new decimal(longVal)); case VARENUM.BOOL: return(val != IntPtr.Zero); case VARENUM.VARIANT: VARIANT varStruct = Marshal.PtrToStructure <VARIANT>(val); return(varStruct.ToObject()); case VARENUM.CLSID: Guid guid = Marshal.PtrToStructure <Guid>(val); return(guid); case VARENUM.FILETIME: longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32); return(new DateTime(longVal)); case VARENUM.USERDEFINED: throw new ArgumentException(string.Format(SR.COM2UnhandledVT, "USERDEFINED")); case VARENUM.ARRAY: case VARENUM.VOID: case VARENUM.PTR: case VARENUM.SAFEARRAY: case VARENUM.CARRAY: case VARENUM.RECORD: case VARENUM.BLOB: case VARENUM.STREAM: case VARENUM.STORAGE: case VARENUM.STREAMED_OBJECT: case VARENUM.STORED_OBJECT: case VARENUM.BLOB_OBJECT: case VARENUM.CF: case VARENUM.BSTR_BLOB: case VARENUM.VECTOR: case VARENUM.BYREF: default: throw new ArgumentException(string.Format(SR.COM2UnhandledVT, vt)); } }
private static extern int VariantChangeTypeEx(ref object pvargDest, ref object pvarSrc, int lcid, VariantConversionFlags wFlags, VARENUM vt);
private static void SetArrayValue(SAFEARRAY *psa, Array array, Span <int> indices, Span <int> lowerBounds, VARENUM arrayType) {
private void Serialize_Object(BinaryWriter bw, object obj) { if (obj == null) { // 型: VT_EMPTY, 要素数: 1 bw.Write(bCAPByteConverter.Value2Byte((Int16)VARENUM.VT_EMPTY)); bw.Write(bCAPByteConverter.Value2Byte((Int32)1)); } else { // 引数の型を取得 Type t = obj.GetType(); if (t.IsArray) { // 配列に変換 Array objArray = (Array)obj; // 要素の型を取得 t = t.GetElementType(); if (t == typeof(Object)) { // 型: (VT_VARIANT | VT_ARRAY), 要素数: objArray.Length bw.Write(bCAPByteConverter.Value2Byte((Int16)(VARENUM.VT_VARIANT | VARENUM.VT_ARRAY))); bw.Write(bCAPByteConverter.Value2Byte((Int32)objArray.Length)); // 再帰 Serialize_ObjectArray(bw, new ArrayList(objArray)); } else { // TypeをVARENUMに変換 VARENUM vt = FindVtFromType(t); // 型: (vt | VT_ARRAY), 要素数: objArray.Length bw.Write(bCAPByteConverter.Value2Byte((Int16)(vt | VARENUM.VT_ARRAY))); bw.Write(bCAPByteConverter.Value2Byte((Int32)objArray.Length)); if (t == typeof(Byte)) { // バイト配列はそのまま代入 bw.Write((byte[])objArray); } else if (t == typeof(String)) { // 文字列配列をバイト配列に変換 foreach (String tmp in objArray) { bw.Write(bCAPByteConverter.Value2Byte((Int32)(2 * tmp.Length))); bw.Write(bCAPByteConverter.Value2Byte(tmp)); } } else { // 各要素をバイト配列に変換 foreach (object tmp in objArray) { bw.Write(bCAPByteConverter.Value2Byte(tmp)); } } } } else { // TypeをVARENUMに変換 VARENUM vt = FindVtFromType(t); // 型: vt, 要素数: 1 bw.Write(bCAPByteConverter.Value2Byte((Int16)vt)); bw.Write(bCAPByteConverter.Value2Byte((Int32)1)); if (t == typeof(Byte)) { // バイトはそのまま代入 bw.Write((byte)obj); } else if (t == typeof(String)) { // 文字列をバイト配列に変換 bw.Write(bCAPByteConverter.Value2Byte((Int32)(2 * ((String)obj).Length))); bw.Write(bCAPByteConverter.Value2Byte(obj)); } else { // 要素をバイト配列に変換 bw.Write(bCAPByteConverter.Value2Byte(obj)); } } } }
internal static extern int VariantChangeType(ref object pvargDest, ref object pvarSrc, VariantConversionFlags wFlags, VARENUM vt);
/// <summary> /// Coerces a <see cref="PropVariant"/> value to the specified type. and returns that value as a native instance of that type /// </summary> /// <typeparam name="T">The native type required</typeparam> /// <returns>The value of the PropVariant</returns> public T ToType <T>() { using (PropVariant propVar = new PropVariant()) { HRESULT hr; VARENUM vt = VARENUM.VT_EMPTY; switch (Type.GetTypeCode(typeof(T))) { case TypeCode.Boolean: vt = VARENUM.VT_BOOL; break; case TypeCode.Byte: vt = VARENUM.VT_UI1; break; case TypeCode.Char: vt = VARENUM.VT_I1; break; case TypeCode.Single: vt = VARENUM.VT_R4; break; case TypeCode.Double: vt = VARENUM.VT_R8; break; case TypeCode.DateTime: vt = VARENUM.VT_FILETIME; break; case TypeCode.Decimal: vt = VARENUM.VT_DECIMAL; break; case TypeCode.Int16: vt = VARENUM.VT_I2; break; case TypeCode.Int32: vt = VARENUM.VT_I4; break; case TypeCode.Int64: vt = VARENUM.VT_I8; break; case TypeCode.UInt16: vt = VARENUM.VT_UI2; break; case TypeCode.UInt32: vt = VARENUM.VT_UI4; break; case TypeCode.UInt64: vt = VARENUM.VT_UI8; break; case TypeCode.String: { IntPtr pStr = IntPtr.Zero; PropVariantToStringAlloc(MarshalledPointer, out pStr).ThrowIfFailed(); object sResult = Marshal.PtrToStringAuto(pStr); Marshal.FreeCoTaskMem(pStr); return((T)sResult); } case TypeCode.Object: if (typeof(T) == typeof(Guid)) { try { if (IsVector && _propVar.VarType.HasFlag(VARENUM.VT_UI1)) { byte[] data = (byte[])Value; object result = new Guid(data); return((T)result); } if (IsString) { object result = new Guid((string)Value); return((T)result); } if (_propVar.VarType == VARENUM.VT_CLSID || _propVar.VarType == VARENUM.VT_RECORD) { return((T)Value); } } catch { } } throw new VariantTypeException($"Cannot convert PropVariant with {_propVar.VarType} To {typeof(T)}"); default: throw new VariantTypeException($"Cannot convert PropVariant with {_propVar.VarType} To {typeof(T)}"); } hr = PropVariantChangeType(propVar.MarshalledPointer, MarshalledPointer, 0, vt); if (hr.Failed) { throw new VariantTypeException($"Cannot convert PropVariant with {_propVar.VarType} To {typeof(T)}", hr.GetException()); } propVar.MarshalPointerToValue(); return((T)propVar.Value); } }
private static object?ToObject(VARENUM type, bool byRef, void *data) { switch (type) { case VARENUM.EMPTY: if (byRef) { // CLR returns VT_EMPTY | VT_BYREF data as nuint. if (IntPtr.Size == 8) { return((ulong)data); } return((uint)data); } return(null); case VARENUM.NULL: return(Convert.DBNull); case VARENUM.I1: return(*((sbyte *)data)); case VARENUM.UI1: return(*((byte *)data)); case VARENUM.I2: return(*((short *)data)); case VARENUM.UI2: return(*((ushort *)data)); case VARENUM.I4: case VARENUM.INT: case VARENUM.ERROR: case VARENUM.HRESULT: return(*((int *)data)); case VARENUM.UI4: case VARENUM.UINT: return(*((uint *)data)); case VARENUM.I8: return(*((long *)data)); case VARENUM.UI8: return(*((ulong *)data)); case VARENUM.R4: return(*((float *)data)); case VARENUM.R8: return(*((double *)data)); case VARENUM.CY: long cyVal = *((long *)data); return(decimal.FromOACurrency(cyVal)); case VARENUM.DATE: double date = *((double *)data); return(DateTime.FromOADate(date)); case VARENUM.BSTR: case VARENUM.LPWSTR: return(Marshal.PtrToStringUni(*(IntPtr *)data)); case VARENUM.LPSTR: return(Marshal.PtrToStringAnsi(*(IntPtr *)data)); case VARENUM.DISPATCH: case VARENUM.UNKNOWN: IntPtr pInterface = *(IntPtr *)data; if (pInterface == IntPtr.Zero) { return(null); } return(Marshal.GetObjectForIUnknown(pInterface)); case VARENUM.DECIMAL: return(((DECIMAL *)data)->ToDecimal()); case VARENUM.BOOL: return((*(VARIANT_BOOL *)data) != VARIANT_BOOL.FALSE); case VARENUM.VARIANT: // We only support VT_VARIANT | VT_BYREF. if (!byRef) { break; } // BYREF VARIANTS are not allowed to be nested. VARIANT *pVariant = (VARIANT *)data; if (pVariant->Byref) { throw new InvalidOleVariantTypeException(); } return(pVariant->ToObject()); case VARENUM.CLSID: // We only support VT_CLSID. // This is the type of InitPropVariantFromCLSID. if (byRef) { break; } return(**((Guid **)data)); case VARENUM.FILETIME: // We only support VT_FILETIME. // This is the type of InitPropVariantFromFILETIME. if (byRef) { break; } return((*(Kernel32.FILETIME *)data).ToDateTime()); case VARENUM.VOID: return(null); case VARENUM.RECORD: { VARIANTRecord *record = (VARIANTRecord *)data; if (record->pRecInfo == IntPtr.Zero) { throw new ArgumentException("Specified OLE variant is invalid."); } if (record->pvRecord is null) { return(null); } // TODO: cast IntPtr to IRecordInfo. Not that much of a concern // as .NET Core doesn't support records anyway. // Type recordType = GetRecordElementType(record->pvRecord); throw new ArgumentException("Record marshalling doesn't actually work in .NET Core. Matching that behaviour."); } } throw new ArgumentException(string.Format(SR.COM2UnhandledVT, type)); }
internal static Type VarEnumToSystemType(VARENUM varEnumType) { switch (varEnumType) { case (VARENUM.VT_EMPTY): case (VARENUM.VT_NULL): return(typeof(Object)); case (VARENUM.VT_UI1): return(typeof(Byte?)); case (VARENUM.VT_I2): return(typeof(Int16?)); case (VARENUM.VT_UI2): return(typeof(UInt16?)); case (VARENUM.VT_I4): return(typeof(Int32?)); case (VARENUM.VT_UI4): return(typeof(UInt32?)); case (VARENUM.VT_I8): return(typeof(Int64?)); case (VARENUM.VT_UI8): return(typeof(UInt64?)); case (VARENUM.VT_R8): return(typeof(Double?)); case (VARENUM.VT_BOOL): return(typeof(Boolean?)); case (VARENUM.VT_FILETIME): return(typeof(DateTime?)); case (VARENUM.VT_CLSID): return(typeof(IntPtr?)); case (VARENUM.VT_CF): return(typeof(IntPtr?)); case (VARENUM.VT_BLOB): return(typeof(Byte[])); case (VARENUM.VT_LPWSTR): return(typeof(String)); case (VARENUM.VT_UNKNOWN): return(typeof(IntPtr?)); case (VARENUM.VT_STREAM): return(typeof(IStream)); case (VARENUM.VT_VECTOR | VARENUM.VT_UI1): return(typeof(Byte[])); case (VARENUM.VT_VECTOR | VARENUM.VT_I2): return(typeof(Int16[])); case (VARENUM.VT_VECTOR | VARENUM.VT_UI2): return(typeof(UInt16[])); case (VARENUM.VT_VECTOR | VARENUM.VT_I4): return(typeof(Int32[])); case (VARENUM.VT_VECTOR | VARENUM.VT_UI4): return(typeof(UInt32[])); case (VARENUM.VT_VECTOR | VARENUM.VT_I8): return(typeof(Int64[])); case (VARENUM.VT_VECTOR | VARENUM.VT_UI8): return(typeof(UInt64[])); case (VARENUM.VT_VECTOR | VARENUM.VT_R8): return(typeof(Double[])); case (VARENUM.VT_VECTOR | VARENUM.VT_BOOL): return(typeof(Boolean[])); case (VARENUM.VT_VECTOR | VARENUM.VT_FILETIME): return(typeof(DateTime[])); case (VARENUM.VT_VECTOR | VARENUM.VT_CLSID): return(typeof(IntPtr[])); case (VARENUM.VT_VECTOR | VARENUM.VT_CF): return(typeof(IntPtr[])); case (VARENUM.VT_VECTOR | VARENUM.VT_LPWSTR): return(typeof(String[])); default: return(typeof(Object)); } }