diff --git a/src/System.Windows.Forms.Design/src/Resources/SR.resx b/src/System.Windows.Forms.Design/src/Resources/SR.resx
index eac5cc0aa9..1e5cd836f5 100644
--- a/src/System.Windows.Forms.Design/src/Resources/SR.resx
+++ b/src/System.Windows.Forms.Design/src/Resources/SR.resx
@@ -133,12 +133,6 @@
Read-Only
-
- Double cannot be converted to a date.
-
-
- Integer cannot be converted to a float.
-
Unhandled VT: {0}.
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.cs.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.cs.xlf
index f2984f56ce..6c71d78e97 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.cs.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.cs.xlf
@@ -406,16 +406,6 @@
Nezpracovaná hodnota VT: {0}.
-
-
- Nelze převést typ Double na typ Date.
-
-
-
-
- Nelze převést typ Integer na typ Float.
-
-
Výběr přiřazení
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.de.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.de.xlf
index 912855a523..c48b784ed9 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.de.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.de.xlf
@@ -406,16 +406,6 @@
Unbehandelter VT: {0}.
-
-
- "Double" kann nicht in "Date" konvertiert werden.
-
-
-
-
- "Integer" kann nicht in "Float" konvertiert werden.
-
-
Ausrichtungsauswahl
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.es.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.es.xlf
index cba42ab044..6f42ee1c61 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.es.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.es.xlf
@@ -406,16 +406,6 @@
VT no controlado: {0}.
-
-
- No se puede convertir double en date.
-
-
-
-
- No se puede convertir integer en float.
-
-
Selector de alineación
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.fr.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.fr.xlf
index 261f051244..4d0e524842 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.fr.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.fr.xlf
@@ -406,16 +406,6 @@
VT non géré : {0}.
-
-
- Impossible de convertir une valeur double en date.
-
-
-
-
- Impossible de convertir une valeur integer en float.
-
-
Sélecteur d'alignement
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.it.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.it.xlf
index 1716476468..5dfc120191 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.it.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.it.xlf
@@ -406,16 +406,6 @@
VT non gestito: {0}.
-
-
- Impossibile convertire un tipo double in un tipo date.
-
-
-
-
- Impossibile convertire un numero intero in un valore float.
-
-
Selezione allineamento
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ja.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ja.xlf
index 421aa4ff8f..f733326c05 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ja.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ja.xlf
@@ -406,16 +406,6 @@
ハンドルされていない VT: {0}
-
-
- double を date に変換できません。
-
-
-
-
- integer を float に変換できません。
-
-
配置ピッカー
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ko.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ko.xlf
index 5d3dc736ce..20d4603916 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ko.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ko.xlf
@@ -406,16 +406,6 @@
처리되지 않은 VT입니다. {0}
-
-
- double 형식을 date 형식으로 변환할 수 없습니다.
-
-
-
-
- integer 형식을 float 형식으로 변환할 수 없습니다.
-
-
맞춤 선택
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pl.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pl.xlf
index ac1608ca58..7e6c90957f 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pl.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pl.xlf
@@ -406,16 +406,6 @@
Nieobsługiwany VT: {0}.
-
-
- Nie można przekonwertować typu double na typ date.
-
-
-
-
- Nie można przekonwertować typu integer na typ float.
-
-
Selektor wyrównania
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pt-BR.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pt-BR.xlf
index 655e0cda24..aa04e91e8d 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pt-BR.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.pt-BR.xlf
@@ -406,16 +406,6 @@
VT não tratado: {0}.
-
-
- Não é possível converter duplo em data.
-
-
-
-
- Não é possível converter inteiro em flutuante.
-
-
Seletor de Alinhamento
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ru.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ru.xlf
index 2a1e47e3cb..c0c0b5b107 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ru.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.ru.xlf
@@ -406,16 +406,6 @@
Необработанный VT: {0}.
-
-
- Тип double нельзя привести к типу date.
-
-
-
-
- Тип integer нельзя привести к типу float.
-
-
Выбор выравнивания
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.tr.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.tr.xlf
index 3e257f5e0a..7b6a1ad098 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.tr.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.tr.xlf
@@ -406,16 +406,6 @@
İşlenmemiş VT: {0}.
-
-
- Double tarihe dönüştürülemez.
-
-
-
-
- Tam sayı kayan noktalıya dönüştürülemez.
-
-
Hizalama Seçici
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hans.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hans.xlf
index cb761b2ccc..c3a188e0d2 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hans.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hans.xlf
@@ -406,16 +406,6 @@
未处理的 VT: {0}。
-
-
- 无法将 double 转换为 date。
-
-
-
-
- 无法将 integer 转换为 float。
-
-
对齐方式选择器
diff --git a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hant.xlf b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hant.xlf
index 230df74512..14329a2561 100644
--- a/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hant.xlf
+++ b/src/System.Windows.Forms.Design/src/Resources/xlf/SR.zh-Hant.xlf
@@ -406,16 +406,6 @@
未處理的 VT: {0}。
-
-
- Double 無法轉換為 Date。
-
-
-
-
- Integer 無法轉換為 Float。
-
-
對齊選擇器
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Interop.HRESULT.cs b/src/System.Windows.Forms.Primitives/src/Interop/Interop.HRESULT.cs
index cc4ba9f8e3..6304d0579b 100644
--- a/src/System.Windows.Forms.Primitives/src/Interop/Interop.HRESULT.cs
+++ b/src/System.Windows.Forms.Primitives/src/Interop/Interop.HRESULT.cs
@@ -18,6 +18,7 @@ internal static partial class Interop
DISP_E_UNKNOWNNAME = unchecked((int)0x80020006),
DISP_E_EXCEPTION = unchecked((int)0x80020009),
DISP_E_UNKNOWNLCID = unchecked((int)0x8002000C),
+ DISP_E_DIVBYZERO = unchecked((int)0x80020012),
TYPE_E_BADMODULEKIND = unchecked((int)0x800288BD),
E_NOTIMPL = unchecked((int)0x80004001),
E_NOINTERFACE = unchecked((int)0x80004002),
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Interop.Libraries.cs b/src/System.Windows.Forms.Primitives/src/Interop/Interop.Libraries.cs
index 613380c753..150b5e5bec 100644
--- a/src/System.Windows.Forms.Primitives/src/Interop/Interop.Libraries.cs
+++ b/src/System.Windows.Forms.Primitives/src/Interop/Interop.Libraries.cs
@@ -17,6 +17,7 @@ internal static partial class Interop
public const string Oleacc = "oleacc.dll";
public const string Oleaut32 = "oleaut32.dll";
public const string Powrprof = "Powrprof.dll";
+ public const string Propsys = "Propsys.dll";
public const string RichEdit41 = "MsftEdit.DLL";
public const string SHCore = "SHCore.dll";
public const string Shell32 = "shell32.dll";
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FILETIME.cs b/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FILETIME.cs
new file mode 100644
index 0000000000..4ae3bb7761
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/Kernel32/Interop.FILETIME.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+internal static partial class Interop
+{
+ internal static partial class Kernel32
+ {
+ public struct FILETIME
+ {
+ public FILETIME(DateTime date)
+ {
+ long ft = date.ToFileTime();
+ dwLowDateTime = (uint)(ft & 0xFFFFFFFF);
+ dwHighDateTime = (uint)(ft >> 32);
+ }
+
+ public uint dwLowDateTime;
+ public uint dwHighDateTime;
+
+ public DateTime ToDateTime()
+ {
+ return DateTime.FromFileTime(((long)dwHighDateTime << 32) + dwLowDateTime);
+ }
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.PropVariantClear.cs b/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.PropVariantClear.cs
new file mode 100644
index 0000000000..c42718172c
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.PropVariantClear.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using static Interop.Oleaut32;
+
+internal partial class Interop
+{
+ internal static partial class Ole32
+ {
+ [DllImport(Libraries.Ole32, ExactSpelling = true)]
+ public unsafe static extern HRESULT PropVariantClear(VARIANT* pvarg);
+
+ public unsafe static HRESULT PropVariantClear(ref VARIANT varg)
+ {
+ fixed (VARIANT* pvarg = &varg)
+ {
+ return PropVariantClear(pvarg);
+ }
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.DECIMAL.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.DECIMAL.cs
new file mode 100644
index 0000000000..40beacebd5
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.DECIMAL.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal static partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ public struct DECIMAL
+ {
+ public ushort wReserved;
+ public byte scale;
+ public byte sign;
+ public uint Hi32;
+ public uint Lo32;
+ public uint Mid32;
+
+ public decimal ToDecimal()
+ {
+ return new decimal((int)Lo32, (int)Mid32, (int)Hi32, sign == 0x80, scale);
+ }
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.FADF.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.FADF.cs
new file mode 100644
index 0000000000..1545b9a5e3
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.FADF.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+internal partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ [Flags]
+ public enum FADF : ushort
+ {
+ AUTO = 0x0001,
+ STATIC = 0x0002,
+ EMBEDDED = 0x0004,
+ FIXEDSIZE = 0x0010,
+ RECORD = 0x0020,
+ HAVEIID = 0x0040,
+ HAVEVARTYPE = 0x0080,
+ BSTR = 0x0100,
+ UNKNOWN = 0x0200,
+ DISPATCH = 0x0400,
+ VARIANT = 0x0800
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IPerPropertyBrowsing.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IPerPropertyBrowsing.cs
index 514deb8cab..ae6efe1885 100644
--- a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IPerPropertyBrowsing.cs
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IPerPropertyBrowsing.cs
@@ -28,8 +28,8 @@ internal partial class Interop
[PreserveSig]
HRESULT GetPredefinedStrings(
DispatchID dispID,
- CA* pCaStringsOut,
- CA* pCaCookiesOut);
+ Ole32.CA* pCaStringsOut,
+ Ole32.CA* pCaCookiesOut);
[PreserveSig]
HRESULT GetPredefinedValue(
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IRecordInfo.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IRecordInfo.cs
new file mode 100644
index 0000000000..18793dab51
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IRecordInfo.cs
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ [ComImport]
+ [Guid("0000002F-0000-0000-C000-000000000046")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public unsafe interface IRecordInfo
+ {
+ [PreserveSig]
+ HRESULT RecordInit(
+ void* pvNew);
+
+ [PreserveSig]
+ HRESULT RecordClear(
+ void* pvExisting);
+
+ [PreserveSig]
+ HRESULT RecordCopy(
+ void* pvExisting,
+ void* pvNew);
+
+ [PreserveSig]
+ HRESULT GetGuid(
+ Guid* pguid);
+
+ [PreserveSig]
+ HRESULT GetName(
+ BSTR* pbstrName);
+
+ [PreserveSig]
+ HRESULT GetSize(
+ uint* pcbSize);
+
+ [PreserveSig]
+ HRESULT GetTypeInfo(
+ out ITypeInfo ppTypeInfo);
+
+ [PreserveSig]
+ HRESULT GetField(
+ void* pvData,
+ [MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
+ VARIANT* pvarField);
+
+ [PreserveSig]
+ HRESULT GetFieldNoCopy(
+ void* pvData,
+ [MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
+ VARIANT* pvarField,
+ void* ppvDataCArray);
+
+ [PreserveSig]
+ HRESULT PutField(
+ Ole32.INVOKEKIND wFlags,
+ void* pvData,
+ [MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
+ VARIANT* pvarField);
+
+ [PreserveSig]
+ HRESULT PutFieldNoCopy(
+ Ole32.INVOKEKIND wFlags,
+ void* pvData,
+ [MarshalAs(UnmanagedType.LPWStr)] out string szFieldName,
+ VARIANT* pvarField);
+
+ [PreserveSig]
+ HRESULT GetFieldNames(
+ uint* pcNames,
+ BSTR* rgBstrNames);
+
+ [PreserveSig]
+ BOOL IsMatchingType(
+ ref IRecordInfo pRecordInfo);
+
+ [PreserveSig]
+ void* RecordCreate();
+
+ [PreserveSig]
+ HRESULT RecordCreateCopy(
+ void* pvSource,
+ void** ppvDest);
+
+ [PreserveSig]
+ HRESULT RecordDestroy(
+ void* pvRecord);
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SAFEARRAY.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SAFEARRAY.cs
new file mode 100644
index 0000000000..a48236974b
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SAFEARRAY.cs
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using static Interop.Ole32;
+
+internal partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ public unsafe struct SAFEARRAY
+ {
+ public ushort cDims;
+ public FADF fFeatures;
+ public uint cbElements;
+ public uint cLocks;
+ public void* pvData;
+ public SAFEARRAYBOUND _rgsabound;
+
+ public ReadOnlySpan rgsabound => TrailingArray.GetBuffer(ref _rgsabound, cDims);
+
+ public VARENUM VarType
+ {
+ get
+ {
+ // Match CLR behaviour.
+ FADF hardwiredType = fFeatures & (FADF.BSTR | FADF.UNKNOWN | FADF.DISPATCH | FADF.VARIANT);
+ if (hardwiredType == FADF.BSTR && cbElements == sizeof(char*))
+ {
+ return VARENUM.BSTR;
+ }
+ else if (hardwiredType == FADF.UNKNOWN && cbElements == sizeof(IntPtr))
+ {
+ return VARENUM.UNKNOWN;
+ }
+ else if (hardwiredType == FADF.DISPATCH && cbElements == sizeof(IntPtr))
+ {
+ return VARENUM.DISPATCH;
+ }
+ else if (hardwiredType == FADF.VARIANT && cbElements == sizeof(VARIANT))
+ {
+ return VARENUM.VARIANT;
+ }
+
+ // Call native API.
+ VARENUM vt = VARENUM.EMPTY;
+ fixed (SAFEARRAY* pThis = &this)
+ {
+ SafeArrayGetVartype(pThis, &vt);
+ return vt;
+ }
+ }
+ }
+
+ public T GetValue(Span indices)
+ {
+ // SAFEARRAY is laid out in column-major order.
+ // See https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/array-manipulation-functions
+ int indicesIndex = 0;
+ int c1 = indices[indicesIndex++];
+ uint dimensionSize = 1;
+
+ ReadOnlySpan bounds = rgsabound;
+ int boundIndex = cDims - 1;
+
+ uint cell = 0;
+ for (ushort dim = 1; dim < cDims; dim++)
+ {
+ dimensionSize *= bounds[boundIndex--].cElements;
+
+ int diff = (indices[indicesIndex++] - bounds[boundIndex].lLbound);
+ cell += (uint)diff * dimensionSize;
+ }
+
+ cell += (uint)(c1 - bounds[cDims - 1].lLbound);
+
+ void* v = Unsafe.Add(pvData, (int)cell);
+ return Unsafe.AsRef(v);
+ }
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SAFEARRAYBOUND.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SAFEARRAYBOUND.cs
new file mode 100644
index 0000000000..ee2e26fd20
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SAFEARRAYBOUND.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ public struct SAFEARRAYBOUND
+ {
+ public uint cElements;
+ public int lLbound;
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetElemsize.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetElemsize.cs
new file mode 100644
index 0000000000..94137b95de
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetElemsize.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ public unsafe static extern uint SafeArrayGetElemsize(SAFEARRAY* psa);
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetRecordInfo.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetRecordInfo.cs
new file mode 100644
index 0000000000..6a3b4cef58
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetRecordInfo.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ public unsafe static extern HRESULT SafeArrayGetRecordInfo(SAFEARRAY* psa, out IRecordInfo pRecInfo);
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetVartype.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetVartype.cs
new file mode 100644
index 0000000000..4c86455b19
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayGetVartype.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ public unsafe static extern HRESULT SafeArrayGetVartype(SAFEARRAY* psa, Ole32.VARENUM* pvt);
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VariantClear.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayLock.cs
similarity index 70%
rename from src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VariantClear.cs
rename to src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayLock.cs
index 43f8aa2199..5123ec48c2 100644
--- a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VariantClear.cs
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayLock.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -10,6 +10,6 @@ internal partial class Interop
internal static partial class Oleaut32
{
[DllImport(Libraries.Oleaut32, ExactSpelling = true)]
- public unsafe static extern HRESULT VariantClear(VARIANT* pvarg);
+ public unsafe static extern HRESULT SafeArrayLock(SAFEARRAY* psa);
}
}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayUnlock.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayUnlock.cs
new file mode 100644
index 0000000000..470e198fce
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.SafeArrayUnlock.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal static partial class Oleaut32
+ {
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ public unsafe static extern HRESULT SafeArrayUnlock(SAFEARRAY* psa);
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VARIANT.cs b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VARIANT.cs
index 14f748c1fe..b30e4e60d6 100644
--- a/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VARIANT.cs
+++ b/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.VARIANT.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms.Primitives.Resources;
using static Interop.Ole32;
@@ -22,10 +24,7 @@ internal static partial class Interop
public short reserved1;
public short reserved2;
public short reserved3;
-
- public IntPtr data1;
-
- public IntPtr data2;
+ public VARIANTUnion data;
public VARENUM Type => (vt & VARENUM.TYPEMASK);
@@ -33,177 +32,960 @@ internal static partial class Interop
public void Clear()
{
- fixed (VARIANT* pThis = &this)
- {
- VariantClear(pThis);
- }
-
+ PropVariantClear(ref this);
vt = VARENUM.EMPTY;
- data1 = IntPtr.Zero;
- data2 = IntPtr.Zero;
+ data = new VARIANTUnion();
}
public void Dispose() => Clear();
public object? ToObject()
{
- IntPtr val = data1;
- long longVal;
+ fixed (VARIANT* thisVariant = &this)
+ {
+ void* data = &thisVariant->data;
+ if (Byref)
+ {
+ data = *((void**)data);
+ // CLR allows VT_EMPTY/NULL | VT_BYREF to have no data.
+ // In other cases, the variant is invalid.
+ if (data == null && !(Type == VARENUM.EMPTY || Type == VARENUM.NULL))
+ {
+ throw new ArgumentException("Invalid Variant");
+ }
+ }
+ else if (vt == VARENUM.DECIMAL)
+ {
+ data = thisVariant;
+ }
- switch (Type)
+ // Note that the following check also covers VT_ILLEGAL.
+ if ((vt & ~(VARENUM.BYREF | VARENUM.ARRAY | VARENUM.VECTOR)) >= (VARENUM)0x80)
+ {
+ throw new InvalidOleVariantTypeException();
+ }
+
+ if ((vt & VARENUM.VECTOR) != 0)
+ {
+ return ToVector(thisVariant->data.ca, vt);
+ }
+ if ((vt & VARENUM.ARRAY) != 0)
+ {
+ return ToArray(*(SAFEARRAY**)data, vt);
+ }
+
+ return ToObject(Type, Byref, data);
+ }
+ }
+
+ 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:
- if (Byref)
- {
- val = (IntPtr)Marshal.ReadByte(val);
- }
- return (sbyte)(0xFF & (sbyte)val);
-
+ return *((sbyte*)data);
case VARENUM.UI1:
- if (Byref)
- {
- val = (IntPtr)Marshal.ReadByte(val);
- }
-
- return (byte)(0xFF & (byte)val);
-
+ return *((byte*)data);
case VARENUM.I2:
- if (Byref)
- {
- val = (IntPtr)Marshal.ReadInt16(val);
- }
- return (short)(0xFFFF & (short)val);
-
+ return *((short*)data);
case VARENUM.UI2:
- if (Byref)
- {
- val = (IntPtr)Marshal.ReadInt16(val);
- }
- return (ushort)(0xFFFF & (ushort)val);
-
+ return *((ushort*)data);
case VARENUM.I4:
case VARENUM.INT:
- if (Byref)
- {
- val = (IntPtr)Marshal.ReadInt32(val);
- }
- return (int)val;
-
+ case VARENUM.ERROR:
+ case VARENUM.HRESULT:
+ return *((int*)data);
case VARENUM.UI4:
case VARENUM.UINT:
- if (Byref)
- {
- val = (IntPtr)Marshal.ReadInt32(val);
- }
- return (uint)val;
-
+ return *((uint*)data);
case VARENUM.I8:
+ return *((long*)data);
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 (Type)
- {
+ return *((ulong*)data);
case VARENUM.R4:
+ return *((float*)data);
case VARENUM.R8:
-
- // can I use unsafe here?
- throw new FormatException(SR.CannotConvertIntToFloat);
-
+ return *((double*)data);
case VARENUM.CY:
- // internally currency is 8-byte int scaled by 10,000
- longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32);
- return new decimal(longVal);
+ long cyVal = *((long*)data);
+ return decimal.FromOACurrency(cyVal);
case VARENUM.DATE:
- throw new FormatException(SR.CannotConvertDoubleToDate);
-
+ double date = *((double*)data);
+ return DateTime.FromOADate(date);
case VARENUM.BSTR:
case VARENUM.LPWSTR:
- return Marshal.PtrToStringUni(val);
-
+ return Marshal.PtrToStringUni(*(IntPtr*)data);
case VARENUM.LPSTR:
- return Marshal.PtrToStringAnsi(val);
-
+ return Marshal.PtrToStringAnsi(*(IntPtr*)data);
case VARENUM.DISPATCH:
case VARENUM.UNKNOWN:
+ IntPtr pInterface = *(IntPtr*)data;
+ if (pInterface == IntPtr.Zero)
{
- return Marshal.GetObjectForIUnknown(val);
+ return null;
}
- case VARENUM.HRESULT:
- return val;
-
+ return Marshal.GetObjectForIUnknown(pInterface);
case VARENUM.DECIMAL:
- longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32);
- return new decimal(longVal);
-
+ return ((DECIMAL*)data)->ToDecimal();
case VARENUM.BOOL:
- return (val != IntPtr.Zero);
-
+ return (*(VARIANT_BOOL*)data) != VARIANT_BOOL.FALSE;
case VARENUM.VARIANT:
- VARIANT* pVariant = (VARIANT*)val;
+ // 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:
- Guid guid = Marshal.PtrToStructure(val);
- return guid;
+ // We only support VT_CLSID.
+ // This is the type of InitPropVariantFromCLSID.
+ if (byRef)
+ {
+ break;
+ }
+ return **((Guid**)data);
case VARENUM.FILETIME:
- longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32);
- return new DateTime(longVal);
+ // We only support VT_FILETIME.
+ // This is the type of InitPropVariantFromFILETIME.
+ if (byRef)
+ {
+ break;
+ }
- case VARENUM.USERDEFINED:
- throw new ArgumentException(string.Format(SR.COM2UnhandledVT, "USERDEFINED"));
-
- case VARENUM.ARRAY:
+ return (*(Kernel32.FILETIME*)data).ToDateTime();
case VARENUM.VOID:
- case VARENUM.PTR:
- case VARENUM.SAFEARRAY:
- case VARENUM.CARRAY:
-
+ return null;
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:
+ {
+ VARIANTRecord* record = (VARIANTRecord*)data;
+ if (record->pRecInfo == IntPtr.Zero)
+ {
+ throw new ArgumentException("Specified OLE variant is invalid.");
+ }
+ if (record->pvRecord == 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));
+ }
+
+ private static Type GetRecordElementType(IRecordInfo record)
+ {
+ Guid guid;
+ HRESULT hr = record.GetGuid(&guid);
+ if (!hr.Succeeded())
+ {
+ throw Marshal.GetExceptionForHR((int)hr)!;
+ }
+
+ Type? t = System.Type.GetTypeFromCLSID(guid);
+ if (t == null || !t.IsValueType)
+ {
+ throw new ArgumentException("The specified record cannot be mapped to a managed value class.");
+ }
+
+ return t;
+ }
+
+ private static object? ToArray(SAFEARRAY* psa, VARENUM vt)
+ {
+ if (psa == 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(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.UI1:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.I2:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.UI2:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.I4:
+ case VARENUM.INT:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.UI4:
+ case VARENUM.UINT:
+ case VARENUM.ERROR: // Not explicitly mentioned in the docs but trivial to implement.
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.I8:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.UI8:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.R4:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.R8:
+ new Span(psa->pvData, array.Length)
+ .CopyTo(GetSpan(array));
+ break;
+ case VARENUM.BOOL:
+ {
+ var data = new Span(psa->pvData, array.Length);
+ var result = GetSpan(array);
+ for (int i = 0; i < data.Length; i++)
+ {
+ result[i] = data[i] != VARIANT_BOOL.FALSE;
+ }
+ break;
+ }
+ case VARENUM.DECIMAL:
+ {
+ var data = new Span(psa->pvData, array.Length);
+ var result = GetSpan(array);
+ for (int i = 0; i < data.Length; i++)
+ {
+ result[i] = data[i].ToDecimal();
+ }
+ break;
+ }
+ case VARENUM.CY:
+ {
+ var data = new Span(psa->pvData, array.Length);
+ var result = GetSpan(array);
+ for (int i = 0; i < data.Length; i++)
+ {
+ result[i] = decimal.FromOACurrency(data[i]);
+ }
+ break;
+ }
+ case VARENUM.DATE:
+ {
+ var data = new Span(psa->pvData, array.Length);
+ var result = GetSpan(array);
+ for (int i = 0; i < data.Length; i++)
+ {
+ result[i] = DateTime.FromOADate(data[i]);
+ }
+ break;
+ }
+ case VARENUM.BSTR:
+ {
+ var data = new Span(psa->pvData, array.Length);
+ var result = GetSpan(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(psa->pvData, array.Length);
+ var result = GetSpan
-
-
- Nelze převést typ Double na typ Date.
-
-
-
-
- Nelze převést typ Integer na typ Float.
-
-
Nejméně jedna položka není platná v parametru IDictionary. Ověřte, zda všechny hodnoty odpovídají vlastnostem objektu.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.de.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.de.xlf
index a35ff04ee2..efb807cdad 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.de.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.de.xlf
@@ -7,16 +7,6 @@
Unbehandelter VT: {0}.
-
-
- "Double" kann nicht in "Date" konvertiert werden.
-
-
-
-
- "Integer" kann nicht in "Float" konvertiert werden.
-
-
Mindestens ein Eintrag im IDictionary-Parameter ist ungültig. Stellen Sie sicher, dass alle Werte den Eigenschaften des Objekts entsprechen.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.es.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.es.xlf
index 320092e759..cfabfcbdf5 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.es.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.es.xlf
@@ -7,16 +7,6 @@
VT no controlado: {0}.
-
-
- No se puede convertir double en date.
-
-
-
-
- No se puede convertir integer en float.
-
-
Una o más entradas no son válidas en el parámetro IDictionary. Compruebe que todos los valores coinciden con las propiedades del objeto.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.fr.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.fr.xlf
index ce45ccc99b..f63e6f37f1 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.fr.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.fr.xlf
@@ -7,16 +7,6 @@
VT non géré : {0}.
-
-
- Impossible de convertir une valeur double en date.
-
-
-
-
- Impossible de convertir une valeur integer en float.
-
-
Le paramètre IDictionary contient au moins une entrée non valide. Vérifiez que toutes les valeurs correspondent aux propriétés de l'objet.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.it.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.it.xlf
index 490cacf84f..bf41e36ee8 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.it.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.it.xlf
@@ -7,16 +7,6 @@
VT non gestito: {0}.
-
-
- Impossibile convertire un tipo double in un tipo date.
-
-
-
-
- Impossibile convertire un numero intero in un valore float.
-
-
Una o più voci non valide nel parametro IDictionary. Verificare che tutti i valori corrispondano alle proprietà dell'oggetto.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ja.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ja.xlf
index 0850740290..fa20df62c0 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ja.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ja.xlf
@@ -7,16 +7,6 @@
ハンドルされていない VT: {0}
-
-
- double を date に変換できません。
-
-
-
-
- integer を float に変換できません。
-
-
1 つ以上の有効ではないエントリが IDictionary パラメーターにあります。すべての値がオブジェクトのプロパティに一致していることを確認してください。
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ko.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ko.xlf
index 9efbafb79a..b97b2c9653 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ko.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ko.xlf
@@ -7,16 +7,6 @@
처리되지 않은 VT입니다. {0}
-
-
- double 형식을 date 형식으로 변환할 수 없습니다.
-
-
-
-
- integer 형식을 float 형식으로 변환할 수 없습니다.
-
-
IDictionary 매개 변수에 잘못된 항목이 하나 이상 있습니다. 모든 값이 개체의 속성과 일치하는지 확인하십시오.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pl.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pl.xlf
index 29fc0e457b..59d141aef1 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pl.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pl.xlf
@@ -7,16 +7,6 @@
Nieobsługiwany VT: {0}.
-
-
- Nie można przekonwertować typu double na typ date.
-
-
-
-
- Nie można przekonwertować typu integer na typ float.
-
-
Jeden lub kilka wpisów jest nieprawidłowych w parametrze IDictionary. Sprawdź, czy wszystkie wartości pasują do właściwości obiektu.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pt-BR.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pt-BR.xlf
index 24ba52ecd9..4d9c16d9fe 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pt-BR.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.pt-BR.xlf
@@ -7,16 +7,6 @@
VT não tratado: {0}.
-
-
- Não é possível converter duplo em data.
-
-
-
-
- Não é possível converter inteiro em flutuante.
-
-
Uma ou mais entradas não são válidas no parâmetro IDictionary. Verifique se todos os valores correspondem às propriedades do objeto.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ru.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ru.xlf
index 4c27386b68..ff6937a2ec 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ru.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.ru.xlf
@@ -7,16 +7,6 @@
Необработанный VT: {0}.
-
-
- Тип double нельзя привести к типу date.
-
-
-
-
- Тип integer нельзя привести к типу float.
-
-
Недействительны одна или больше записей в параметре IDictionary. Проверьте, все ли значения соответствуют свойствам этого объекта.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.tr.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.tr.xlf
index 8a8e90b2f8..81bcf3c1f0 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.tr.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.tr.xlf
@@ -7,16 +7,6 @@
İşlenmemiş VT: {0}.
-
-
- Double tarihe dönüştürülemez.
-
-
-
-
- Tam sayı kayan noktalıya dönüştürülemez.
-
-
IDictionary parametresindeki bir veya daha fazla girdi geçerli değil. Tüm değerlerin nesnenin özellikleriyle eşleştiğini doğrulayın.
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hans.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hans.xlf
index 780c4c0ff9..81f74cff1c 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hans.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hans.xlf
@@ -7,16 +7,6 @@
未处理的 VT: {0}。
-
-
- 无法将 double 转换为 date。
-
-
-
-
- 无法将 integer 转换为 float。
-
-
在 IDictionary 参数中有一个或多个无效项。请验证所有值均与对象的属性匹配。
diff --git a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hant.xlf b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hant.xlf
index 686780ca8e..50bf38889c 100644
--- a/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hant.xlf
+++ b/src/System.Windows.Forms.Primitives/src/Resources/xlf/SR.zh-Hant.xlf
@@ -7,16 +7,6 @@
未處理的 VT: {0}。
-
-
- Double 無法轉換為 Date。
-
-
-
-
- Integer 無法轉換為 Float。
-
-
IDictionary 參數中有一或多個無效的項目。請確認所有值都符合物件的屬性。
diff --git a/src/System.Windows.Forms.Primitives/tests/Interop/Oleaut32/VARIANTTests.cs b/src/System.Windows.Forms.Primitives/tests/Interop/Oleaut32/VARIANTTests.cs
deleted file mode 100644
index abf73f645c..0000000000
--- a/src/System.Windows.Forms.Primitives/tests/Interop/Oleaut32/VARIANTTests.cs
+++ /dev/null
@@ -1,168 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using Xunit;
-using static Interop;
-using static Interop.Kernel32;
-using static Interop.Ole32;
-using static Interop.Oleaut32;
-
-namespace System.Windows.Forms.Tests.Interop.Oleaut32
-{
- public unsafe class VARIANTTests : IClassFixture
- {
- [ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is32bit))]
- public void VARIANT_Sizeof_InvokeX86_ReturnsExpected()
- {
- Assert.Equal(16, Marshal.SizeOf());
- Assert.Equal(16, sizeof(VARIANT));
- }
-
- [ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is64bit))]
- public void VARIANT_Sizeof_InvokeX64_ReturnsExpected()
- {
- Assert.Equal(24, Marshal.SizeOf());
- Assert.Equal(24, sizeof(VARIANT));
- }
-
- [WinFormsTheory]
- [InlineData((ushort)VARENUM.EMPTY, false)]
- [InlineData((ushort)VARENUM.BOOL, false)]
- [InlineData((ushort)(VARENUM.BYREF), true)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF), true)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF | VARENUM.ARRAY), true)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF | VARENUM.VECTOR), true)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.ARRAY), false)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.VECTOR), false)]
- public void VARIANT_Byref_Get_ReturnsExpected(ushort vt, bool expected)
- {
- using var variant = new VARIANT
- {
- vt = (VARENUM)vt
- };
- Assert.Equal(expected, variant.Byref);
- }
-
- [WinFormsTheory]
- [InlineData((ushort)VARENUM.EMPTY, (ushort)VARENUM.EMPTY)]
- [InlineData((ushort)VARENUM.BOOL, (ushort)VARENUM.BOOL)]
- [InlineData((ushort)(VARENUM.BYREF), (ushort)VARENUM.EMPTY)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF), (ushort)VARENUM.BOOL)]
- public void VARIANT_Type_Get_ReturnsExpected(ushort vt, ushort expected)
- {
- using var variant = new VARIANT
- {
- vt = (VARENUM)vt
- };
- Assert.Equal((VARENUM)expected, variant.Type);
- }
-
- [WinFormsTheory]
- [InlineData((ushort)VARENUM.EMPTY)]
- [InlineData((ushort)(VARENUM.EMPTY | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.UNKNOWN)]
- [InlineData((ushort)(VARENUM.UNKNOWN | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.DISPATCH)]
- [InlineData((ushort)(VARENUM.DISPATCH | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.BSTR)]
- [InlineData((ushort)(VARENUM.BSTR | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.BOOL)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF))]
- public void VARIANT_Clear_InvokeDefault_Success(ushort vt)
- {
- using var variant = new VARIANT
- {
- vt = (VARENUM)vt
- };
- variant.Clear();
- Assert.Equal(VARENUM.EMPTY, variant.vt);
- Assert.Equal(IntPtr.Zero, variant.data1);
- Assert.Equal(IntPtr.Zero, variant.data2);
- }
-
- [WinFormsFact]
- public void VARIANT_Clear_InvokeCustom_Success()
- {
- using var variant = new VARIANT
- {
- vt = VARENUM.BOOL,
- data1 = (IntPtr)1
- };
- variant.Clear();
- Assert.Equal(VARENUM.EMPTY, variant.vt);
- Assert.Equal(IntPtr.Zero, variant.data1);
- Assert.Equal(IntPtr.Zero, variant.data2);
- }
-
- [WinFormsFact]
- public void VARIANT_Clear_InvokeBSTR_Success()
- {
- IntPtr data = Marshal.StringToBSTR("abc");
- using var variant = new VARIANT
- {
- vt = VARENUM.BSTR,
- data1 = data
- };
- variant.Clear();
- Assert.Equal(VARENUM.EMPTY, variant.vt);
- Assert.Equal(IntPtr.Zero, variant.data1);
- Assert.Equal(IntPtr.Zero, variant.data2);
- }
-
- [WinFormsTheory]
- [InlineData((ushort)VARENUM.EMPTY)]
- [InlineData((ushort)(VARENUM.EMPTY | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.UNKNOWN)]
- [InlineData((ushort)(VARENUM.UNKNOWN | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.DISPATCH)]
- [InlineData((ushort)(VARENUM.DISPATCH | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.BSTR)]
- [InlineData((ushort)(VARENUM.BSTR | VARENUM.BYREF))]
- [InlineData((ushort)VARENUM.BOOL)]
- [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF))]
- public void VARIANT_Dispose_InvokeDefault_Success(ushort vt)
- {
- using var variant = new VARIANT
- {
- vt = (VARENUM)vt
- };
- variant.Dispose();
- Assert.Equal(VARENUM.EMPTY, variant.vt);
- Assert.Equal(IntPtr.Zero, variant.data1);
- Assert.Equal(IntPtr.Zero, variant.data2);
- }
-
- [WinFormsFact]
- public void VARIANT_Dispose_InvokeCustom_Success()
- {
- using var variant = new VARIANT
- {
- vt = VARENUM.BOOL,
- data1 = (IntPtr)1
- };
- variant.Dispose();
- Assert.Equal(VARENUM.EMPTY, variant.vt);
- Assert.Equal(IntPtr.Zero, variant.data1);
- Assert.Equal(IntPtr.Zero, variant.data2);
- }
-
- [WinFormsFact]
- public void VARIANT_Dispose_InvokeBSTR_Success()
- {
- IntPtr data = Marshal.StringToBSTR("abc");
- using var variant = new VARIANT
- {
- vt = VARENUM.BSTR,
- data1 = data
- };
- variant.Dispose();
- Assert.Equal(VARENUM.EMPTY, variant.vt);
- Assert.Equal(IntPtr.Zero, variant.data1);
- Assert.Equal(IntPtr.Zero, variant.data2);
- }
- }
-}
diff --git a/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Kernel32/FILETIMETests.cs b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Kernel32/FILETIMETests.cs
new file mode 100644
index 0000000000..20fe747680
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Kernel32/FILETIMETests.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using Xunit;
+using static Interop.Kernel32;
+
+namespace System.Windows.Forms.Tests.Interop.Kernel32
+{
+ // NB: doesn't require thread affinity
+ public class FILETIMETests
+ {
+ [Fact]
+ public unsafe void FILETIME_Sizeof_Invoke_ReturnsExpected()
+ {
+ Assert.Equal(8, Marshal.SizeOf());
+ Assert.Equal(8, sizeof(FILETIME));
+ }
+
+ [Fact]
+ public void FILETIME_Ctor_Default()
+ {
+ var ft = new FILETIME();
+ Assert.Equal(0u, ft.dwLowDateTime);
+ Assert.Equal(0u, ft.dwHighDateTime);
+ }
+
+ [Fact]
+ public void FILETIME_Ctor_DateTime()
+ {
+ var dt = new DateTime(2020, 05, 13, 13, 3, 12);
+ var ft = new FILETIME(dt);
+ Assert.Equal(3680495616u, ft.dwLowDateTime);
+ Assert.Equal(30812454u, ft.dwHighDateTime);
+ }
+
+ [Fact]
+ public void FILETIME_ToDateTime_Invoke_ReturnsExpected()
+ {
+ var ft = new FILETIME()
+ {
+ dwLowDateTime = 3680495616u,
+ dwHighDateTime = 30812454u
+ };
+ Assert.Equal(new DateTime(2020, 05, 13, 13, 3, 12), ft.ToDateTime());
+ }
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/DECIMALTests.cs b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/DECIMALTests.cs
new file mode 100644
index 0000000000..1357d9d8ea
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/DECIMALTests.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using Xunit;
+using static Interop;
+using static Interop.Oleaut32;
+
+namespace System.Windows.Forms.Tests.Interop.Oleaut32
+{
+ // NB: doesn't require thread affinity
+ public class DECIMALTests
+ {
+ [Fact]
+ public unsafe void DECIMAL_Sizeof_Invoke_ReturnsExpected()
+ {
+ Assert.Equal(16, Marshal.SizeOf());
+ Assert.Equal(16, sizeof(DECIMAL));
+ }
+
+ [Fact]
+ public void DECIMAL_ToDecimal_InvokeEmpty_ReturnsExpected()
+ {
+ var dec = new DECIMAL();
+ Assert.Equal(0m, dec.ToDecimal());
+ }
+
+ [Theory]
+ [InlineData((double)int.MinValue)]
+ [InlineData(-1.2)]
+ [InlineData(0)]
+ [InlineData(1.2)]
+ [InlineData((double)int.MaxValue)]
+ public void DECIMAL_ToDecimal_InvokeCustom_ReturnsExpected(double value)
+ {
+ HRESULT hr = VarDecFromR8(value, out DECIMAL dec);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal((decimal)value, dec.ToDecimal());
+ }
+
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ private static extern HRESULT VarDecFromR8(double dblIn, out DECIMAL pdecOut);
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/SAFEARRAYTests.cs b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/SAFEARRAYTests.cs
new file mode 100644
index 0000000000..4ab7f9203d
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/SAFEARRAYTests.cs
@@ -0,0 +1,416 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable disable
+
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Xunit;
+using static Interop;
+using static Interop.Ole32;
+using static Interop.Oleaut32;
+
+namespace System.Windows.Forms.Tests.Interop.Oleaut32
+{
+ public unsafe class SAFEARRAYTests
+ {
+ [ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is32bit))]
+ public void SAFEARRAY_Sizeof_InvokeX86_ReturnsExpected()
+ {
+ Assert.Equal(24, Marshal.SizeOf());
+ Assert.Equal(24, sizeof(SAFEARRAY));
+ }
+
+ [ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is64bit))]
+ public void SAFEARRAY_Sizeof_InvokeX64_ReturnsExpected()
+ {
+ Assert.Equal(32, Marshal.SizeOf());
+ Assert.Equal(32, sizeof(SAFEARRAY));
+ }
+
+ public static IEnumerable Create_TestData()
+ {
+ yield return new object[] { VARENUM.I4, FADF.HAVEVARTYPE, 4 };
+ yield return new object[] { VARENUM.I8, FADF.HAVEVARTYPE, 8 };
+ yield return new object[] { VARENUM.BSTR, FADF.HAVEVARTYPE | FADF.BSTR, IntPtr.Size };
+ yield return new object[] { VARENUM.UNKNOWN, FADF.HAVEIID | FADF.UNKNOWN, IntPtr.Size };
+ yield return new object[] { VARENUM.DISPATCH, FADF.HAVEIID | FADF.DISPATCH, IntPtr.Size };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(Create_TestData))]
+ 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);
+ }
+ }
+
+ [StaFact]
+ public void SAFEARRAY_CreateSingleDimensionRECORD_GetProperties_Success()
+ {
+ var saBound = new SAFEARRAYBOUND
+ {
+ cElements = 10,
+ lLbound = 1
+ };
+ var record = new CustomRecordInfo();
+ IntPtr pRecord = Marshal.GetComInterfaceForObject(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);
+ }
+ }
+
+ private class CustomRecordInfo : IRecordInfo
+ {
+ HRESULT IRecordInfo.RecordInit(void* pvNew) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordClear(void* pvExisting) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordCopy(void* pvExisting, void* pvNew) => throw new NotImplementedException();
+
+ public Func<(Guid, HRESULT)> GetGuidAction { get; set; }
+
+ HRESULT IRecordInfo.GetGuid(Guid* pguid)
+ {
+ (Guid guid, HRESULT hr) = GetGuidAction();
+ *pguid = guid;
+ return hr;
+ }
+
+ HRESULT IRecordInfo.GetName(BSTR* pbstrName) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetSize(uint* pcbSize)
+ {
+ *pcbSize = (uint)sizeof(int);
+ return HRESULT.S_OK;
+ }
+
+ HRESULT IRecordInfo.GetTypeInfo(out ITypeInfo ppTypeInfo) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetField(void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetFieldNoCopy(void* pvData, out string szFieldName, VARIANT* pvarField, void* ppvDataCArray) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.PutField(INVOKEKIND wFlags, void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.PutFieldNoCopy(INVOKEKIND wFlags, void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetFieldNames(uint* pcNames, BSTR* rgBstrNames) => throw new NotImplementedException();
+
+ BOOL IRecordInfo.IsMatchingType(ref IRecordInfo pRecordInfo) => throw new NotImplementedException();
+
+ void* IRecordInfo.RecordCreate() => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordCreateCopy(void* pvSource, void** ppvDest) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordDestroy(void* pvRecord) => throw new NotImplementedException();
+ }
+
+ [StaTheory]
+ [MemberData(nameof(Create_TestData))]
+ public void SAFEARRAY_CreateMultipleDimensions_GetProperties_Success(ushort vt, ushort expectedFeatures, uint expectedCbElements)
+ {
+ SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
+ saBounds[0] = new SAFEARRAYBOUND
+ {
+ cElements = 10,
+ lLbound = 1
+ };
+ saBounds[1] = new SAFEARRAYBOUND
+ {
+ cElements = 20,
+ lLbound = 0
+ };
+ SAFEARRAY *psa = SafeArrayCreate((VARENUM)vt, 2, saBounds);
+ Assert.True(psa != null);
+
+ try
+ {
+ Assert.Equal(2u, psa->cDims);
+ Assert.Equal((FADF)expectedFeatures, psa->fFeatures);
+ Assert.Equal(expectedCbElements, psa->cbElements);
+ Assert.Equal(0u, psa->cLocks);
+ Assert.True(psa->pvData != null);
+ Assert.Equal(20u, psa->rgsabound[0].cElements);
+ Assert.Equal(0, psa->rgsabound[0].lLbound);
+ Assert.Equal(10u, psa->rgsabound[1].cElements);
+ Assert.Equal(1, psa->rgsabound[1].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);
+ }
+ }
+
+ [StaFact]
+ public void SAFEARRAY_GetValue_InvokeSingleDimensional_ReturnsExpected()
+ {
+ var saBound = new SAFEARRAYBOUND
+ {
+ cElements = 10,
+ lLbound = 0
+ };
+ SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 1, &saBound);
+ Assert.True(psa != null);
+
+ try
+ {
+ Span indices1 = stackalloc int[] { 0 };
+ Span indices2 = stackalloc int[] { 1 };
+
+ fixed (int* pIndices1 = indices1)
+ fixed (int* pIndices2 = indices2)
+ {
+ int value1 = 1;
+ HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int value2 = 2;
+ hr = SafeArrayPutElement(psa, pIndices2, &value2);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int result = -1;
+ hr = SafeArrayGetElement(psa, pIndices1, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(1, result);
+
+ hr = SafeArrayGetElement(psa, pIndices2, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(2, result);
+ }
+
+ Assert.Equal(1, psa->GetValue(indices1));
+ Assert.Equal(2, psa->GetValue(indices2));
+ }
+ finally
+ {
+ SafeArrayDestroy(psa);
+ }
+ }
+
+ [StaFact]
+ public void SAFEARRAY_GetValue_InvokeSingleDimensionalNonZeroLowerBound_ReturnsExpected()
+ {
+ var saBound = new SAFEARRAYBOUND
+ {
+ cElements = 10,
+ lLbound = -5
+ };
+ SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 1, &saBound);
+ Assert.True(psa != null);
+
+ try
+ {
+ Span indices1 = stackalloc int[] { -5 };
+ Span indices2 = stackalloc int[] { -4 };
+
+ fixed (int* pIndices1 = indices1)
+ fixed (int* pIndices2 = indices2)
+ {
+ int value1 = 1;
+ HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int value2 = 2;
+ hr = SafeArrayPutElement(psa, pIndices2, &value2);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int result = -1;
+ hr = SafeArrayGetElement(psa, pIndices1, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(1, result);
+
+ hr = SafeArrayGetElement(psa, pIndices2, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(2, result);
+ }
+
+ Assert.Equal(1, psa->GetValue(indices1));
+ Assert.Equal(2, psa->GetValue(indices2));
+ }
+ finally
+ {
+ SafeArrayDestroy(psa);
+ }
+ }
+
+ [StaFact]
+ public void SAFEARRAY_GetValue_InvokeMultiDimensional_ReturnsExpected()
+ {
+ SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
+ saBounds[0] = new SAFEARRAYBOUND
+ {
+ cElements = 10,
+ lLbound = 0
+ };
+ saBounds[1] = new SAFEARRAYBOUND
+ {
+ cElements = 20,
+ lLbound = 0
+ };
+ SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 2, saBounds);
+ Assert.True(psa != null);
+
+ try
+ {
+ Span indices1 = stackalloc int[] { 0, 0 };
+ Span indices2 = stackalloc int[] { 1, 2 };
+
+ fixed (int* pIndices1 = indices1)
+ fixed (int* pIndices2 = indices2)
+ {
+ int value1 = 1;
+ HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int value2 = 2;
+ hr = SafeArrayPutElement(psa, pIndices2, &value2);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int result = -1;
+ hr = SafeArrayGetElement(psa, pIndices1, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(1, result);
+
+ hr = SafeArrayGetElement(psa, pIndices2, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(2, result);
+ }
+
+ Assert.Equal(1, psa->GetValue(indices1));
+ Assert.Equal(2, psa->GetValue(indices2));
+ }
+ finally
+ {
+ SafeArrayDestroy(psa);
+ }
+ }
+
+ [StaFact]
+ public void SAFEARRAY_GetValue_InvokeMultiDimensionalNonZeroLowerBound_ReturnsExpected()
+ {
+ SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
+ saBounds[0] = new SAFEARRAYBOUND
+ {
+ cElements = 10,
+ lLbound = -5
+ };
+ saBounds[1] = new SAFEARRAYBOUND
+ {
+ cElements = 20,
+ lLbound = -4
+ };
+ SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, 2, saBounds);
+ Assert.True(psa != null);
+
+ try
+ {
+ Span indices1 = stackalloc int[] { -5, -4 };
+ Span indices2 = stackalloc int[] { -4, -3 };
+
+ fixed (int* pIndices1 = indices1)
+ fixed (int* pIndices2 = indices2)
+ {
+ int value1 = 1;
+ HRESULT hr = SafeArrayPutElement(psa, pIndices1, &value1);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int value2 = 2;
+ hr = SafeArrayPutElement(psa, pIndices2, &value2);
+ Assert.Equal(HRESULT.S_OK, hr);
+
+ int result = -1;
+ hr = SafeArrayGetElement(psa, pIndices1, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(1, result);
+
+ hr = SafeArrayGetElement(psa, pIndices2, &result);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(2, result);
+ }
+
+ Assert.Equal(1, psa->GetValue(indices1));
+ Assert.Equal(2, psa->GetValue(indices2));
+ }
+ finally
+ {
+ SafeArrayDestroy(psa);
+ }
+ }
+
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ private static unsafe extern SAFEARRAY* SafeArrayCreate(VARENUM vt, uint cDims, SAFEARRAYBOUND* rgsabound);
+
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ private static unsafe extern SAFEARRAY* SafeArrayCreateEx(VARENUM vt, uint cDims, SAFEARRAYBOUND* rgsabound, IntPtr pvExtra);
+
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ private static unsafe extern HRESULT SafeArrayDestroy(SAFEARRAY* psa);
+
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ private unsafe static extern HRESULT SafeArrayPutElement(SAFEARRAY* psa, int* rgIndices, void* pv);
+
+ [DllImport(Libraries.Oleaut32, ExactSpelling = true)]
+ private unsafe static extern HRESULT SafeArrayGetElement(SAFEARRAY* psa, int* rgIndices, void* pv);
+ }
+}
diff --git a/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/VARIANTTests.cs b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/VARIANTTests.cs
new file mode 100644
index 0000000000..56eff86f97
--- /dev/null
+++ b/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/VARIANTTests.cs
@@ -0,0 +1,6111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable disable
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using Xunit;
+using static Interop;
+using static Interop.Kernel32;
+using static Interop.Ole32;
+using static Interop.Oleaut32;
+
+namespace System.Windows.Forms.Tests.Interop.Oleaut32
+{
+ public unsafe class VARIANTTests
+ {
+ [ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is32bit))]
+ public void VARIANT_Sizeof_InvokeX86_ReturnsExpected()
+ {
+ Assert.Equal(16, Marshal.SizeOf());
+ Assert.Equal(16, sizeof(VARIANT));
+ }
+
+ [ConditionalFact(typeof(ArchitectureDetection), nameof(ArchitectureDetection.Is64bit))]
+ public void VARIANT_Sizeof_InvokeX64_ReturnsExpected()
+ {
+ Assert.Equal(24, Marshal.SizeOf());
+ Assert.Equal(24, sizeof(VARIANT));
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.EMPTY, false)]
+ [InlineData((ushort)VARENUM.BOOL, false)]
+ [InlineData((ushort)(VARENUM.BYREF), true)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF), true)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF | VARENUM.ARRAY), true)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF | VARENUM.VECTOR), true)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.ARRAY), false)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.VECTOR), false)]
+ public void VARIANT_Byref_Get_ReturnsExpected(ushort vt, bool expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ Assert.Equal(expected, variant.Byref);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.EMPTY, (ushort)VARENUM.EMPTY)]
+ [InlineData((ushort)VARENUM.BOOL, (ushort)VARENUM.BOOL)]
+ [InlineData((ushort)(VARENUM.BYREF), (ushort)VARENUM.EMPTY)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF), (ushort)VARENUM.BOOL)]
+ public void VARIANT_Type_Get_ReturnsExpected(ushort vt, ushort expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ Assert.Equal((VARENUM)expected, variant.Type);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.EMPTY)]
+ [InlineData((ushort)(VARENUM.EMPTY | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.UNKNOWN)]
+ [InlineData((ushort)(VARENUM.UNKNOWN | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.DISPATCH)]
+ [InlineData((ushort)(VARENUM.DISPATCH | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.BSTR)]
+ [InlineData((ushort)(VARENUM.BSTR | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.BOOL)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF))]
+ public void VARIANT_Clear_InvokeDefault_Success(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ variant.Clear();
+ Assert.Equal(VARENUM.EMPTY, variant.vt);
+ Assert.Equal(IntPtr.Zero, variant.data.punkVal);
+ }
+
+ [StaFact]
+ public void VARIANT_Clear_InvokeCustom_Success()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BOOL,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)1,
+ }
+ };
+ variant.Clear();
+ Assert.Equal(VARENUM.EMPTY, variant.vt);
+ Assert.Equal(IntPtr.Zero, variant.data.punkVal);
+ }
+
+ [StaFact]
+ public void VARIANT_Clear_InvokeBSTR_Success()
+ {
+ IntPtr data = Marshal.StringToBSTR("abc");
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ variant.Clear();
+ Assert.Equal(VARENUM.EMPTY, variant.vt);
+ Assert.Equal(IntPtr.Zero, variant.data.punkVal);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.EMPTY)]
+ [InlineData((ushort)(VARENUM.EMPTY | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.UNKNOWN)]
+ [InlineData((ushort)(VARENUM.UNKNOWN | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.DISPATCH)]
+ [InlineData((ushort)(VARENUM.DISPATCH | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.BSTR)]
+ [InlineData((ushort)(VARENUM.BSTR | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.BOOL)]
+ [InlineData((ushort)(VARENUM.BOOL | VARENUM.BYREF))]
+ public void VARIANT_Dispose_InvokeDefault_Success(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ variant.Dispose();
+ Assert.Equal(VARENUM.EMPTY, variant.vt);
+ Assert.Equal(IntPtr.Zero, variant.data.punkVal);
+ }
+
+ [StaFact]
+ public void VARIANT_Dispose_InvokeCustom_Success()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BOOL,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)1,
+ }
+ };
+ variant.Dispose();
+ Assert.Equal(VARENUM.EMPTY, variant.vt);
+ Assert.Equal(IntPtr.Zero, variant.data.punkVal);
+ }
+
+ [StaFact]
+ public void VARIANT_Dispose_InvokeBSTR_Success()
+ {
+ IntPtr data = Marshal.StringToBSTR("abc");
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ variant.Dispose();
+ Assert.Equal(VARENUM.EMPTY, variant.vt);
+ Assert.Equal(IntPtr.Zero, variant.data.punkVal);
+ }
+
+ public static IEnumerable ToObject_TestData()
+ {
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.I1, (IntPtr)long.MinValue, (sbyte)0 };
+ }
+ yield return new object[] { VARENUM.I1, (IntPtr)int.MinValue, (sbyte)0 };
+ yield return new object[] { VARENUM.I1, (IntPtr)short.MinValue, (sbyte)0 };
+ yield return new object[] { VARENUM.I1, (IntPtr)sbyte.MinValue, sbyte.MinValue };
+ yield return new object[] { VARENUM.I1, (IntPtr)(-10), (sbyte)(-10) };
+ yield return new object[] { VARENUM.I1, (IntPtr)0, (sbyte)0 };
+ yield return new object[] { VARENUM.I1, (IntPtr)10, (sbyte)10 };
+ yield return new object[] { VARENUM.I1, (IntPtr)sbyte.MaxValue, sbyte.MaxValue };
+ yield return new object[] { VARENUM.I1, (IntPtr)short.MaxValue, (sbyte)(-1) };
+ yield return new object[] { VARENUM.I1, (IntPtr)int.MaxValue, (sbyte)(-1) };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.I1, (IntPtr)long.MaxValue, (sbyte)(-1) };
+ }
+
+ yield return new object[] { VARENUM.UI1, (IntPtr)(-10), (byte)246 };
+ yield return new object[] { VARENUM.UI1, (IntPtr)0, (byte)0 };
+ yield return new object[] { VARENUM.UI1, (IntPtr)10, (byte)10 };
+ yield return new object[] { VARENUM.UI1, (IntPtr)byte.MaxValue, byte.MaxValue };
+ yield return new object[] { VARENUM.UI1, (IntPtr)ushort.MaxValue, byte.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.UI1, (IntPtr)uint.MaxValue, byte.MaxValue };
+ }
+ yield return new object[] { VARENUM.UI1, (IntPtr)(-1), byte.MaxValue };
+
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.I2, (IntPtr)long.MinValue, (short)0 };
+ }
+ yield return new object[] { VARENUM.I2, (IntPtr)int.MinValue, (short)0 };
+ yield return new object[] { VARENUM.I2, (IntPtr)short.MinValue, short.MinValue };
+ yield return new object[] { VARENUM.I2, (IntPtr)sbyte.MinValue, (short)sbyte.MinValue };
+ yield return new object[] { VARENUM.I2, (IntPtr)(-10), (short)(-10) };
+ yield return new object[] { VARENUM.I2, (IntPtr)0, (short)0 };
+ yield return new object[] { VARENUM.I2, (IntPtr)10, (short)10 };
+ yield return new object[] { VARENUM.I2, (IntPtr)sbyte.MaxValue, (short)sbyte.MaxValue };
+ yield return new object[] { VARENUM.I2, (IntPtr)short.MaxValue, short.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.I2, (IntPtr)long.MaxValue, (short)(-1) };
+ }
+
+ yield return new object[] { VARENUM.UI2, (IntPtr)(-10), (ushort)65526 };
+ yield return new object[] { VARENUM.UI2, (IntPtr)0, (ushort)0 };
+ yield return new object[] { VARENUM.UI2, (IntPtr)10, (ushort)10 };
+ yield return new object[] { VARENUM.UI2, (IntPtr)byte.MaxValue, (ushort)byte.MaxValue };
+ yield return new object[] { VARENUM.UI2, (IntPtr)ushort.MaxValue, ushort.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.UI2, (IntPtr)uint.MaxValue, ushort.MaxValue };
+ }
+ yield return new object[] { VARENUM.UI2, (IntPtr)(-1), ushort.MaxValue };
+
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.I4, (IntPtr)long.MinValue, 0 };
+ }
+ yield return new object[] { VARENUM.I4, (IntPtr)int.MinValue, int.MinValue };
+ yield return new object[] { VARENUM.I4, (IntPtr)short.MinValue, (int)short.MinValue };
+ yield return new object[] { VARENUM.I4, (IntPtr)sbyte.MinValue, (int)sbyte.MinValue };
+ yield return new object[] { VARENUM.I4, (IntPtr)(-10), -10 };
+ yield return new object[] { VARENUM.I4, (IntPtr)0, 0 };
+ yield return new object[] { VARENUM.I4, (IntPtr)10, 10 };
+ yield return new object[] { VARENUM.I4, (IntPtr)sbyte.MaxValue, (int)sbyte.MaxValue };
+ yield return new object[] { VARENUM.I4, (IntPtr)short.MaxValue, (int)short.MaxValue };
+ yield return new object[] { VARENUM.I4, (IntPtr)int.MaxValue, int.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.I4, (IntPtr)long.MaxValue, -1 };
+ }
+
+ yield return new object[] { VARENUM.UI4, (IntPtr)(-10), (uint)4294967286 };
+ yield return new object[] { VARENUM.UI4, (IntPtr)0, (uint)0 };
+ yield return new object[] { VARENUM.UI4, (IntPtr)10, (uint)10 };
+ yield return new object[] { VARENUM.UI4, (IntPtr)byte.MaxValue, (uint)byte.MaxValue };
+ yield return new object[] { VARENUM.UI4, (IntPtr)ushort.MaxValue, (uint)ushort.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.UI4, (IntPtr)uint.MaxValue, uint.MaxValue };
+ }
+ yield return new object[] { VARENUM.UI4, (IntPtr)(-1), uint.MaxValue };
+
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.INT, (IntPtr)long.MinValue, 0 };
+ }
+ yield return new object[] { VARENUM.INT, (IntPtr)int.MinValue, int.MinValue };
+ yield return new object[] { VARENUM.INT, (IntPtr)short.MinValue, (int)short.MinValue };
+ yield return new object[] { VARENUM.INT, (IntPtr)sbyte.MinValue, (int)sbyte.MinValue };
+ yield return new object[] { VARENUM.INT, (IntPtr)(-10), -10 };
+ yield return new object[] { VARENUM.INT, (IntPtr)0, 0 };
+ yield return new object[] { VARENUM.INT, (IntPtr)10, 10 };
+ yield return new object[] { VARENUM.INT, (IntPtr)sbyte.MaxValue, (int)sbyte.MaxValue };
+ yield return new object[] { VARENUM.INT, (IntPtr)short.MaxValue, (int)short.MaxValue };
+ yield return new object[] { VARENUM.INT, (IntPtr)int.MaxValue, int.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.INT, (IntPtr)long.MaxValue, -1 };
+ }
+
+ yield return new object[] { VARENUM.UINT, (IntPtr)(-10), (uint)4294967286 };
+ yield return new object[] { VARENUM.UINT, (IntPtr)0, (uint)0 };
+ yield return new object[] { VARENUM.UINT, (IntPtr)10, (uint)10 };
+ yield return new object[] { VARENUM.UINT, (IntPtr)byte.MaxValue, (uint)byte.MaxValue };
+ yield return new object[] { VARENUM.UINT, (IntPtr)ushort.MaxValue, (uint)ushort.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.UINT, (IntPtr)uint.MaxValue, uint.MaxValue };
+ }
+ yield return new object[] { VARENUM.UINT, (IntPtr)(-1), uint.MaxValue };
+
+ yield return new object[] { VARENUM.BOOL, (IntPtr)(-1), true };
+ yield return new object[] { VARENUM.BOOL, (IntPtr)0, false };
+ yield return new object[] { VARENUM.BOOL, (IntPtr)1, true };
+
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.ERROR, (IntPtr)long.MinValue, 0 };
+ }
+ yield return new object[] { VARENUM.ERROR, (IntPtr)int.MinValue, int.MinValue };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)short.MinValue, (int)short.MinValue };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)sbyte.MinValue, (int)sbyte.MinValue };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)(-10), -10 };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)0, 0 };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)10, 10 };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)sbyte.MaxValue, (int)sbyte.MaxValue };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)short.MaxValue, (int)short.MaxValue };
+ yield return new object[] { VARENUM.ERROR, (IntPtr)int.MaxValue, int.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { VARENUM.ERROR, (IntPtr)long.MaxValue, -1 };
+ }
+ }
+
+ [StaTheory]
+ [MemberData(nameof(ToObject_TestData))]
+ public void VARIANT_ToObject_Invoke_ReturnsExpected(ushort vt, IntPtr data, object expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)data
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(ToObject_TestData))]
+ public void VARIANT_ToObject_InvokeBYREF_ReturnsExpected(ushort vt, IntPtr data, object expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)(&data)
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable BYREFNoData_TestData()
+ {
+ yield return new object[] { VARENUM.I2 };
+ yield return new object[] { VARENUM.I4 };
+ yield return new object[] { VARENUM.R4 };
+ yield return new object[] { VARENUM.R8 };
+ yield return new object[] { VARENUM.CY };
+ yield return new object[] { VARENUM.DATE };
+ yield return new object[] { VARENUM.BSTR };
+ yield return new object[] { VARENUM.DISPATCH };
+ yield return new object[] { VARENUM.ERROR };
+ yield return new object[] { VARENUM.BOOL };
+ yield return new object[] { VARENUM.VARIANT };
+ yield return new object[] { VARENUM.UNKNOWN };
+ yield return new object[] { VARENUM.DECIMAL };
+ yield return new object[] { VARENUM.I1 };
+ yield return new object[] { VARENUM.UI1 };
+ yield return new object[] { VARENUM.UI2 };
+ yield return new object[] { VARENUM.UI4 };
+ yield return new object[] { VARENUM.I8 };
+ yield return new object[] { VARENUM.UI8 };
+ yield return new object[] { VARENUM.INT };
+ yield return new object[] { VARENUM.UINT };
+ yield return new object[] { VARENUM.VOID };
+ yield return new object[] { VARENUM.HRESULT };
+ yield return new object[] { VARENUM.PTR };
+ yield return new object[] { VARENUM.SAFEARRAY };
+ yield return new object[] { VARENUM.CARRAY };
+ yield return new object[] { VARENUM.USERDEFINED };
+ yield return new object[] { VARENUM.LPSTR };
+ yield return new object[] { VARENUM.LPWSTR };
+ yield return new object[] { VARENUM.RECORD };
+ yield return new object[] { VARENUM.INT_PTR };
+ yield return new object[] { VARENUM.UINT_PTR };
+ yield return new object[] { VARENUM.FILETIME };
+ yield return new object[] { VARENUM.BLOB };
+ yield return new object[] { VARENUM.STREAM };
+ yield return new object[] { VARENUM.STORAGE };
+ yield return new object[] { VARENUM.STREAMED_OBJECT };
+ yield return new object[] { VARENUM.STORED_OBJECT };
+ yield return new object[] { VARENUM.BLOB_OBJECT };
+ yield return new object[] { VARENUM.CF };
+ yield return new object[] { VARENUM.CLSID };
+ yield return new object[] { VARENUM.VERSIONED_STREAM };
+ yield return new object[] { VARENUM.BSTR_BLOB };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(BYREFNoData_TestData))]
+ public void VARIANT_Toobject_BYREFNoData_Throws(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BYREF | (VARENUM)vt,
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ public static IEnumerable ToObject_I8_TestData()
+ {
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)long.MinValue, long.MinValue };
+ yield return new object[] { (IntPtr)int.MinValue, (long)int.MinValue };
+ yield return new object[] { (IntPtr)short.MinValue, (long)short.MinValue };
+ yield return new object[] { (IntPtr)sbyte.MinValue, (long)sbyte.MinValue };
+ yield return new object[] { (IntPtr)(-10), (long)(-10) };
+ }
+ yield return new object[] { (IntPtr)0, (long)0 };
+ yield return new object[] { (IntPtr)10, (long)10 };
+ yield return new object[] { (IntPtr)sbyte.MaxValue, (long)sbyte.MaxValue };
+ yield return new object[] { (IntPtr)short.MaxValue, (long)short.MaxValue };
+ yield return new object[] { (IntPtr)int.MaxValue, (long)int.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)long.MaxValue, long.MaxValue };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_I8_TestData))]
+ public void VARIANT_ToObject_I8_ReturnsExpected(IntPtr data, long expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.I8,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable ToObject_I8BYREF_TestData()
+ {
+ yield return new object[] { long.MinValue };
+ yield return new object[] { int.MinValue };
+ yield return new object[] { short.MinValue };
+ yield return new object[] { sbyte.MinValue };
+ yield return new object[] { -10, };
+ yield return new object[] { 0, };
+ yield return new object[] { 10, };
+ yield return new object[] { sbyte.MaxValue };
+ yield return new object[] { short.MaxValue };
+ yield return new object[] { int.MaxValue };
+ yield return new object[] { long.MaxValue };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_I8BYREF_TestData))]
+ public void VARIANT_ToObject_I8BYREF_ReturnsExpected(long data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.I8 | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)(&data)
+ }
+ };
+ AssertToObjectEqual(data, variant);
+ }
+
+ public static IEnumerable ToObject_UI8_TestData()
+ {
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)(-10), (ulong)18446744073709551606 };
+ }
+ yield return new object[] { (IntPtr)0, (ulong)0 };
+ yield return new object[] { (IntPtr)10, (ulong)10 };
+ yield return new object[] { (IntPtr)byte.MaxValue, (ulong)byte.MaxValue };
+ yield return new object[] { (IntPtr)ushort.MaxValue, (ulong)ushort.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)uint.MaxValue, (ulong)uint.MaxValue };
+ yield return new object[] { (IntPtr)ulong.MaxValue, ulong.MaxValue };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_UI8_TestData))]
+ public void VARIANT_ToObject_UI8_ReturnsExpected(IntPtr data, ulong expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.UI8,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable ToObject_UI8BYREF_TestData()
+ {
+ yield return new object[] { 0 };
+ yield return new object[] { 10 };
+ yield return new object[] { byte.MaxValue };
+ yield return new object[] { ushort.MaxValue};
+ yield return new object[] { uint.MaxValue };
+ yield return new object[] { ulong.MaxValue };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_UI8BYREF_TestData))]
+ public void VARIANT_ToObject_UI8BYREF_ReturnsExpected(ulong data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.UI8 | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)(&data)
+ }
+ };
+ AssertToObjectEqual(data, variant);
+ }
+
+ public static IEnumerable ToObject_CY_TestData()
+ {
+ yield return new object[] { (IntPtr)0, 0.0m };
+ yield return new object[] { (IntPtr)10, 0.001m };
+ yield return new object[] { (IntPtr)10000, 1m };
+ yield return new object[] { (IntPtr)123456, 12.3456m };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)(-10), -0.001m };
+ yield return new object[] { (IntPtr)(-10000), -1m };
+ yield return new object[] { (IntPtr)(-123456), -12.3456m };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_CY_TestData))]
+ public void VARIANT_ToObject_CY_ReturnsExpected(IntPtr data, decimal expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.CY,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable ToObject_CYBYREF_TestData()
+ {
+ yield return new object[] { 0, 0.0m };
+ yield return new object[] { 10, 0.001m };
+ yield return new object[] { 10000, 1m };
+ yield return new object[] { 123456, 12.3456m };
+ yield return new object[] { -10, -0.001m };
+ yield return new object[] { -10000, -1m };
+ yield return new object[] { -123456, -12.3456m };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_CYBYREF_TestData))]
+ public void VARIANT_ToObject_CYBYREF_ReturnsExpected(long data, decimal expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.CY | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)(&data)
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable ToObject_R4_TestData()
+ {
+ yield return new object[] { (IntPtr)0, 0.0f };
+ yield return new object[] { (IntPtr)1067030938, 1.2f };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)3214514586, -1.2f };
+ yield return new object[] { (IntPtr)4290772992, float.NaN };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_R4_TestData))]
+ public void VARIANT_ToObject_R4_ReturnsExpected(IntPtr data, float expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.R4,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable ToObject_R4BYREF_TestData()
+ {
+ yield return new object[] { 0.0f };
+ yield return new object[] { 1.2f };
+ yield return new object[] { -1.2f };
+ yield return new object[] { float.NaN };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_R4BYREF_TestData))]
+ public void VARIANT_ToObject_R4BYREF_ReturnsExpected(float data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.R4 | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)(&data)
+ }
+ };
+ AssertToObjectEqual(data, variant);
+ }
+
+ public static IEnumerable ToObject_R8_TestData()
+ {
+ yield return new object[] { (IntPtr)0, 0.0 };
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)4608083138725491507, 1.2 };
+ yield return new object[] { (IntPtr)(-4615288898129284301), -1.2 };
+ yield return new object[] { (IntPtr)(-2251799813685248), double.NaN };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_R8_TestData))]
+ public void VARIANT_ToObject_R8_ReturnsExpected(IntPtr data, double expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.R8,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ public static IEnumerable ToObject_R8BYREF_TestData()
+ {
+ yield return new object[] { 0.0 };
+ yield return new object[] { 1.2 };
+ yield return new object[] { -1.2 };
+ yield return new object[] { double.NaN };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToObject_R8BYREF_TestData))]
+ public void VARIANT_ToObject_R8BYREF_ReturnsExpected(double data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.R8 | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = (IntPtr)(&data)
+ }
+ };
+ AssertToObjectEqual(data, variant);
+ }
+
+ public static IEnumerable NULL_TestData()
+ {
+ yield return new object[] { IntPtr.Zero };
+ yield return new object[] { (IntPtr)1 };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(NULL_TestData))]
+ public void VARIANT_ToObject_NULL_Sucess(IntPtr data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BYREF | VARENUM.NULL,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(Convert.DBNull, variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(NULL_TestData))]
+ public void VARIANT_ToObject_NULLBYREFData_Sucess(IntPtr data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BYREF | VARENUM.NULL,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppunkVal = &data
+ }
+ };
+ AssertToObjectEqual(Convert.DBNull, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_NULLBYREFNoData_Sucess()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BYREF | VARENUM.NULL
+ };
+ AssertToObjectEqual(Convert.DBNull, variant);
+ }
+
+ public static IEnumerable EMPTY_TestData()
+ {
+ yield return new object[] { IntPtr.Zero };
+ yield return new object[] { (IntPtr)1 };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(EMPTY_TestData))]
+ public void VARIANT_ToObject_EMPTY_Sucess(IntPtr data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.EMPTY,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(EMPTY_TestData))]
+ public void VARIANT_ToObject_EMPTYBYREFData_Sucess(IntPtr data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BYREF | VARENUM.EMPTY,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppunkVal = &data
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ if (IntPtr.Size == 8)
+ {
+ Assert.Equal((ulong)(IntPtr)variant.data.ppunkVal, value);
+ }
+ else
+ {
+ Assert.Equal((uint)(IntPtr)variant.data.ppunkVal, value);
+ }
+ });
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_EMPTYBYREFNoData_Sucess()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BYREF | VARENUM.EMPTY
+ };
+ AssertToObject(variant, value =>
+ {
+ if (IntPtr.Size == 8)
+ {
+ Assert.Equal((ulong)0, value);
+ }
+ else
+ {
+ Assert.Equal((uint)0, value);
+ }
+ });
+ }
+
+ public static IEnumerable HRESULT_TestData()
+ {
+ yield return new object[] { (IntPtr)int.MinValue, int.MinValue };
+ yield return new object[] { (IntPtr)short.MinValue, (int)short.MinValue };
+ yield return new object[] { (IntPtr)sbyte.MinValue, (int)sbyte.MinValue };
+ yield return new object[] { (IntPtr)(-10), -10 };
+ yield return new object[] { (IntPtr)0, 0 };
+ yield return new object[] { (IntPtr)10, 10 };
+ yield return new object[] { (IntPtr)sbyte.MaxValue, (int)sbyte.MaxValue };
+ yield return new object[] { (IntPtr)short.MaxValue, (int)short.MaxValue };
+ yield return new object[] { (IntPtr)int.MaxValue, int.MaxValue };
+ if (IntPtr.Size == 8)
+ {
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)long.MinValue, 0 };
+ }
+ if (IntPtr.Size == 8)
+ {
+ yield return new object[] { (IntPtr)long.MaxValue, -1 };
+ }
+ }
+ }
+
+ [StaTheory]
+ [MemberData(nameof(HRESULT_TestData))]
+ public void VARIANT_ToObject_HRESULT_Success(IntPtr data, int expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.HRESULT,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ AssertToObjectEqualExtension(expected, variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(HRESULT_TestData))]
+ public void VARIANT_ToObject_HRESULTBYREF_Success(IntPtr data, int expected)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.HRESULT | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppunkVal = &data
+ }
+ };
+ AssertToObjectEqualExtension(expected, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_FILETIME_Success()
+ {
+ using var variant = new VARIANT();
+ var dt = new DateTime(2020, 05, 13, 13, 3, 12);
+ var ft = new FILETIME(dt);
+ HRESULT hr = InitPropVariantFromFileTime(&ft, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.FILETIME, variant.Type);
+
+ AssertToObjectEqualExtension(new DateTime(2020, 05, 13, 13, 3, 12), variant);
+ }
+
+ [StaTheory]
+ [InlineData(-10)]
+ public void VARIANT_ToObject_InvalidFILETIME_ThrowsArgumentOutOfRangeException(int value)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.FILETIME,
+ data = new VARIANT.VARIANTUnion
+ {
+ cyVal = value
+ }
+ };
+ Assert.Throws("fileTime", () => variant.ToObject());
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DateFromFILETIME_Success()
+ {
+ using var variant = new VARIANT();
+ var dt = new DateTime(2020, 05, 13, 13, 3, 12);
+ var ft = new FILETIME(dt);
+ HRESULT hr = InitVariantFromFileTime(&ft, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.DATE, variant.Type);
+
+ AssertToObjectEqual(new DateTime(2020, 05, 13, 13, 3, 12), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_Date_Success()
+ {
+ var dt = new DateTime(2020, 05, 13, 13, 3, 12);
+ double date = dt.ToOADate();
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DATE,
+ data = new VARIANT.VARIANTUnion
+ {
+ date = date
+ }
+ };
+ AssertToObjectEqual(new DateTime(2020, 05, 13, 13, 3, 12), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DateEmpty_Success()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DATE
+ };
+ AssertToObjectEqual(new DateTime(1899, 12, 30), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DateBYREF_Success()
+ {
+ var dt = new DateTime(2020, 05, 13, 13, 3, 12);
+ double date = dt.ToOADate();
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DATE | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pdate = &date
+ }
+ };
+ AssertToObjectEqual(new DateTime(2020, 05, 13, 13, 3, 12), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DateBYREFEmpty_Success()
+ {
+ double date = 0;
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DATE | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pdate = &date
+ }
+ };
+ AssertToObjectEqual(new DateTime(1899, 12, 30), variant);
+ }
+
+ [StaTheory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("text")]
+ public void VARIANT_ToObject_BSTR_ReturnsExpected(string text)
+ {
+ IntPtr ptr = Marshal.StringToBSTR(text);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ bstrVal = ptr
+ }
+ };
+ AssertToObjectEqual(text, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_BSTRNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BSTR
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaTheory]
+ [InlineData("")]
+ [InlineData("text")]
+ public void VARIANT_ToObject_BSTRBYREF_ReturnsExpected(string text)
+ {
+ IntPtr ptr = Marshal.StringToBSTR(text);
+ try
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.BSTR | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pbstrVal = &ptr
+ }
+ };
+ AssertToObjectEqual(text, variant);
+ }
+ finally
+ {
+ Marshal.FreeBSTR(ptr);
+ }
+ }
+
+ [StaTheory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("text")]
+ public void VARIANT_ToObject_LPWSTR_ReturnsExpected(string text)
+ {
+ IntPtr ptr = Marshal.StringToCoTaskMemUni(text);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.LPWSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ bstrVal = ptr
+ }
+ };
+ AssertToObjectEqualExtension(text, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_LPWSTRNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.LPWSTR
+ };
+ AssertToObjectEqualExtension(null, variant);
+ }
+
+ [StaTheory]
+ [InlineData("")]
+ [InlineData("text")]
+ public void VARIANT_ToObject_LPWSTRBYREF_ReturnsExpected(string text)
+ {
+ IntPtr ptr = Marshal.StringToCoTaskMemUni(text);
+ try
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.LPWSTR | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pbstrVal = &ptr
+ }
+ };
+ AssertToObjectEqualExtension(text, variant);
+ }
+ finally
+ {
+ Marshal.FreeCoTaskMem(ptr);
+ }
+ }
+
+ [StaTheory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("text")]
+ public void VARIANT_ToObject_LPSTR_ReturnsExpected(string text)
+ {
+ IntPtr ptr = Marshal.StringToCoTaskMemAnsi(text);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.LPSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ bstrVal = ptr
+ }
+ };
+ AssertToObjectEqualExtension(text, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_LPSTRNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.LPSTR
+ };
+ AssertToObjectEqualExtension(null, variant);
+ }
+
+ [StaTheory]
+ [InlineData("")]
+ [InlineData("text")]
+ public void VARIANT_ToObject_LPSTRBYREF_ReturnsExpected(string text)
+ {
+ IntPtr ptr = Marshal.StringToCoTaskMemAnsi(text);
+ try
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.LPSTR | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pbstrVal = &ptr
+ }
+ };
+ AssertToObjectEqualExtension(text, variant);
+ }
+ finally
+ {
+ Marshal.FreeCoTaskMem(ptr);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_Dispatch_ReturnsExpected()
+ {
+ var o = new object();
+ IntPtr pUnk = Marshal.GetIUnknownForObject(o);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DISPATCH,
+ data = new VARIANT.VARIANTUnion
+ {
+ pdispVal = pUnk
+ }
+ };
+ AssertToObjectEqual(o, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DispatchNoData_ReturnsNull()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DISPATCH
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DispatchBYREF_ReturnsExpected()
+ {
+ var o = new object();
+ IntPtr pUnk = Marshal.GetIUnknownForObject(o);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DISPATCH | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppdispVal = &pUnk
+ }
+ };
+ AssertToObjectEqual(o, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DispatchBYREFNullData_ReturnsNull()
+ {
+ IntPtr pUnk = IntPtr.Zero;
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DISPATCH | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppunkVal = &pUnk
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_UNKNOWN_ReturnsExpected()
+ {
+ var o = new object();
+ IntPtr pUnk = Marshal.GetIUnknownForObject(o);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = pUnk
+ }
+ };
+ AssertToObjectEqual(o, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_UNKNOWNNoData_ReturnsNull()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.UNKNOWN
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_UNKNOWNBYREF_ReturnsExpected()
+ {
+ var o = new object();
+ IntPtr pUnk = Marshal.GetIUnknownForObject(o);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.UNKNOWN | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppunkVal = &pUnk
+ }
+ };
+ AssertToObjectEqual(o, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_UNKNOWNBYREFNullData_ReturnsNull()
+ {
+ IntPtr pUnk = IntPtr.Zero;
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.UNKNOWN | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ ppunkVal = &pUnk
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_I4VARIANTBYREF_ReturnsExpected()
+ {
+ using var target = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 10
+ }
+ };
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VARIANT | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pvarVal = &target
+ }
+ };
+ AssertToObjectEqual(10, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_BSTRVARIANTBYREF_ReturnsExpected()
+ {
+ IntPtr ptr = Marshal.StringToBSTR("test");
+ using var target = new VARIANT
+ {
+ vt = VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ bstrVal = ptr
+ }
+ };
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VARIANT | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pvarVal = &target
+ }
+ };
+ AssertToObjectEqual("test", variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_EMPTYVARIANTBYREF_ThrowsInvalidOleVariantTypeException()
+ {
+ using var target = new VARIANT
+ {
+ vt = VARENUM.EMPTY,
+ };
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VARIANT | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pvarVal = &target
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_BYREFVARIANTBYREF_ThrowsInvalidOleVariantTypeException()
+ {
+ int lval = 10;
+ using var target = new VARIANT
+ {
+ vt = VARENUM.BYREF | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ plVal = &lval
+ }
+ };
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VARIANT | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pvarVal = &target
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VARIANT_ThrowsArgumentException()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VARIANT
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ public static IEnumerable Decimal_I8_TestData()
+ {
+ yield return new object[] { long.MinValue, (decimal)long.MinValue };
+ yield return new object[] { -123, -123m };
+ yield return new object[] { 0, 0m };
+ yield return new object[] { 123, 123m };
+ yield return new object[] { long.MaxValue, (decimal)long.MaxValue };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(Decimal_I8_TestData))]
+ public void VARIANT_ToObject_DecimalI8_ReturnsExpected(long i8, decimal expected)
+ {
+ VarDecFromI8(i8, out DECIMAL d);
+ VARIANT_ToObject_Decimal_ReturnsExpected(d, expected);
+ VARIANT_ToObject_DecimalBYREF_ReturnsExpected(d, expected);
+ }
+
+ public static IEnumerable Decimal_R8_TestData()
+ {
+ yield return new object[] { -10e12, -10e12m };
+ yield return new object[] { -123.456, -123.456m };
+ yield return new object[] { 0.0, 0m };
+ yield return new object[] { 123.456, 123.456m };
+ yield return new object[] { 10e12, 10e12m };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(Decimal_R8_TestData))]
+ public void VARIANT_ToObject_DecimalR8_ReturnsExpected(double r8, decimal expected)
+ {
+ VarDecFromR8(r8, out DECIMAL d);
+ VARIANT_ToObject_Decimal_ReturnsExpected(d, expected);
+ VARIANT_ToObject_DecimalBYREF_ReturnsExpected(d, expected);
+ }
+
+ public static IEnumerable Decimal_TestData()
+ {
+ yield return new object[] { new DECIMAL(), 0.0m };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(Decimal_TestData))]
+ public void VARIANT_ToObject_Decimal_ReturnsExpected(object d, decimal expected)
+ {
+ var variant = new VARIANT();
+ *(DECIMAL*)(&variant) = (DECIMAL)d;
+ variant.vt = VARENUM.DECIMAL;
+ AssertToObjectEqual(expected, variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(Decimal_TestData))]
+ public void VARIANT_ToObject_DecimalBYREF_ReturnsExpected(object d, decimal expected)
+ {
+ DECIMAL asD = (DECIMAL)d;
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.DECIMAL | VARENUM.BYREF,
+ data = new VARIANT.VARIANTUnion
+ {
+ pdecVal = &asD
+ }
+ };
+ AssertToObjectEqual(expected, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_CLSID_ReturnsExpected()
+ {
+ var guid = Guid.NewGuid();
+ using var variant = new VARIANT();
+ HRESULT hr = InitPropVariantFromCLSID(&guid, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.CLSID, variant.Type);
+
+ AssertToObjectEqualExtension(guid, variant);
+ }
+
+ public static IEnumerable VOID_TestData()
+ {
+ yield return new object[] { IntPtr.Zero };
+ yield return new object[] { (IntPtr)1 };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VOID_TestData))]
+ public void VARIANT_ToObject_VOID_ReturnsExpected(IntPtr data)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VOID,
+ data = new VARIANT.VARIANTUnion
+ {
+ punkVal = data
+ }
+ };
+ IntPtr pv = (IntPtr)(&variant);
+ Assert.Null(Marshal.GetObjectForNativeVariant(pv));
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.USERDEFINED)]
+ [InlineData((ushort)(VARENUM.USERDEFINED | VARENUM.BYREF))]
+ public void VARIANT_ToObject_USERDATA_ThrowsArgumentException(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)(VARENUM.VOID | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.PTR)]
+ [InlineData((ushort)(VARENUM.PTR | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.SAFEARRAY)]
+ [InlineData((ushort)(VARENUM.SAFEARRAY | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.CARRAY)]
+ [InlineData((ushort)(VARENUM.CARRAY | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.RECORD)]
+ [InlineData((ushort)(VARENUM.RECORD | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.BLOB)]
+ [InlineData((ushort)(VARENUM.BLOB | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.STREAM)]
+ [InlineData((ushort)(VARENUM.STREAM | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.STORAGE)]
+ [InlineData((ushort)(VARENUM.STORAGE | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.STREAMED_OBJECT)]
+ [InlineData((ushort)(VARENUM.STREAMED_OBJECT | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.STORED_OBJECT)]
+ [InlineData((ushort)(VARENUM.STORED_OBJECT | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.BLOB_OBJECT)]
+ [InlineData((ushort)(VARENUM.BLOB_OBJECT | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.CF)]
+ [InlineData((ushort)(VARENUM.CF | VARENUM.BYREF))]
+ [InlineData((ushort)(VARENUM.BSTR_BLOB | VARENUM.BYREF))]
+ [InlineData((ushort)VARENUM.ILLEGAL)]
+ [InlineData((ushort)VARENUM.INT_PTR)]
+ [InlineData((ushort)VARENUM.UINT_PTR)]
+ [InlineData(127)]
+ [InlineData(0x000F)]
+ [InlineData(0x0020)]
+ [InlineData(0x0021)]
+ [InlineData(0x0022)]
+ [InlineData(0x0023)]
+ [InlineData(0x0024)]
+ public void VARIANT_ToObject_CantConvert_ThrowsArgumentException(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [InlineData(128)]
+ [InlineData(129)]
+ [InlineData((ushort)VARENUM.BSTR_BLOB)]
+ public void VARIANT_ToObject_Illegal_ThrowsInvalidOleVariantTypeException(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = (VARENUM)vt
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ public static IEnumerable VectorI1_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new sbyte[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI1_TestData))]
+ public void VARIANT_ToObject_VECTORI1_ReturnsExpected(sbyte[] result)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (sbyte* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromBuffer(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI1, variant.vt);
+ }
+
+ // I1 and UI1 have the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.I1;
+ AssertToObjectEqualExtension(result, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORI1NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.I1
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorUI1_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new byte[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI1_TestData))]
+ public void VARIANT_ToObject_VECTORUI1_ReturnsExpected(byte[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (byte* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromBuffer(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI1, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORUI1NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.UI1
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorI2_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new short[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI2_TestData))]
+ public void VARIANT_ToObject_VECTORI2_ReturnsExpected(short[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (short* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromInt16Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I2, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORI2NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.I2
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorUI2_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new ushort[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI2_TestData))]
+ public void VARIANT_ToObject_VECTORUI2_ReturnsExpected(ushort[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (ushort* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromUInt16Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI2, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORUI2NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.UI2
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorBOOL_TestData()
+ {
+ yield return new object[] { Array.Empty(), Array.Empty() };
+ yield return new object[] { new BOOL[] { BOOL.TRUE, BOOL.FALSE, BOOL.TRUE }, new bool[] { true, false, true } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorBOOL_TestData))]
+ public void VARIANT_ToObject_VECTORBOOL_ReturnsExpected(object result, bool[] expected)
+ {
+ using var variant = new VARIANT();
+ BOOL[] boolResult = (BOOL[])result;
+ fixed (BOOL* pResult = boolResult)
+ {
+ HRESULT hr = InitPropVariantFromBooleanVector(pResult, (uint)boolResult.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.BOOL, variant.vt);
+ }
+
+ AssertToObjectEqualExtension(expected, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORBOOLNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.BOOL
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorI4_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new int[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI4_TestData))]
+ public void VARIANT_ToObject_VECTORI4_ReturnsExpected(int[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (int* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I4, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORI4NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.I4
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorUI4_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new uint[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI4_TestData))]
+ public void VARIANT_ToObject_VECTORUI4_ReturnsExpected(uint[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (uint* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromUInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI4, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORUI4NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.UI4
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorINT_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new int[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorINT_TestData))]
+ public void VARIANT_ToObject_VECTORINT_ReturnsExpected(int[] result)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (int* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I4, variant.vt);
+ }
+
+ // I4 and INT have the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.INT;
+ AssertToObjectEqualExtension(result, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORINTNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.INT
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorUINT_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new uint[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUINT_TestData))]
+ public void VARIANT_ToObject_VECTORUINT_ReturnsExpected(uint[] result)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (uint* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromUInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI4, variant.vt);
+ }
+
+ // UI4 and UINT have the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.UINT;
+ AssertToObjectEqualExtension(result, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORUINTNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.UINT
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorI8_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new long[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI8_TestData))]
+ public void VARIANT_ToObject_VECTORI8_ReturnsExpected(long[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (long* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromInt64Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I8, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORI8NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.I8
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorUI8_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new ulong[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI8_TestData))]
+ public void VARIANT_ToObject_VECTORUI8_ReturnsExpected(ulong[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (ulong* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromUInt64Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI8, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORUI8NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.UI8
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorR4_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new float[] { 1.1f, 2.2f, 3.3f } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorR4_TestData))]
+ public void VARIANT_ToObject_VECTORR4_ReturnsExpected(float[] result)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (float* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I4, variant.vt);
+ }
+
+ // I4 and R4 are the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.R4;
+ AssertToObjectEqualExtension(result, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORR4NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.R4
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorR8_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new double[] { 1.1, 2.2, 3.3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorR8_TestData))]
+ public void VARIANT_ToObject_VECTORR8_ReturnsExpected(double[] result)
+ {
+ using var variant = new VARIANT();
+ fixed (double* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromDoubleVector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.R8, variant.vt);
+ }
+ AssertToObjectEqualExtension(result, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORR8NoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.R8
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorERROR_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new uint[] { 1, 2, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorERROR_TestData))]
+ public void VARIANT_ToObject_VECTORERROR_ReturnsExpected(uint[] result)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (uint* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromUInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI4, variant.vt);
+ }
+
+ // UI4 and ERROR are the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.ERROR;
+ AssertToObjectEqualExtension(result, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORERRORNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.ERROR
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorCY_TestData()
+ {
+ yield return new object[] { Array.Empty(), Array.Empty() };
+ yield return new object[] { new long[] { 11000, 22000, 30000 } , new decimal[] { 1.1m, 2.2m, 3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorCY_TestData))]
+ public void VARIANT_ToObject_VECTORCY_ReturnsExpected(long[] result, decimal[] expected)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (long* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromInt64Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I8, variant.vt);
+ }
+
+ // I8 and CY have the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.CY;
+ AssertToObjectEqualExtension(expected, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORCYNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.CY
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorDATE_TestData()
+ {
+ yield return new object[] { Array.Empty(), Array.Empty() };
+
+ var d1 = new DateTime(2020, 05, 13, 13, 3, 12);
+ var d2 = new DateTime(2020, 05, 13, 13, 3, 11);
+ var d3 = new DateTime(2020, 3, 13, 13, 3, 12);
+ yield return new object[] { new double[] { d1.ToOADate(), d2.ToOADate(), d3.ToOADate() }, new DateTime[] { d1, d2, d3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorDATE_TestData))]
+ public void VARIANT_ToObject_VECTORDATE_ReturnsExpected(double[] result, DateTime[] expected)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (double* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromDoubleVector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.R8, variant.vt);
+ }
+
+ // R8 and DATE have the same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.DATE;
+ AssertToObjectEqualExtension(expected, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORDATENoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.DATE
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorFILETIME_TestData()
+ {
+ yield return new object[] { Array.Empty(), Array.Empty() };
+
+ var d1 = new DateTime(2020, 05, 13, 13, 3, 12);
+ var d2 = new DateTime(2020, 05, 13, 13, 3, 11);
+ var d3 = new DateTime(2020, 3, 13, 13, 3, 12);
+ yield return new object[] { new FILETIME[] { new FILETIME(d1), new FILETIME(d2), new FILETIME(d3) }, new DateTime[] { d1, d2, d3 } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorFILETIME_TestData))]
+ public void VARIANT_ToObject_VECTORFILETIME_ReturnsExpected(object result, DateTime[] expected)
+ {
+ using var variant = new VARIANT();
+ FILETIME[] fileTimeResult = (FILETIME[])result;
+ fixed (FILETIME* pResult = fileTimeResult)
+ {
+ HRESULT hr = InitPropVariantFromFileTimeVector(pResult, (uint)fileTimeResult.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.FILETIME, variant.vt);
+ }
+
+ AssertToObjectEqualExtension(expected, variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORFILETIMENoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.FILETIME
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ public static IEnumerable VectorCLSID_TestData()
+ {
+ yield return new object[] { Array.Empty() };
+ yield return new object[] { new Guid[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorCLSID_TestData))]
+ public void VARIANT_ToObject_VECTORCLSID_ReturnsExpected(Guid[] result)
+ {
+ var variant = new VARIANT();
+ try
+ {
+ fixed (Guid* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromBuffer(pResult, (uint)(result.Length * sizeof(Guid)), &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI1, variant.vt);
+ }
+
+ variant.data.ca.cElems = (uint)(variant.data.ca.cElems / sizeof(Guid));
+ variant.vt = VARENUM.VECTOR | VARENUM.CLSID;
+ AssertToObjectEqualExtension(result, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORCLSIDNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.CLSID
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORBSTR_ReturnsExpected()
+ {
+ var variant = new VARIANT();
+ IntPtr ptr1 = Marshal.StringToBSTR("text");
+ IntPtr ptr2 = Marshal.StringToBSTR("");
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ fixed (IntPtr* pResult = result)
+ {
+ if (IntPtr.Size == 4)
+ {
+ HRESULT hr = InitPropVariantFromInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I4, variant.vt);
+ }
+ else
+ {
+ HRESULT hr = InitPropVariantFromInt64Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I8, variant.vt);
+ }
+ }
+
+ // I4/I8 and BSTR have same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.BSTR;
+ AssertToObjectEqualExtension(new string[] { null, "text", "" }, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORBSTRNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.BSTR
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORLPWSTR_ReturnsExpected()
+ {
+ var variant = new VARIANT();
+ IntPtr ptr1 = Marshal.StringToCoTaskMemUni("text");
+ IntPtr ptr2 = Marshal.StringToCoTaskMemUni("");
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ fixed (IntPtr* pResult = result)
+ {
+ if (IntPtr.Size == 4)
+ {
+ HRESULT hr = InitPropVariantFromInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I4, variant.vt);
+ }
+ else
+ {
+ HRESULT hr = InitPropVariantFromInt64Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I8, variant.vt);
+ }
+ }
+
+ // I4/I8 and LPWSTR have same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.LPWSTR;
+ AssertToObjectEqualExtension(new string[] { null, "text", "" }, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORLPWSTRNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.LPWSTR
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORLPSTR_ReturnsExpected()
+ {
+ var variant = new VARIANT();
+ IntPtr ptr1 = Marshal.StringToCoTaskMemAnsi("text");
+ IntPtr ptr2 = Marshal.StringToCoTaskMemAnsi("");
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ fixed (IntPtr* pResult = result)
+ {
+ if (IntPtr.Size == 4)
+ {
+ HRESULT hr = InitPropVariantFromInt32Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I4, variant.vt);
+ }
+ else
+ {
+ HRESULT hr = InitPropVariantFromInt64Vector(pResult, (uint)result.Length, &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.I8, variant.vt);
+ }
+ }
+
+ // I4/I8 and LPSTR have same size.
+ variant.vt = VARENUM.VECTOR | VARENUM.LPSTR;
+ AssertToObjectEqualExtension(new string[] { null, "text", "" }, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORLPSTRNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.LPSTR
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORVARIANT_ReturnsExpected()
+ {
+ var variant = new VARIANT();
+ try
+ {
+ var variant1 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ lVal = 1
+ }
+ };
+ var variant2 = new VARIANT
+ {
+ vt = VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ ulVal = 2
+ }
+ };
+ var result = new VARIANT[] { variant1, variant2 };
+ fixed (VARIANT* pResult = result)
+ {
+ HRESULT hr = InitPropVariantFromBuffer(pResult, (uint)(result.Length * sizeof(VARIANT)), &variant);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(VARENUM.VECTOR | VARENUM.UI1, variant.vt);
+ }
+
+ variant.data.ca.cElems = (uint)(variant.data.ca.cElems / sizeof(VARIANT));
+ variant.vt = VARENUM.VECTOR | VARENUM.VARIANT;
+ AssertToObjectEqualExtension(new object[] { 1, 2u }, variant);
+ }
+ finally
+ {
+ variant.Dispose();
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_VECTORVARIANTNoData_ReturnsExpected()
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | VARENUM.VARIANT
+ };
+ AssertToObjectEqualExtension(Array.Empty(), variant);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.EMPTY)]
+ [InlineData((ushort)VARENUM.DECIMAL)]
+ [InlineData((ushort)VARENUM.UNKNOWN)]
+ [InlineData((ushort)VARENUM.DISPATCH)]
+ [InlineData((ushort)VARENUM.NULL)]
+ [InlineData((ushort)VARENUM.CF)]
+ [InlineData((ushort)VARENUM.VOID)]
+ [InlineData((ushort)VARENUM.PTR)]
+ [InlineData((ushort)VARENUM.SAFEARRAY)]
+ [InlineData((ushort)VARENUM.CARRAY)]
+ [InlineData((ushort)VARENUM.RECORD)]
+ [InlineData((ushort)VARENUM.BLOB)]
+ [InlineData((ushort)VARENUM.STREAM)]
+ [InlineData((ushort)VARENUM.STORAGE)]
+ [InlineData((ushort)VARENUM.STREAMED_OBJECT)]
+ [InlineData((ushort)VARENUM.STORED_OBJECT)]
+ [InlineData((ushort)VARENUM.BLOB_OBJECT)]
+ [InlineData(127)]
+ [InlineData(0x000F)]
+ [InlineData(0x0020)]
+ [InlineData(0x0021)]
+ [InlineData(0x0022)]
+ [InlineData(0x0023)]
+ [InlineData(0x0024)]
+ public void VARIANT_ToObject_VECTORInvalidType_ThrowsArgumentException(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | (VARENUM)vt
+ };
+ Assert.Throws(null, () => variant.ToObject());
+ }
+
+ [StaTheory]
+ [InlineData(128)]
+ [InlineData(129)]
+ [InlineData((ushort)VARENUM.BSTR_BLOB)]
+ public void VARIANT_ToObject_VECTORInvalidTypeNoData_ThrowsInvalidOleVariantTypeException(ushort vt)
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.VECTOR | (VARENUM)vt
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI1_TestData))]
+ public void VARIANT_ToObject_ARRAYUI1SingleDimension_ReturnsExpected(byte[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI1, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI1_TestData))]
+ public void VARIANT_ToObject_ARRAYUI1SingleDimensionNonZeroLowerBounds_ReturnsExpected(byte[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI1, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(byte).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionUI1_TestData()
+ {
+ yield return new object[] { new byte[0,0] };
+ yield return new object[] { new byte[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI1_TestData))]
+ public void VARIANT_ToObject_ARRAYUI1MultiDimension_ReturnsExpected(byte[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI1, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(byte).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI1_TestData))]
+ public void VARIANT_ToObject_ARRAYUI1MultiDimensionNonZeroLowerBound_ReturnsExpected(byte[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI1, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(byte).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI1_TestData))]
+ public void VARIANT_ToObject_ARRAYI1SingleDimension_ReturnsExpected(sbyte[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I1, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI1_TestData))]
+ public void VARIANT_ToObject_ARRAYI1SingleDimensionNonZeroLowerBounds_ReturnsExpected(sbyte[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I1, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(sbyte).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionI1_TestData()
+ {
+ yield return new object[] { new sbyte[0,0] };
+ yield return new object[] { new sbyte[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI1_TestData))]
+ public void VARIANT_ToObject_ARRAYI1MultiDimension_ReturnsExpected(sbyte[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I1, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(sbyte).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI1_TestData))]
+ public void VARIANT_ToObject_ARRAYI1MultiDimensionNonZeroLowerBound_ReturnsExpected(sbyte[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I1, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I1,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(sbyte).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI2_TestData))]
+ public void VARIANT_ToObject_ARRAYI2SingleDimension_ReturnsExpected(short[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I2, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI2_TestData))]
+ public void VARIANT_ToObject_ARRAYI2SingleDimensionNonZeroLowerBounds_ReturnsExpected(short[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I2, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(short).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionI2_TestData()
+ {
+ yield return new object[] { new short[0,0] };
+ yield return new object[] { new short[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI2_TestData))]
+ public void VARIANT_ToObject_ARRAYI2MultiDimension_ReturnsExpected(short[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I2, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(short).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI2_TestData))]
+ public void VARIANT_ToObject_ARRAYI2MultiDimensionNonZeroLowerBound_ReturnsExpected(short[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I2, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(short).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI2_TestData))]
+ public void VARIANT_ToObject_ARRAYUI2SingleDimension_ReturnsExpected(ushort[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI2, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI2_TestData))]
+ public void VARIANT_ToObject_ARRAYUI2SingleDimensionNonZeroLowerBounds_ReturnsExpected(ushort[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI2, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(ushort).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionUI2_TestData()
+ {
+ yield return new object[] { new ushort[0,0] };
+ yield return new object[] { new ushort[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI2_TestData))]
+ public void VARIANT_ToObject_ARRAYUI2MultiDimension_ReturnsExpected(ushort[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI2, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(ushort).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI2_TestData))]
+ public void VARIANT_ToObject_ARRAYUI2MultiDimensionNonZeroLowerBound_ReturnsExpected(ushort[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI2, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI2,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(ushort).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI4_TestData))]
+ public void VARIANT_ToObject_ARRAYI4SingleDimension_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI4_TestData))]
+ public void VARIANT_ToObject_ARRAYI4SingleDimensionNonZeroLowerBounds_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionI4_TestData()
+ {
+ yield return new object[] { new int[0,0] };
+ yield return new object[] { new int[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI4_TestData))]
+ public void VARIANT_ToObject_ARRAYI4MultiDimension_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI4_TestData))]
+ public void VARIANT_ToObject_ARRAYI4MultiDimensionNonZeroLowerBound_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI4_TestData))]
+ public void VARIANT_ToObject_INTArrayI4SingleDimension_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI4_TestData))]
+ public void VARIANT_ToObject_INTArrayI4SingleDimensionNonZeroLowerBounds_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI4_TestData))]
+ public void VARIANT_ToObject_INTArrayI4MultiDimension_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI4_TestData))]
+ public void VARIANT_ToObject_INTArrayI4MultiDimensionNonZeroLowerBound_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI4_TestData))]
+ public void VARIANT_ToObject_ARRAYUI4SingleDimension_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI4_TestData))]
+ public void VARIANT_ToObject_ARRAYUI4SingleDimensionNonZeroLowerBounds_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionUI4_TestData()
+ {
+ yield return new object[] { new uint[0,0] };
+ yield return new object[] { new uint[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI4_TestData))]
+ public void VARIANT_ToObject_ARRAYUI4MultiDimension_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI4_TestData))]
+ public void VARIANT_ToObject_ARRAYUI4MultiDimensionNonZeroLowerBound_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI4_TestData))]
+ public void VARIANT_ToObject_UINTArrayUI4SingleDimension_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI4_TestData))]
+ public void VARIANT_ToObject_UINTArrayUI4SingleDimensionNonZeroLowerBounds_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI4_TestData))]
+ public void VARIANT_ToObject_UINTArrayUI4MultiDimension_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI4_TestData))]
+ public void VARIANT_ToObject_UINTArrayUI4MultiDimensionNonZeroLowerBound_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorINT_TestData))]
+ public void VARIANT_ToObject_ARRAYINTSingleDimension_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorINT_TestData))]
+ public void VARIANT_ToObject_ARRAYINTSingleDimensionNonZeroLowerBounds_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionINT_TestData()
+ {
+ yield return new object[] { new int[0,0] };
+ yield return new object[] { new int[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionINT_TestData))]
+ public void VARIANT_ToObject_ARRAYINTMultiDimension_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionINT_TestData))]
+ public void VARIANT_ToObject_ARRAYINTMultiDimensionNonZeroLowerBound_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.INT, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorINT_TestData))]
+ public void VARIANT_ToObject_I4ArrayINTSingleDimension_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorINT_TestData))]
+ public void VARIANT_ToObject_I4ArrayINTSingleDimensionNonZeroLowerBounds_ReturnsExpected(int[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionINT_TestData))]
+ public void VARIANT_ToObject_I4ArrayINTMultiDimension_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionINT_TestData))]
+ public void VARIANT_ToObject_I4ArrayINTMultiDimensionNonZeroLowerBound_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I4, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.INT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(int).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUINT_TestData))]
+ public void VARIANT_ToObject_ARRAYUINTSingleDimension_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUINT_TestData))]
+ public void VARIANT_ToObject_ARRAYUINTSingleDimensionNonZeroLowerBounds_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionUINT_TestData()
+ {
+ yield return new object[] { new uint[0,0] };
+ yield return new object[] { new uint[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUINT_TestData))]
+ public void VARIANT_ToObject_ARRAYUINTMultiDimension_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUINT_TestData))]
+ public void VARIANT_ToObject_ARRAYUINTMultiDimensionNonZeroLowerBound_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UINT, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUINT_TestData))]
+ public void VARIANT_ToObject_UI4ArrayUINTSingleDimension_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUINT_TestData))]
+ public void VARIANT_ToObject_UI4ArrayUINTSingleDimensionNonZeroLowerBounds_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUINT_TestData))]
+ public void VARIANT_ToObject_UI4ArrayUINTMultiDimension_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUINT_TestData))]
+ public void VARIANT_ToObject_UI4ArrayUINTMultiDimensionNonZeroLowerBound_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI4, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UINT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI8_TestData))]
+ public void VARIANT_ToObject_ARRAYI8SingleDimension_ReturnsExpected(long[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I8, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorI8_TestData))]
+ public void VARIANT_ToObject_ARRAYI8SingleDimensionNonZeroLowerBounds_ReturnsExpected(long[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I8, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(long).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionI8_TestData()
+ {
+ yield return new object[] { new long[0,0] };
+ yield return new object[] { new long[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI8_TestData))]
+ public void VARIANT_ToObject_ARRAYI8MultiDimension_ReturnsExpected(long[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I8, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(long).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionI8_TestData))]
+ public void VARIANT_ToObject_ARRAYI8MultiDimensionNonZeroLowerBound_ReturnsExpected(long[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.I8, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(long).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI8_TestData))]
+ public void VARIANT_ToObject_ARRAYUI8SingleDimension_ReturnsExpected(ulong[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI8, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorUI8_TestData))]
+ public void VARIANT_ToObject_ARRAYUI8SingleDimensionNonZeroLowerBounds_ReturnsExpected(ulong[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI8, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(ulong).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionUI8_TestData()
+ {
+ yield return new object[] { new ulong[0,0] };
+ yield return new object[] { new ulong[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI8_TestData))]
+ public void VARIANT_ToObject_ARRAYUI8MultiDimension_ReturnsExpected(ulong[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI8, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(ulong).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionUI8_TestData))]
+ public void VARIANT_ToObject_ARRAYUI8MultiDimensionNonZeroLowerBound_ReturnsExpected(ulong[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UI8, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UI8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(ulong).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorR4_TestData))]
+ public void VARIANT_ToObject_ARRAYR4SingleDimension_ReturnsExpected(float[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorR4_TestData))]
+ public void VARIANT_ToObject_ARRAYR4SingleDimensionNonZeroLowerBounds_ReturnsExpected(float[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R4, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(float).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionR4_TestData()
+ {
+ yield return new object[] { new float[0,0] };
+ yield return new object[] { new float[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionR4_TestData))]
+ public void VARIANT_ToObject_ARRAYR4MultiDimension_ReturnsExpected(float[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R4, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(float).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionR4_TestData))]
+ public void VARIANT_ToObject_ARRAYR4MultiDimensionNonZeroLowerBound_ReturnsExpected(float[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R4, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(float).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorR8_TestData))]
+ public void VARIANT_ToObject_ARRAYR8SingleDimension_ReturnsExpected(double[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R8, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorR8_TestData))]
+ public void VARIANT_ToObject_ARRAYR8SingleDimensionNonZeroLowerBounds_ReturnsExpected(double[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R8, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(double).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionR8_TestData()
+ {
+ yield return new object[] { new double[0,0] };
+ yield return new object[] { new double[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionR8_TestData))]
+ public void VARIANT_ToObject_ARRAYR8MultiDimension_ReturnsExpected(double[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R8, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(double).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionR8_TestData))]
+ public void VARIANT_ToObject_ARRAYR8MultiDimensionNonZeroLowerBound_ReturnsExpected(double[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.R8, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.R8,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(double).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorERROR_TestData))]
+ public void VARIANT_ToObject_ARRAYERRORSingleDimension_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.ERROR, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.ERROR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorERROR_TestData))]
+ public void VARIANT_ToObject_ARRAYERRORSingleDimensionNonZeroLowerBounds_ReturnsExpected(uint[] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.ERROR, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.ERROR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionERROR_TestData()
+ {
+ yield return new object[] { new uint[0,0] };
+ yield return new object[] { new uint[2,3] { { 1, 2, 3 }, { 4, 5, 6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionERROR_TestData))]
+ public void VARIANT_ToObject_ARRAYERRORMultiDimension_ReturnsExpected(uint[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.ERROR, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.ERROR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionERROR_TestData))]
+ public void VARIANT_ToObject_ARRAYERRORMultiDimensionNonZeroLowerBound_ReturnsExpected(int[,] result)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.ERROR, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.ERROR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(uint).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(result, array);
+ });
+ }
+
+ public static IEnumerable ArrayBOOL_TestData()
+ {
+ yield return new object[] { Array.Empty(), Array.Empty() };
+ yield return new object[] { new VARIANT_BOOL[] { VARIANT_BOOL.TRUE, VARIANT_BOOL.FALSE, VARIANT_BOOL.TRUE }, new bool[] { true, false, true } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(ArrayBOOL_TestData))]
+ public void VARIANT_ToObject_ARRAYBOOLSingleDimension_ReturnsExpected(object result, bool[] expected)
+ {
+ VARIANT_BOOL[] boolResult = (VARIANT_BOOL[])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BOOL, boolResult);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BOOL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(ArrayBOOL_TestData))]
+ public void VARIANT_ToObject_ARRAYBOOLSingleDimensionNonZeroLowerBounds_ReturnsExpected(object result, bool[] expected)
+ {
+ VARIANT_BOOL[] boolResult = (VARIANT_BOOL[])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BOOL, boolResult, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BOOL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(bool).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionBOOL_TestData()
+ {
+ yield return new object[] { new VARIANT_BOOL[0,0], new bool[0,0] };
+ yield return new object[] { new VARIANT_BOOL[2, 3] { { VARIANT_BOOL.TRUE, VARIANT_BOOL.FALSE, VARIANT_BOOL.TRUE }, { VARIANT_BOOL.FALSE, VARIANT_BOOL.TRUE, VARIANT_BOOL.FALSE } }, new bool[2,3] { { true, false, true }, { false, true, false } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionBOOL_TestData))]
+ public void VARIANT_ToObject_ARRAYBOOLMultiDimension_ReturnsExpected(object result, bool[,] expected)
+ {
+ VARIANT_BOOL[,] boolResult = (VARIANT_BOOL[,])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BOOL, boolResult);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BOOL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(bool).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionBOOL_TestData))]
+ public void VARIANT_ToObject_ARRAYBOOLMultiDimensionNonZeroLowerBound_ReturnsExpected(object result, bool[,] expected)
+ {
+ VARIANT_BOOL[,] boolResult = (VARIANT_BOOL[,])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BOOL, boolResult, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BOOL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(bool).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ public static IEnumerable ArrayDECIMAL_TestData()
+ {
+ yield return new object[] { Array.Empty(), Array.Empty() };
+
+ VarDecFromR8(1.1, out DECIMAL d1);
+ VarDecFromR8(2.2, out DECIMAL d2);
+ VarDecFromR8(3.3, out DECIMAL d3);
+ yield return new object[] { new DECIMAL[] { d1, d2, d3 }, new decimal[] { 1.1m, 2.2m, 3.3m } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(ArrayDECIMAL_TestData))]
+ public void VARIANT_ToObject_ARRAYDECIMALSingleDimension_ReturnsExpected(object result, decimal[] expected)
+ {
+ DECIMAL[] decimalResult = (DECIMAL[])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DECIMAL, decimalResult);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DECIMAL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(ArrayDECIMAL_TestData))]
+ public void VARIANT_ToObject_ARRAYDECIMALSingleDimensionNonZeroLowerBounds_ReturnsExpected(object result, decimal[] expected)
+ {
+ DECIMAL[] decimalResult = (DECIMAL[])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DECIMAL, decimalResult, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DECIMAL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(decimal).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionDECIMAL_TestData()
+ {
+ yield return new object[] { new DECIMAL[0,0], new decimal[0,0] };
+ VarDecFromR8(1.1, out DECIMAL d1);
+ VarDecFromR8(2.2, out DECIMAL d2);
+ VarDecFromR8(3.3, out DECIMAL d3);
+ VarDecFromR8(3.1, out DECIMAL d4);
+ VarDecFromR8(2.2, out DECIMAL d5);
+ VarDecFromR8(1.3, out DECIMAL d6);
+ yield return new object[] { new DECIMAL[2, 3] { { d1, d2, d3 }, { d4, d5, d6 } }, new decimal[2,3] { { 1.1m, 2.2m, 3.3m }, { 3.1m, 2.2m, 1.3m } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionDECIMAL_TestData))]
+ public void VARIANT_ToObject_ARRAYDECIMALMultiDimension_ReturnsExpected(object result, decimal[,] expected)
+ {
+ DECIMAL[,] decimalResult = (DECIMAL[,])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DECIMAL, decimalResult);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DECIMAL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(decimal).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionDECIMAL_TestData))]
+ public void VARIANT_ToObject_ARRAYDECIMALMultiDimensionNonZeroLowerBound_ReturnsExpected(object result, decimal[,] expected)
+ {
+ DECIMAL[,] decimalResult = (DECIMAL[,])result;
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DECIMAL, decimalResult, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DECIMAL,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(decimal).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorCY_TestData))]
+ public void VARIANT_ToObject_ARRAYCYSingleDimension_ReturnsExpected(long[] result, decimal[] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.CY, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.CY,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorCY_TestData))]
+ public void VARIANT_ToObject_ARRAYCYSingleDimensionNonZeroLowerBounds_ReturnsExpected(long[] result, decimal[] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.CY, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.CY,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(decimal).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionCY_TestData()
+ {
+ yield return new object[] { new long[0,0], new decimal[0,0] };
+ yield return new object[] { new long[2, 3] { { 11000, 22000, 33000 }, { 31000, 22000, 13000 } }, new decimal[2,3] { { 1.1m, 2.2m, 3.3m }, { 3.1m, 2.2m, 1.3m } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionCY_TestData))]
+ public void VARIANT_ToObject_ARRAYCYMultiDimension_ReturnsExpected(long[,] result, decimal[,] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.CY, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.CY,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(decimal).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionCY_TestData))]
+ public void VARIANT_ToObject_ARRAYCYMultiDimensionNonZeroLowerBound_ReturnsExpected(long[,] result, decimal[,] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.CY, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.CY,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(decimal).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorDATE_TestData))]
+ public void VARIANT_ToObject_ARRAYDATESingleDimension_ReturnsExpected(double[] result, DateTime[] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DATE, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DATE,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(VectorDATE_TestData))]
+ public void VARIANT_ToObject_ARRAYDATESingleDimensionNonZeroLowerBounds_ReturnsExpected(double[] result, DateTime[] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DATE, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DATE,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(DateTime).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(expected.Length, array.GetLength(0));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ public static IEnumerable MultiDimensionDATE_TestData()
+ {
+ yield return new object[] { new double[0,0], new DateTime[0,0] };
+
+ var d1 = new DateTime(2020, 05, 13, 13, 3, 12);
+ var d2 = new DateTime(2020, 05, 13, 13, 3, 11);
+ var d3 = new DateTime(2020, 3, 13, 13, 3, 12);
+ var d4 = new DateTime(1892, 1, 2, 3, 4, 5, 6);
+ var d5 = new DateTime(2010, 2, 3, 4, 5, 6);
+ var d6 = new DateTime(8000, 10, 11, 12, 13, 14);
+ yield return new object[] { new double[2, 3] { { d1.ToOADate(), d2.ToOADate(), d3.ToOADate() }, { d4.ToOADate(), d5.ToOADate(), d6.ToOADate() } }, new DateTime[2,3] { { d1, d2, d3 }, { d4, d5, d6 } } };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionDATE_TestData))]
+ public void VARIANT_ToObject_ARRAYDATEMultiDimension_ReturnsExpected(double[,] result, DateTime[,] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DATE, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DATE,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(DateTime).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaTheory]
+ [MemberData(nameof(MultiDimensionDATE_TestData))]
+ public void VARIANT_ToObject_ARRAYDATEMultiDimensionNonZeroLowerBound_ReturnsExpected(double[,] result, DateTime[,] expected)
+ {
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DATE, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DATE,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(DateTime).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(expected.GetLength(0), array.GetLength(0));
+ Assert.Equal(expected.GetLength(1), array.GetLength(1));
+ Assert.Equal(expected, array);
+ });
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYBSTRSingleDimension_ReturnsExpected()
+ {
+ IntPtr ptr1 = Marshal.StringToBSTR("text");
+ IntPtr ptr2 = Marshal.StringToBSTR("");
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BSTR, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new string[] { null, "text", "" }, array);
+ });
+ }
+ finally
+ {
+ Marshal.FreeBSTR(ptr1);
+ Marshal.FreeBSTR(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYBSTRSingleDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ IntPtr ptr1 = Marshal.StringToBSTR("text");
+ IntPtr ptr2 = Marshal.StringToBSTR("");
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BSTR, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(string).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new string[] { null, "text", "" }, array);
+ });
+ }
+ finally
+ {
+ Marshal.FreeBSTR(ptr1);
+ Marshal.FreeBSTR(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYBSTRMultiDimension_ReturnsExpected()
+ {
+ IntPtr ptr1 = Marshal.StringToBSTR("text");
+ IntPtr ptr2 = Marshal.StringToBSTR("");
+ IntPtr ptr3 = Marshal.StringToBSTR("text3");
+ IntPtr ptr4 = Marshal.StringToBSTR("text4");
+ IntPtr ptr5 = Marshal.StringToBSTR("text5");
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BSTR, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(string).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new string[,] { { null, "text", "" }, { "text3", "text4", "text5" } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.FreeBSTR(ptr1);
+ Marshal.FreeBSTR(ptr2);
+ Marshal.FreeBSTR(ptr3);
+ Marshal.FreeBSTR(ptr4);
+ Marshal.FreeBSTR(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYBSTRMultiDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ IntPtr ptr1 = Marshal.StringToBSTR("text");
+ IntPtr ptr2 = Marshal.StringToBSTR("");
+ IntPtr ptr3 = Marshal.StringToBSTR("text3");
+ IntPtr ptr4 = Marshal.StringToBSTR("text4");
+ IntPtr ptr5 = Marshal.StringToBSTR("text5");
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.BSTR, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.BSTR,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(string).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new string[,] { { null, "text", "" }, { "text3", "text4", "text5" } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.FreeBSTR(ptr1);
+ Marshal.FreeBSTR(ptr2);
+ Marshal.FreeBSTR(ptr3);
+ Marshal.FreeBSTR(ptr4);
+ Marshal.FreeBSTR(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYUNKNOWNSingleDimension_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UNKNOWN, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { null, o1, o2 }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYUNKNOWNSingleDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UNKNOWN, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { null, o1, o2 }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYUNKNOWNMultiDimension_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ var o3 = new object();
+ var o4 = new object();
+ var o5 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ IntPtr ptr3 = Marshal.GetIUnknownForObject(o3);
+ IntPtr ptr4 = Marshal.GetIUnknownForObject(o4);
+ IntPtr ptr5 = Marshal.GetIUnknownForObject(o5);
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UNKNOWN, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { null, o1, o2 }, { o3, o4, o5 } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ Marshal.Release(ptr3);
+ Marshal.Release(ptr4);
+ Marshal.Release(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYUNKNOWNMultiDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ var o3 = new object();
+ var o4 = new object();
+ var o5 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ IntPtr ptr3 = Marshal.GetIUnknownForObject(o3);
+ IntPtr ptr4 = Marshal.GetIUnknownForObject(o4);
+ IntPtr ptr5 = Marshal.GetIUnknownForObject(o5);
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.UNKNOWN, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { null, o1, o2 }, { o3, o4, o5 } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ Marshal.Release(ptr3);
+ Marshal.Release(ptr4);
+ Marshal.Release(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DISPATCHArrayUNKNOWNSingleDimension_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { null, o1, o2 }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DISPATCHArrayUNKNOWNSingleDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { null, o1, o2 }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DISPATCHArrayUNKNOWNMultiDimension_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ var o3 = new object();
+ var o4 = new object();
+ var o5 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ IntPtr ptr3 = Marshal.GetIUnknownForObject(o3);
+ IntPtr ptr4 = Marshal.GetIUnknownForObject(o4);
+ IntPtr ptr5 = Marshal.GetIUnknownForObject(o5);
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { null, o1, o2 }, { o3, o4, o5 } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ Marshal.Release(ptr3);
+ Marshal.Release(ptr4);
+ Marshal.Release(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_DISPATCHArrayUNKNOWNMultiDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ var o3 = new object();
+ var o4 = new object();
+ var o5 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ IntPtr ptr3 = Marshal.GetIUnknownForObject(o3);
+ IntPtr ptr4 = Marshal.GetIUnknownForObject(o4);
+ IntPtr ptr5 = Marshal.GetIUnknownForObject(o5);
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.UNKNOWN,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { null, o1, o2 }, { o3, o4, o5 } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ Marshal.Release(ptr3);
+ Marshal.Release(ptr4);
+ Marshal.Release(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYDISPATCHSingleDimension_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DISPATCH,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { null, o1, o2 }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYDISPATCHSingleDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ try
+ {
+ var result = new IntPtr[] { IntPtr.Zero, ptr1, ptr2 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DISPATCH,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { null, o1, o2 }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYDISPATCHMultiDimension_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ var o3 = new object();
+ var o4 = new object();
+ var o5 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ IntPtr ptr3 = Marshal.GetIUnknownForObject(o3);
+ IntPtr ptr4 = Marshal.GetIUnknownForObject(o4);
+ IntPtr ptr5 = Marshal.GetIUnknownForObject(o5);
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DISPATCH,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { null, o1, o2 }, { o3, o4, o5 } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ Marshal.Release(ptr3);
+ Marshal.Release(ptr4);
+ Marshal.Release(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYDISPATCHMultiDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ var o1 = new object();
+ var o2 = new object();
+ var o3 = new object();
+ var o4 = new object();
+ var o5 = new object();
+ IntPtr ptr1 = Marshal.GetIUnknownForObject(o1);
+ IntPtr ptr2 = Marshal.GetIUnknownForObject(o2);
+ IntPtr ptr3 = Marshal.GetIUnknownForObject(o3);
+ IntPtr ptr4 = Marshal.GetIUnknownForObject(o4);
+ IntPtr ptr5 = Marshal.GetIUnknownForObject(o5);
+ try
+ {
+ var result = new IntPtr[2,3] { { IntPtr.Zero, ptr1, ptr2 }, { ptr3, ptr4, ptr5 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.DISPATCH, result, 1, 2);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.DISPATCH,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(2, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { null, o1, o2 }, { o3, o4, o5 } }, array);
+ });
+ }
+ finally
+ {
+ Marshal.Release(ptr1);
+ Marshal.Release(ptr2);
+ Marshal.Release(ptr3);
+ Marshal.Release(ptr4);
+ Marshal.Release(ptr5);
+ }
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYVARIANTSingleDimension_ReturnsExpected()
+ {
+ using var v1 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 1
+ }
+ };
+ using var v2 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 2
+ }
+ };
+ using var v3 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 3
+ }
+ };
+ var result = new VARIANT[] { v1, v2, v3 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.VARIANT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.VARIANT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { 1, 2, 3 }, array);
+ });
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYVARIANTSingleDimensionNonZeroLowerBound_ReturnsExpected()
+ {
+ using var v1 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 1
+ }
+ };
+ using var v2 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 2
+ }
+ };
+ using var v3 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 3
+ }
+ };
+ var result = new VARIANT[] { v1, v2, v3 };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.VARIANT, result, 1);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.VARIANT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(1), array);
+ Assert.Equal(1, array.Rank);
+ Assert.Equal(1, array.GetLowerBound(0));
+ Assert.Equal(result.Length, array.GetLength(0));
+ Assert.Equal(new object[] { 1, 2, 3 }, array);
+ });
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYVARIANTMultiDimension_ReturnsExpected()
+ {
+ using var v1 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 1
+ }
+ };
+ using var v2 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 2
+ }
+ };
+ using var v3 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 3
+ }
+ };
+ using var v4 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 4
+ }
+ };
+ using var v5 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 5
+ }
+ };
+ using var v6 = new VARIANT
+ {
+ vt = VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ llVal = 6
+ }
+ };
+
+ var result = new VARIANT[2,3] { { v1, v2, v3 }, { v4, v5, v6 } };
+ SAFEARRAY *psa = CreateSafeArray(VARENUM.VARIANT, result);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.VARIANT,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObject(variant, value =>
+ {
+ Array array = (Array)value;
+ Assert.IsType(typeof(object).MakeArrayType(2), array);
+ Assert.Equal(2, array.Rank);
+ Assert.Equal(0, array.GetLowerBound(0));
+ Assert.Equal(0, array.GetLowerBound(1));
+ Assert.Equal(result.GetLength(0), array.GetLength(0));
+ Assert.Equal(result.GetLength(1), array.GetLength(1));
+ Assert.Equal(new object[,] { { 1, 2, 3 }, { 4, 5, 6 } }, array);
+ });
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.I1)]
+ [InlineData((ushort)VARENUM.UI1)]
+ [InlineData((ushort)VARENUM.I2)]
+ [InlineData((ushort)VARENUM.UI2)]
+ [InlineData((ushort)VARENUM.I4)]
+ [InlineData((ushort)VARENUM.UI4)]
+ [InlineData((ushort)VARENUM.I8)]
+ [InlineData((ushort)VARENUM.UI8)]
+ [InlineData((ushort)VARENUM.BSTR)]
+ [InlineData((ushort)VARENUM.LPWSTR)]
+ [InlineData((ushort)VARENUM.LPSTR)]
+ [InlineData((ushort)VARENUM.UNKNOWN)]
+ [InlineData((ushort)VARENUM.DISPATCH)]
+ [InlineData((ushort)VARENUM.EMPTY)]
+ [InlineData((ushort)VARENUM.NULL)]
+ [InlineData((ushort)VARENUM.CF)]
+ [InlineData((ushort)VARENUM.VOID)]
+ [InlineData((ushort)VARENUM.PTR)]
+ [InlineData((ushort)VARENUM.SAFEARRAY)]
+ [InlineData((ushort)VARENUM.CARRAY)]
+ [InlineData((ushort)VARENUM.RECORD)]
+ [InlineData((ushort)VARENUM.BLOB)]
+ [InlineData((ushort)VARENUM.STREAM)]
+ [InlineData((ushort)VARENUM.STORAGE)]
+ [InlineData((ushort)VARENUM.STREAMED_OBJECT)]
+ [InlineData((ushort)VARENUM.STORED_OBJECT)]
+ [InlineData((ushort)VARENUM.BLOB_OBJECT)]
+ public void VARIANT_ToObject_ARRAYNoData_ReturnsExpected(ushort vt)
+ {
+ SAFEARRAY* psa = CreateSafeArray(VARENUM.I1, Array.Empty());
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | (VARENUM)vt
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaTheory]
+ [InlineData(128)]
+ [InlineData(129)]
+ [InlineData((ushort)VARENUM.BSTR_BLOB)]
+ public void VARIANT_ToObject_ARRAYInvalidTypeNoData_ThrowsInvalidOleVariantTypeException(ushort vt)
+ {
+ SAFEARRAY* psa = CreateSafeArray(VARENUM.I1, Array.Empty());
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | (VARENUM)vt
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYVECTOR_ThrowsInvalidOleVariantTypeException()
+ {
+ SAFEARRAY* psa = CreateSafeArray(VARENUM.I1, Array.Empty());
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.VECTOR | VARENUM.I4
+ };
+ Assert.Throws(null, () => variant.ToObject());
+ }
+
+ [StaFact]
+ public void VARIANT_ToObject_ARRAYTypeEMPTY_ThrowsInvalidOleVariantTypeException()
+ {
+ SAFEARRAY* psa = CreateSafeArray(VARENUM.I1, Array.Empty());
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.EMPTY,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.I1, (ushort)VARENUM.UI1)]
+ [InlineData((ushort)VARENUM.UI1, (ushort)VARENUM.I1)]
+ [InlineData((ushort)VARENUM.I2, (ushort)VARENUM.UI2)]
+ [InlineData((ushort)VARENUM.UI2, (ushort)VARENUM.I2)]
+ [InlineData((ushort)VARENUM.I4, (ushort)VARENUM.UI4)]
+ [InlineData((ushort)VARENUM.UI4, (ushort)VARENUM.I4)]
+ [InlineData((ushort)VARENUM.INT, (ushort)VARENUM.UINT)]
+ [InlineData((ushort)VARENUM.INT, (ushort)VARENUM.I2)]
+ [InlineData((ushort)VARENUM.INT, (ushort)VARENUM.I8)]
+ [InlineData((ushort)VARENUM.UINT, (ushort)VARENUM.INT)]
+ [InlineData((ushort)VARENUM.UINT, (ushort)VARENUM.UI2)]
+ [InlineData((ushort)VARENUM.UINT, (ushort)VARENUM.UI8)]
+ [InlineData((ushort)VARENUM.I8, (ushort)VARENUM.UI8)]
+ [InlineData((ushort)VARENUM.UI8, (ushort)VARENUM.I8)]
+ [InlineData((ushort)VARENUM.UNKNOWN, (ushort)VARENUM.DISPATCH)]
+ [InlineData((ushort)VARENUM.UNKNOWN, (ushort)VARENUM.I4)]
+ [InlineData((ushort)VARENUM.UNKNOWN, (ushort)VARENUM.UI4)]
+ [InlineData((ushort)VARENUM.UNKNOWN, (ushort)VARENUM.I8)]
+ [InlineData((ushort)VARENUM.UNKNOWN, (ushort)VARENUM.UI8)]
+ [InlineData((ushort)VARENUM.DISPATCH, (ushort)VARENUM.I4)]
+ [InlineData((ushort)VARENUM.DISPATCH, (ushort)VARENUM.UI4)]
+ [InlineData((ushort)VARENUM.DISPATCH, (ushort)VARENUM.I8)]
+ [InlineData((ushort)VARENUM.DISPATCH, (ushort)VARENUM.UI8)]
+ public void VARIANT_ToObject_ARRAYTypeDifferent_ThrowsSafeArrayTypeMismatchException(ushort arrayVt, ushort vt)
+ {
+ SAFEARRAY* psa = CreateSafeArray((VARENUM)arrayVt, Array.Empty());
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | (VARENUM)vt,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [InlineData((ushort)VARENUM.INT_PTR)]
+ [InlineData((ushort)VARENUM.UINT_PTR)]
+ public void VARIANT_ToObject_ARRAYTypeInvalid_ThrowsArgumentException(ushort vt)
+ {
+ SAFEARRAY* psa = CreateSafeArray((VARENUM)vt, Array.Empty());
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | (VARENUM)vt,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [InlineData(33)]
+ [InlineData(255)]
+ [InlineData(256)]
+ [InlineData(512)]
+ public void VARIANT_ARRAYBigRank_ThrowsTypeLoadException(int rank)
+ {
+ SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[rank];
+ for (uint i = 0; i < rank; i++)
+ {
+ saBounds[i] = new SAFEARRAYBOUND
+ {
+ cElements = 0,
+ lLbound = 0
+ };
+ }
+
+ SAFEARRAY *psa = SafeArrayCreate(VARENUM.I4, (uint)rank, saBounds);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.I4,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ private unsafe static SAFEARRAY* CreateSafeArray(VARENUM vt, T[] result, int lbound = 0) where T : unmanaged
+ {
+ var saBound = new SAFEARRAYBOUND
+ {
+ cElements = (uint)result.Length,
+ lLbound = lbound
+ };
+ SAFEARRAY *psa = SafeArrayCreate(vt, 1, &saBound);
+ Assert.True(psa != null);
+
+ VARENUM arrayVt = VARENUM.EMPTY;
+ HRESULT hr = SafeArrayGetVartype(psa, &arrayVt);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(vt, arrayVt);
+
+ for (int i = 0; i < result.Length; i++)
+ {
+ T value = result[i];
+ int index = i + lbound;
+ // Insert pointers directly.
+ if (value is IntPtr valuePtr)
+ {
+ hr = SafeArrayPutElement(psa, &index, (void*)valuePtr);
+ }
+ else
+ {
+ hr = SafeArrayPutElement(psa, &index, &value);
+ }
+ Assert.Equal(HRESULT.S_OK, hr);
+ }
+
+ return psa;
+ }
+
+ private unsafe SAFEARRAY* CreateSafeArray(VARENUM vt, T[,] multiDimArray, int lbound1 = 0, int lbound2 = 0) where T : unmanaged
+ {
+ SAFEARRAYBOUND* saBounds = stackalloc SAFEARRAYBOUND[2];
+ saBounds[0] = new SAFEARRAYBOUND
+ {
+ cElements = (uint)multiDimArray.GetLength(0),
+ lLbound = lbound1
+ };
+ saBounds[1] = new SAFEARRAYBOUND
+ {
+ cElements = (uint)multiDimArray.GetLength(1),
+ lLbound = lbound2
+ };
+ SAFEARRAY *psa = SafeArrayCreate(vt, 2, saBounds);
+ Assert.True(psa != null);
+
+ VARENUM arrayVt = VARENUM.EMPTY;
+ HRESULT hr = SafeArrayGetVartype(psa, &arrayVt);
+ Assert.Equal(HRESULT.S_OK, hr);
+ Assert.Equal(vt, arrayVt);
+
+ for (int i = 0; i < multiDimArray.GetLength(0); i++)
+ {
+ for (int j = 0; j < multiDimArray.GetLength(1); j++)
+ {
+ int* indices = stackalloc int[] { i + lbound1, j + lbound2 };
+ T value = multiDimArray[i, j];
+ // Insert pointers directly.
+ if (value is IntPtr valuePtr)
+ {
+ hr = SafeArrayPutElement(psa, indices, (void*)valuePtr);
+ }
+ else
+ {
+ hr = SafeArrayPutElement(psa, indices, &value);
+ }
+ Assert.Equal(HRESULT.S_OK, hr);
+ }
+ }
+
+ return psa;
+ }
+
+ [StaFact]
+ public void ToObject_RECORDRecordData_ReturnsExpected()
+ {
+ int record = 1;
+ IntPtr mem = Marshal.AllocCoTaskMem(sizeof(int));
+ (*(int*)mem) = record;
+ var recordInfo = new CustomRecordInfo
+ {
+ GetGuidAction = () => (typeof(int).GUID, HRESULT.S_OK)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(recordInfo);
+
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = pRecordInfo,
+ pvRecord = mem.ToPointer()
+ }
+ }
+ };
+ // Records actually don't work in .NET Core...
+#if false
+ AssertToObjectEqual(1, variant);
+#else
+ AssertToObjectThrows(variant);
+#endif
+ }
+
+ [StaFact]
+ public void ToObject_RECORDNullRecordData_ReturnsNull()
+ {
+ var recordInfo = new CustomRecordInfo();
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(recordInfo);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = pRecordInfo
+ }
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ [StaFact]
+ public void ToObject_RECORDNullRecordInfo_ThrowsArgumentException()
+ {
+ int record = 1;
+ IntPtr mem = Marshal.AllocCoTaskMem(sizeof(int));
+ (*(int*)mem) = record;
+
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = IntPtr.Zero,
+ pvRecord = mem.ToPointer()
+ }
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaFact]
+ public void ToObject_RECORDInvalidGetGuidHRData_ThrowsArgumentException()
+ {
+ int record = 1;
+ IntPtr mem = Marshal.AllocCoTaskMem(sizeof(int));
+ (*(int*)mem) = record;
+
+ var recordInfo = new CustomRecordInfo
+ {
+ GetGuidAction = () => (Guid.Empty, HRESULT.DISP_E_DIVBYZERO)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(recordInfo);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = pRecordInfo,
+ pvRecord = mem.ToPointer()
+ }
+ }
+ };
+ // Records actually don't work in .NET Core...
+#if false
+ AssertToObjectThrows(variant);
+#endif
+ }
+
+ [StaFact]
+ public void ToObject_RECORDInvalidGetGuidHRNoData_ReturnsNull()
+ {
+ var record = new CustomRecordInfo
+ {
+ GetGuidAction = () => (Guid.Empty, HRESULT.DISP_E_DIVBYZERO)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(record);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = pRecordInfo,
+ }
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+
+ public static IEnumerable RECORD_TestData()
+ {
+ yield return new object[] { Guid.Empty };
+ yield return new object[] { new Guid("8856f961-340a-11d0-a96b-00c04fd705a2") };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(RECORD_TestData))]
+ public void ToObject_RECORDInvalidGuidData_ThrowsArgumentException(Guid guid)
+ {
+ int record = 1;
+ IntPtr mem = Marshal.AllocCoTaskMem(sizeof(int));
+ (*(int*)mem) = record;
+
+ var recordInfo = new CustomRecordInfo
+ {
+ GetGuidAction = () => (guid, HRESULT.S_OK)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(recordInfo);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = pRecordInfo,
+ pvRecord = mem.ToPointer()
+ }
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+
+ [StaTheory]
+ [MemberData(nameof(RECORD_TestData))]
+ public void ToObject_RECORDInvalidGuidNoData_ReturnsNull(Guid guid)
+ {
+ var record = new CustomRecordInfo
+ {
+ GetGuidAction = () => (guid, HRESULT.S_OK)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(record);
+ try
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ recordVal = new VARIANT.VARIANTRecord
+ {
+ pRecInfo = pRecordInfo,
+ }
+ }
+ };
+ AssertToObjectEqual(null, variant);
+ }
+ finally
+ {
+ Marshal.Release(pRecordInfo);
+ }
+ }
+
+ [StaFact]
+ public void ToObject_RECORDARRAYValid_ReturnsExpected()
+ {
+ var result = new int[] { 1, 2 };
+ var recordInfo = new CustomRecordInfo
+ {
+ GetGuidAction = () => (typeof(int).GUID, HRESULT.S_OK)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(recordInfo);
+ try
+ {
+ SAFEARRAY *psa = CreateRecordSafeArray(result, pRecordInfo);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ // Records actually don't work in .NET Core...
+#if false
+ AssertToObjectEqual(new int[] { 0, 0 }, variant);
+#endif
+ }
+ finally
+ {
+ Marshal.Release(pRecordInfo);
+ }
+ }
+
+ [StaFact]
+ public void ToObject_RECORDARRAYInvalidFFeatures_ThrowsArgumentException()
+ {
+ var result = new int[] { 1, 2 };
+ var record = new CustomRecordInfo();
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(record);
+ try
+ {
+ SAFEARRAY *psa = CreateRecordSafeArray(result, pRecordInfo);
+ psa->fFeatures &= ~FADF.RECORD;
+ try
+ {
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+ finally
+ {
+ // Make sure disposal works.
+ psa->fFeatures |= FADF.RECORD;
+ }
+ }
+ finally
+ {
+ Marshal.Release(pRecordInfo);
+ }
+ }
+
+ [StaFact]
+ public void ToObject_RECORDARRAYInvalidGetGuidHR_ThrowsArgumentException()
+ {
+ var result = new int[] { 1, 2 };
+ var record = new CustomRecordInfo
+ {
+ GetGuidAction = () => (Guid.Empty, HRESULT.DISP_E_DIVBYZERO)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(record);
+ try
+ {
+ SAFEARRAY *psa = CreateRecordSafeArray(result, pRecordInfo);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+ finally
+ {
+ Marshal.Release(pRecordInfo);
+ }
+ }
+
+ public static IEnumerable RECORDARRAY_InvalidGuid_TestData()
+ {
+ yield return new object[] { Guid.Empty };
+ yield return new object[] { new Guid("8856f961-340a-11d0-a96b-00c04fd705a2") };
+ }
+
+ [StaTheory]
+ [MemberData(nameof(RECORDARRAY_InvalidGuid_TestData))]
+ public void ToObject_RECORDARRAY_InvokeInvalidGuid_ThrowsArgumentException(Guid guid)
+ {
+ var result = new int[] { 1, 2 };
+ var record = new CustomRecordInfo
+ {
+ GetGuidAction = () => (guid, HRESULT.S_OK)
+ };
+ IntPtr pRecordInfo = Marshal.GetComInterfaceForObject(record);
+ try
+ {
+ SAFEARRAY *psa = CreateRecordSafeArray(result, pRecordInfo);
+ using var variant = new VARIANT
+ {
+ vt = VARENUM.ARRAY | VARENUM.RECORD,
+ data = new VARIANT.VARIANTUnion
+ {
+ parray = psa
+ }
+ };
+ AssertToObjectThrows(variant);
+ }
+ finally
+ {
+ Marshal.Release(pRecordInfo);
+ }
+ }
+
+ private class CustomRecordInfo : IRecordInfo
+ {
+ HRESULT IRecordInfo.RecordInit(void* pvNew) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordClear(void* pvExisting) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordCopy(void* pvExisting, void* pvNew) => throw new NotImplementedException();
+
+ public Func<(Guid, HRESULT)> GetGuidAction { get; set; }
+
+ HRESULT IRecordInfo.GetGuid(Guid* pguid)
+ {
+ (Guid guid, HRESULT hr) = GetGuidAction();
+ *pguid = guid;
+ return hr;
+ }
+
+ HRESULT IRecordInfo.GetName(BSTR* pbstrName) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetSize(uint* pcbSize)
+ {
+ *pcbSize = (uint)sizeof(int);
+ return HRESULT.S_OK;
+ }
+
+ HRESULT IRecordInfo.GetTypeInfo(out ITypeInfo ppTypeInfo) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetField(void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetFieldNoCopy(void* pvData, out string szFieldName, VARIANT* pvarField, void* ppvDataCArray) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.PutField(INVOKEKIND wFlags, void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.PutFieldNoCopy(INVOKEKIND wFlags, void* pvData, out string szFieldName, VARIANT* pvarField) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.GetFieldNames(uint* pcNames, BSTR* rgBstrNames) => throw new NotImplementedException();
+
+ BOOL IRecordInfo.IsMatchingType(ref IRecordInfo pRecordInfoInfo) => throw new NotImplementedException();
+
+ void* IRecordInfo.RecordCreate() => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordCreateCopy(void* pvSource, void** ppvDest) => throw new NotImplementedException();
+
+ HRESULT IRecordInfo.RecordDestroy(void* pvRecord) => throw new NotImplementedException();
+ }
+
+ private static SAFEARRAY* CreateRecordSafeArray