Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert OAVariant interop to managed #100176

Merged
merged 37 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
aa612d1
Convert BoxEnum to managed
huoyaoyuan Jun 8, 2022
a3dfc8e
Temp commit
huoyaoyuan Jun 8, 2022
6ceec59
SetFieldsObject to managed
huoyaoyuan Mar 23, 2024
5eb3f80
Color call
huoyaoyuan Mar 23, 2024
f82d6b6
Cleanup FCall
huoyaoyuan Mar 23, 2024
e8f3f1f
Handle decimal and other CV_OBJECT
huoyaoyuan Mar 23, 2024
88f9e55
Fix BoxEnum
huoyaoyuan Mar 25, 2024
4013082
Body of OAVariant_ChangeType
huoyaoyuan Mar 25, 2024
f12f8f6
Avoid converting through Variant in OAVariantLib
huoyaoyuan Mar 25, 2024
f2c96e2
Managed ToOAVariant and FromOAVariant
huoyaoyuan Mar 26, 2024
9787743
Marshal for IUnknown and IDispatch
huoyaoyuan Mar 26, 2024
2164865
Fullfill interop for OAVariant
huoyaoyuan Mar 26, 2024
aa963e0
VariantChangeTypeEx interop
huoyaoyuan Mar 26, 2024
568ba08
Complete GetObjectRefFromComIP
huoyaoyuan Mar 26, 2024
e6338a1
System.Color interop
huoyaoyuan Mar 26, 2024
6cda5f3
Use managed reflection for System.Drawing.Color conversion
huoyaoyuan Mar 27, 2024
80c9f56
Use MarshalNative for IDispatch/IUnknown marshalling
huoyaoyuan Mar 27, 2024
d4addb9
Fulfill behavior of ToOAVariant
huoyaoyuan Mar 27, 2024
d17d427
Delete unreachable special type handling
huoyaoyuan Mar 27, 2024
b4b86bb
Revert System.Drawing.Color reflection
huoyaoyuan Mar 27, 2024
756ad96
Revert changes around Variant
huoyaoyuan Mar 28, 2024
de55154
Move Color conversion to Variant
huoyaoyuan Mar 28, 2024
1cfc19b
Respect VTToCV mapping
huoyaoyuan Mar 28, 2024
539040c
Update src/coreclr/vm/marshalnative.cpp
huoyaoyuan Mar 28, 2024
f989fce
Update src/coreclr/classlibnative/bcltype/variant.cpp
huoyaoyuan Mar 29, 2024
3c61dd4
Merge branch 'main' into variant
huoyaoyuan May 5, 2024
434fff6
Cleanup impossible types and unused constants
huoyaoyuan May 5, 2024
24bada7
Fix HResult
huoyaoyuan May 5, 2024
9c1e96f
Use constants for HRESULT
huoyaoyuan May 6, 2024
578b028
Improve test type coverage
huoyaoyuan May 7, 2024
00a0a61
Remove more impossible types
huoyaoyuan May 7, 2024
4256710
Merge branch 'main' into variant
huoyaoyuan May 7, 2024
ca55c17
Apply suggestions from code review
huoyaoyuan May 8, 2024
9d79d19
Don't test for types that were not requested
huoyaoyuan May 8, 2024
4334c40
Fix compilation of NETServer
huoyaoyuan May 8, 2024
e4c4994
Test for values in ReturnToManaged
huoyaoyuan May 12, 2024
ae0b4f8
Add value test in managed arg
huoyaoyuan May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private static unsafe CorElementType InternalGetCorElementType(RuntimeType rt)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe CorElementType InternalGetCorElementType()
internal unsafe CorElementType InternalGetCorElementType()
{
CorElementType elementType = InternalGetCorElementType(RuntimeHelpers.GetMethodTable(this));
GC.KeepAlive(this);
Expand Down
158 changes: 149 additions & 9 deletions src/coreclr/System.Private.CoreLib/src/System/Variant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@

using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System
{
internal struct Variant
internal partial struct Variant
{
// Do Not change the order of these fields.
// They are mapped to the native VariantData * data structure.
Expand Down Expand Up @@ -60,6 +61,15 @@ internal struct Variant
internal const int CV_MISSING = 0x16;
internal const int CV_NULL = 0x17;
internal const int CV_LAST = 0x18;
internal const int EnumI1 = 0x100000;
internal const int EnumU1 = 0x200000;
internal const int EnumI2 = 0x300000;
internal const int EnumU2 = 0x400000;
internal const int EnumI4 = 0x500000;
internal const int EnumU4 = 0x600000;
internal const int EnumI8 = 0x700000;
internal const int EnumU8 = 0x800000;
internal const int EnumMask = 0xF00000;

internal const int TypeCodeBitMask = 0xffff;
internal const int VTBitMask = unchecked((int)0xff000000);
Expand All @@ -70,11 +80,137 @@ internal struct Variant
internal static Variant Missing => new Variant(CV_MISSING, Type.Missing, 0);
internal static Variant DBNull => new Variant(CV_NULL, System.DBNull.Value, 0);

//
// Native Methods
//
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern void SetFieldsObject(object val);
private static extern unsafe bool IsSystemDrawingColor(MethodTable* pMT);

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Variant_ConvertSystemColorToOleColor")]
private static partial uint ConvertSystemColorToOleColor(ObjectHandleOnStack obj);

internal unsafe void SetFieldsObject(object val)
{
MethodTable* pMT = RuntimeHelpers.GetMethodTable(val);

if (!pMT->IsValueType)
{
_objref = val;
if (val.GetType() == typeof(Missing))
{
_flags = CV_MISSING;
}
else if (val.GetType() == typeof(DBNull))
{
_flags = CV_NULL;
}
else if (val.GetType() == typeof(Empty))
{
_flags = CV_EMPTY;
_objref = null;
}
else
{
_flags = CV_OBJECT;
}
}
else if (IsSystemDrawingColor(pMT))
{
// System.Drawing.Color is converted to UInt32
object obj = val;
_data = ConvertSystemColorToOleColor(ObjectHandleOnStack.Create(ref obj));
_flags = CV_U4;
}
else
{
//If this is a primitive type, we need to unbox it, get the value and create a variant
//with just those values.

_objref = null;

//copy all of the data.
// Copies must be done based on the exact number of bytes to copy.
// We don't want to read garbage from other blocks of memory.
//CV_I8 --> CV_R8, CV_DATETIME, CV_TIMESPAN, & CV_CURRENCY are all of the 8 byte quantities
//If we don't find one of those ranges, we've found a value class
//of which we don't have inherent knowledge, so just slam that into an
//ObjectRef.
switch (val)
huoyaoyuan marked this conversation as resolved.
Show resolved Hide resolved
{
case byte u1:
this = new(u1);
break;
case sbyte i1:
this = new(i1);
break;
case bool boolean:
this = new(boolean);
break;
case short i2:
this = new(i2);
break;
case ushort u2:
this = new(u2);
break;
case char ch:
this = new(ch);
break;
case int i4:
this = new(i4);
break;
case uint u4:
this = new(u4);
break;
case float r4:
this = new(r4);
break;
// CV_DATETIME handled by caller
case TimeSpan ts:
_flags = CV_TIMESPAN;
_data = ts.Ticks;
break;
// CV_CURRENCY handled by caller
case long i8:
this = new(i8);
break;
case ulong u8:
this = new(u8);
break;
case double r8:
this = new(r8);
break;
case decimal d:
this = new(d);
break;
case Enum e:
_data = (long)Enum.ToUInt64(e);
_objref = e.GetType();
_flags = e.InternalGetCorElementType() switch
{
CorElementType.ELEMENT_TYPE_I1 => CV_ENUM | EnumI1,
CorElementType.ELEMENT_TYPE_U1 => CV_ENUM | EnumU1,
CorElementType.ELEMENT_TYPE_I2 => CV_ENUM | EnumI2,
CorElementType.ELEMENT_TYPE_U2 => CV_ENUM | EnumU2,
CorElementType.ELEMENT_TYPE_I4 => CV_ENUM | EnumI4,
CorElementType.ELEMENT_TYPE_U4 => CV_ENUM | EnumU4,
#if TARGET_64BIT
CorElementType.ELEMENT_TYPE_I => CV_ENUM | EnumI8,
CorElementType.ELEMENT_TYPE_U => CV_ENUM | EnumU8,
#else

CorElementType.ELEMENT_TYPE_I => CV_ENUM | EnumI4,
CorElementType.ELEMENT_TYPE_U => CV_ENUM | EnumU4,
#endif
CorElementType.ELEMENT_TYPE_I8 => CV_ENUM | EnumI8,
CorElementType.ELEMENT_TYPE_U8 => CV_ENUM | EnumU8,
_ => throw new InvalidOperationException(SR.InvalidOperation_UnknownEnumType)
};
break;
default:
// Other boxed value classes get handled here.
_objref = val;
_flags = CV_OBJECT;
break;
}
}
}

//
// Constructors
Expand Down Expand Up @@ -206,7 +342,7 @@ public Variant(object? obj)
return;
}

if (obj == null)
if (obj == null || obj is System.Empty)
{
this = Empty;
return;
Expand Down Expand Up @@ -303,9 +439,13 @@ public Variant(object? obj)
_ => _objref, // CV_DECIMAL, CV_STRING, CV_OBJECT
};

// This routine will return an boxed enum.
[MethodImpl(MethodImplOptions.InternalCall)]
private extern object BoxEnum();
private unsafe object BoxEnum()
{
Debug.Assert(_objref != null);
return RuntimeHelpers.Box(
RuntimeHelpers.GetMethodTable(_objref),
huoyaoyuan marked this conversation as resolved.
Show resolved Hide resolved
ref Unsafe.As<long, byte>(ref _data))!;
}

// Helper code for marshaling managed objects to VARIANT's (we use
// managed variants as an intermediate type.
Expand Down
Loading
Loading