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

Implement the ComVariant struct, the ComVariantMarshaller type, and generator integration #93635

Merged
merged 22 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
40d27a8
Add initial implementation of OleVariant struct.
jkoritzinsky Oct 12, 2023
2c574cd
Finish implementation of OleVariant, add unit tests, and use it in Co…
jkoritzinsky Oct 16, 2023
4ef3c25
Implement OleVariantMarshaller.
jkoritzinsky Oct 17, 2023
099a1a3
Implement generator integration. Instead of special-casing support fo…
jkoritzinsky Oct 17, 2023
b63a0b9
Add doc comments to new APIs
jkoritzinsky Oct 17, 2023
8472e60
Fix xplat OleVariant.Dispose()
jkoritzinsky Oct 18, 2023
62d329a
Rename OleVariant to ComVariant
jkoritzinsky Oct 19, 2023
8f8e897
Merge branch 'variant' of github.com:jkoritzinsky/runtime into variant
jkoritzinsky Oct 19, 2023
c7ee906
PR feedback
jkoritzinsky Oct 19, 2023
ba5cbfc
Add some negative tests for CreateRaw
jkoritzinsky Oct 20, 2023
7027779
Re-inline the variable decl.
jkoritzinsky Oct 20, 2023
e378fc6
PR feedback
jkoritzinsky Oct 20, 2023
b622870
Fix non-Windows build.
jkoritzinsky Oct 20, 2023
15f4a9b
Abstract out VARIANT_TRUE and VARIANT_FALSE to constants and fix the …
jkoritzinsky Oct 23, 2023
1d8c472
Fix build failure
jkoritzinsky Oct 24, 2023
1d3a54b
Skip ComWrappers in Variant tests on Mono.
jkoritzinsky Oct 24, 2023
3cbf995
Fix VT_BOOL handling in BuiltInVariantExtensions.
jkoritzinsky Oct 24, 2023
07228af
Allow a subtype of ArgumentException to be thrown in the Decimal case…
jkoritzinsky Oct 24, 2023
896da6c
Use ComVariant type in NativeAOT's known types
jkoritzinsky Oct 24, 2023
c13cd72
Make mutating extension method take ComVariant by ref.
jkoritzinsky Oct 24, 2023
bf95eea
Don't pass "T" for ThrowsAny
jkoritzinsky Oct 25, 2023
930e87c
Merge branch 'main' into variant
jkoritzinsky Oct 27, 2023
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 @@ -264,8 +264,8 @@
<Compile Include="$(CommonPath)System\Runtime\InteropServices\ComEventsSink.cs">
<Link>Common\System\Runtime\InteropServices\ComEventsSink.cs</Link>
</Compile>
<Compile Include="$(CommonPath)System\Runtime\InteropServices\Variant.cs">
<Link>Common\System\Runtime\InteropServices\Variant.cs</Link>
<Compile Include="$(CommonPath)System\Runtime\InteropServices\BuiltInVariantExtensions.cs">
<Link>Common\System\Runtime\InteropServices\BuiltInVariantExtensions.cs</Link>
</Compile>
<Compile Include="$(BclSourcesRoot)\Internal\Runtime\InteropServices\ComActivator.cs" />
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\OAVariantLib.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices.Marshalling;

namespace System.Runtime.InteropServices.CustomMarshalers
{
Expand All @@ -22,7 +23,7 @@ public EnumerableViewOfDispatch(object dispatch)

public Collections.IEnumerator GetEnumerator()
{
Variant result;
ComVariant result;
unsafe
{
void* resultLocal = &result;
Expand Down Expand Up @@ -54,7 +55,7 @@ public Collections.IEnumerator GetEnumerator()
}
finally
{
result.Clear();
result.Dispose();

if (enumVariantPtr != IntPtr.Zero)
Marshal.Release(enumVariantPtr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.InteropServices.ObjectiveC;
using System.Runtime.Loader;
using System.Text;
Expand Down Expand Up @@ -576,8 +577,8 @@ internal static unsafe void CleanupVariant(IntPtr pDstNativeVariant)
{
#if TARGET_WINDOWS
#pragma warning disable CA1416
Variant* data = (Variant*)pDstNativeVariant;
data->Clear();
ComVariant* data = (ComVariant*)pDstNativeVariant;
data->Dispose();
#pragma warning restore CA1416
#else
throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@
<ItemGroup Condition="'$(TargetsWindows)'=='true'">
<Compile Include="System\Runtime\InteropServices\NativeLibrary.NativeAot.Windows.cs" />
<Compile Include="System\Runtime\InteropServices\PInvokeMarshal.Windows.cs" />
<Compile Include="$(CommonPath)\System\Runtime\InteropServices\Variant.cs">
<Link>System\Runtime\InteropServices\Variant.cs</Link>
<Compile Include="$(CommonPath)\System\Runtime\InteropServices\BuiltInVariantExtensions.cs">
<Link>System\Runtime\InteropServices\BuiltInVariantExtensions.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.IsDebuggerPresent.cs">
<Link>Interop\Windows\Kernel32\Interop.IsDebuggerPresent.cs</Link>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.Versioning;

namespace System.Runtime.InteropServices
Expand Down Expand Up @@ -121,143 +122,143 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati
{
ArgumentNullException.ThrowIfNull(pDstNativeVariant);

Variant* data = (Variant*)pDstNativeVariant;
ComVariant* data = (ComVariant*)pDstNativeVariant;
if (obj == null)
{
data->VariantType = VarEnum.VT_EMPTY;
*data = default;
return;
}

switch (obj)
{
// Int and String most used types.
case int value:
data->AsI4 = value;
*data = ComVariant.Create(value);
break;
case string value:
data->AsBstr = value;
*data = ComVariant.Create(new BStrWrapper(value));
break;

case bool value:
data->AsBool = value;
*data = ComVariant.Create(value);
break;
case byte value:
data->AsUi1 = value;
*data = ComVariant.Create(value);
break;
case sbyte value:
data->AsI1 = value;
*data = ComVariant.Create(value);
break;
case short value:
data->AsI2 = value;
*data = ComVariant.Create(value);
break;
case ushort value:
data->AsUi2 = value;
*data = ComVariant.Create(value);
break;
case uint value:
data->AsUi4 = value;
*data = ComVariant.Create(value);
break;
case long value:
data->AsI8 = value;
*data = ComVariant.Create(value);
break;
case ulong value:
data->AsUi8 = value;
*data = ComVariant.Create(value);
break;
case float value:
data->AsR4 = value;
*data = ComVariant.Create(value);
break;
case double value:
data->AsR8 = value;
*data = ComVariant.Create(value);
break;
case DateTime value:
data->AsDate = value;
*data = ComVariant.Create(value);
break;
case decimal value:
data->AsDecimal = value;
*data = ComVariant.Create(value);
break;
case char value:
data->AsUi2 = value;
*data = ComVariant.Create(value);
break;
case BStrWrapper value:
data->AsBstr = value.WrappedObject;
*data = ComVariant.Create(value);
break;
#pragma warning disable 0618 // CurrencyWrapper is obsolete
case CurrencyWrapper value:
data->AsCy = value.WrappedObject;
*data = ComVariant.Create(value);
break;
#pragma warning restore 0618
case UnknownWrapper value:
data->AsUnknown = value.WrappedObject;
*data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value.WrappedObject));
break;
case DispatchWrapper value:
data->AsDispatch = value.WrappedObject;
*data = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, GetIDispatchForObject(value.WrappedObject));
break;
case ErrorWrapper value:
data->AsError = value.ErrorCode;
*data = ComVariant.Create(value);
break;
case VariantWrapper value:
throw new ArgumentException();
case DBNull value:
data->SetAsNULL();
*data = ComVariant.Null;
break;
case Missing value:
data->AsError = DISP_E_PARAMNOTFOUND;
*data = ComVariant.CreateRaw(VarEnum.VT_ERROR, DISP_E_PARAMNOTFOUND);
break;
case IConvertible value:
switch (value.GetTypeCode())
{
case TypeCode.Empty:
data->VariantType = VarEnum.VT_EMPTY;
*data = default;
break;
case TypeCode.Object:
data->AsUnknown = value;
*data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value));
break;
case TypeCode.DBNull:
data->SetAsNULL();
*data = ComVariant.Null;
break;
case TypeCode.Boolean:
data->AsBool = value.ToBoolean(null);
*data = ComVariant.Create(value.ToBoolean(null));
break;
case TypeCode.Char:
data->AsUi2 = value.ToChar(null);
*data = ComVariant.Create(value.ToChar(null));
break;
case TypeCode.SByte:
data->AsI1 = value.ToSByte(null);
*data = ComVariant.Create(value.ToSByte(null));
break;
case TypeCode.Byte:
data->AsUi1 = value.ToByte(null);
*data = ComVariant.Create(value.ToByte(null));
break;
case TypeCode.Int16:
data->AsI2 = value.ToInt16(null);
*data = ComVariant.Create(value.ToInt16(null));
break;
case TypeCode.UInt16:
data->AsUi2 = value.ToUInt16(null);
*data = ComVariant.Create(value.ToUInt16(null));
break;
case TypeCode.Int32:
data->AsI4 = value.ToInt32(null);
*data = ComVariant.Create(value.ToInt32(null));
break;
case TypeCode.UInt32:
data->AsUi4 = value.ToUInt32(null);
*data = ComVariant.Create(value.ToUInt32(null));
break;
case TypeCode.Int64:
data->AsI8 = value.ToInt64(null);
*data = ComVariant.Create(value.ToInt64(null));
break;
case TypeCode.UInt64:
data->AsUi8 = value.ToUInt64(null);
*data = ComVariant.Create(value.ToUInt64(null));
break;
case TypeCode.Single:
data->AsR4 = value.ToSingle(null);
*data = ComVariant.Create(value.ToSingle(null));
break;
case TypeCode.Double:
data->AsR8 = value.ToDouble(null);
*data = ComVariant.Create(value.ToDouble(null));
break;
case TypeCode.Decimal:
data->AsDecimal = value.ToDecimal(null);
*data = ComVariant.Create(value.ToDecimal(null));
break;
case TypeCode.DateTime:
data->AsDate = value.ToDateTime(null);
*data = ComVariant.Create(value.ToDateTime(null));
break;
case TypeCode.String:
data->AsBstr = value.ToString();
*data = ComVariant.Create(new BStrWrapper(value.ToString(null)));
break;
default:
throw new NotSupportedException();
Expand All @@ -273,7 +274,7 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati
case ValueType:
throw new NotSupportedException("VT_RECORD");
default:
data->AsDispatch = obj;
*data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIDispatchForObject(obj));
break;
}
}
Expand Down Expand Up @@ -303,38 +304,35 @@ public static object GetObjectForIUnknown(IntPtr pUnk)
{
ArgumentNullException.ThrowIfNull(pSrcNativeVariant);

Variant* data = (Variant*)pSrcNativeVariant;
ComVariant* data = (ComVariant*)pSrcNativeVariant;

if (data->IsEmpty)
{
return null;
}

switch (data->VariantType)
switch (data->VarType)
{
case VarEnum.VT_EMPTY:
return null;
case VarEnum.VT_NULL:
return DBNull.Value;

case VarEnum.VT_I1: return data->AsI1;
case VarEnum.VT_I2: return data->AsI2;
case VarEnum.VT_I4: return data->AsI4;
case VarEnum.VT_I8: return data->AsI8;
case VarEnum.VT_UI1: return data->AsUi1;
case VarEnum.VT_UI2: return data->AsUi2;
case VarEnum.VT_UI4: return data->AsUi4;
case VarEnum.VT_UI8: return data->AsUi8;
case VarEnum.VT_INT: return data->AsInt;
case VarEnum.VT_UINT: return data->AsUint;
case VarEnum.VT_BOOL: return data->AsBool;
case VarEnum.VT_ERROR: return data->AsError;
case VarEnum.VT_R4: return data->AsR4;
case VarEnum.VT_R8: return data->AsR8;
case VarEnum.VT_DECIMAL: return data->AsDecimal;
case VarEnum.VT_CY: return data->AsCy;
case VarEnum.VT_DATE: return data->AsDate;
case VarEnum.VT_BSTR: return data->AsBstr;
case VarEnum.VT_UNKNOWN: return data->AsUnknown;
case VarEnum.VT_DISPATCH: return data->AsDispatch;
case VarEnum.VT_I1: return data->As<sbyte>();
case VarEnum.VT_I2: return data->As<short>();
case VarEnum.VT_I4: return data->As<int>();
case VarEnum.VT_I8: return data->As<long>();
case VarEnum.VT_UI1: return data->As<byte>();
case VarEnum.VT_UI2: return data->As<ushort>();
case VarEnum.VT_UI4: return data->As<uint>();
case VarEnum.VT_UI8: return data->As<ulong>();
case VarEnum.VT_INT: return data->As<int>();
case VarEnum.VT_UINT: return data->As<uint>();
case VarEnum.VT_BOOL: return data->As<short>() != -1;
case VarEnum.VT_ERROR: return data->As<int>();
case VarEnum.VT_R4: return data->As<float>();
case VarEnum.VT_R8: return data->As<double>();
case VarEnum.VT_DECIMAL: return data->As<decimal>();
case VarEnum.VT_CY: return decimal.FromOACurrency(data->GetRawDataRef<long>());
case VarEnum.VT_DATE: return data->As<DateTime>();
case VarEnum.VT_BSTR: return PtrToStringBSTR(data->GetRawDataRef<nint>());
case VarEnum.VT_UNKNOWN: return GetObjectForIUnknown(data->GetRawDataRef<nint>());
case VarEnum.VT_DISPATCH: return GetObjectForIUnknown(data->GetRawDataRef<nint>());

default:
// Other VARIANT types not supported yet.
Expand Down
Loading
Loading