Add tests for marshalling as VARIANT_BOOL or VARIANT (#20856)
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>
Fri, 16 Nov 2018 01:14:35 +0000 (17:14 -0800)
committerGitHub <noreply@github.com>
Fri, 16 Nov 2018 01:14:35 +0000 (17:14 -0800)
* Add native side impl for VARIANT_BOOL test.

* More bool native code.

* Add VariantBool marshalling tests.

* Add infrastructure for tests for object -> VARIANT marshalling.

* Add variant tests for all built-in types.

* Clean up Variant tests.

* Add test for passing custom structure as object.

* Add test for VARIANT_BOOL byref.

* Added byref tests for VARIANT marshalling.

* Add field marshalling tests for VARIANT.

* Move ByValue tests to not have two sources of truth.

* Make managed code the one source of truth.

* Clean up formatting/unused methods.

* Clean up some whitespace issues.

* Add tests for BStrWrapper and CurrencyWrapper marshalling.

* Add UnknownWrapper tests.

* Add a test for VariantWrapper and PInvoke.

* PR Feedback.

* Remove ToString.

* Fix visibility

* Fix MSBuild import path.

* Clean up Variant tests.

tests/src/Interop/CMakeLists.txt
tests/src/Interop/PInvoke/Variant/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/PInvoke/Variant/PInvokeDefs.cs [new file with mode: 0644]
tests/src/Interop/PInvoke/Variant/VariantNative.cpp [new file with mode: 0644]
tests/src/Interop/PInvoke/Variant/VariantTest.cs [new file with mode: 0644]
tests/src/Interop/PInvoke/Variant/VariantTest.csproj [new file with mode: 0644]
tests/src/Interop/PrimitiveMarshalling/Bool/BoolNative.cpp
tests/src/Interop/PrimitiveMarshalling/Bool/BoolTest.cs
tests/src/Interop/PrimitiveMarshalling/Bool/NativeMethodDef.cs

index 5d9c27b..60fbde3 100644 (file)
@@ -56,6 +56,7 @@ add_subdirectory(DllImportAttribute/Simple)
 add_subdirectory(ExecInDefAppDom)
 
 if(WIN32)
+    add_subdirectory(PInvoke/Variant)
     add_subdirectory(PInvoke/Varargs)
     add_subdirectory(PInvoke/NativeCallManagedComVisible)
     # This test doesn't necessarily need to be Windows-only, but the implementation is very tied to Windows APIs
diff --git a/tests/src/Interop/PInvoke/Variant/CMakeLists.txt b/tests/src/Interop/PInvoke/Variant/CMakeLists.txt
new file mode 100644 (file)
index 0000000..536ffb3
--- /dev/null
@@ -0,0 +1,18 @@
+cmake_minimum_required (VERSION 2.6)
+project (VariantNative)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES VariantNative.cpp)
+
+# add the executable
+add_library (VariantNative SHARED ${SOURCES})
+
+if(WIN32)
+    list(APPEND LINK_LIBRARIES_ADDITIONAL
+        OleAut32.lib
+    )
+endif(WIN32)
+
+target_link_libraries(VariantNative ${LINK_LIBRARIES_ADDITIONAL}) 
+
+# add the install targets
+install (TARGETS VariantNative DESTINATION bin)
diff --git a/tests/src/Interop/PInvoke/Variant/PInvokeDefs.cs b/tests/src/Interop/PInvoke/Variant/PInvokeDefs.cs
new file mode 100644 (file)
index 0000000..27e90ca
--- /dev/null
@@ -0,0 +1,200 @@
+// 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;
+
+#pragma warning disable CS0612, CS0618
+class VariantNative
+{
+    public struct CustomStruct
+    {
+    }
+
+    public struct ObjectWrapper
+    {
+        [MarshalAs(UnmanagedType.Struct)]
+        public object value;
+    }
+
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Byte(object obj, byte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_SByte(object obj, sbyte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Int16(object obj, short expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_UInt16(object obj, ushort expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Int32(object obj, int expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_UInt32(object obj, uint expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Int64(object obj, long expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_UInt64(object obj, ulong expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Single(object obj, float expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Double(object obj, double expected);
+    [DllImport(nameof(VariantNative), CharSet = CharSet.Unicode)]
+    public static extern bool Marshal_ByValue_String(object obj, [MarshalAs(UnmanagedType.BStr)] string expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Char(object obj, char expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Boolean(object obj, [MarshalAs(UnmanagedType.VariantBool)] bool expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_DateTime(object obj, DateTime expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Decimal(object obj, decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Currency(object obj, [MarshalAs(UnmanagedType.Currency)] decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Missing(object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Object(object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Object_IUnknown(object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Empty(object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Null(object obj);
+
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByValue_Invalid(object obj);
+
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Byte(ref object obj, byte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_SByte(ref object obj, sbyte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Int16(ref object obj, short expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_UInt16(ref object obj, ushort expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Int32(ref object obj, int expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_UInt32(ref object obj, uint expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Int64(ref object obj, long expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_UInt64(ref object obj, ulong expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Single(ref object obj, float expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Double(ref object obj, double expected);
+    [DllImport(nameof(VariantNative), CharSet = CharSet.Unicode)]
+    public static extern bool Marshal_ByRef_String(ref object obj, [MarshalAs(UnmanagedType.BStr)] string expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Char(ref object obj, char expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Boolean(ref object obj, [MarshalAs(UnmanagedType.VariantBool)] bool expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_DateTime(ref object obj, DateTime expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Decimal(ref object obj, decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Currency(ref object obj, [MarshalAs(UnmanagedType.Currency)] decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Missing(ref object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Object(ref object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Object_IUnknown(ref object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Empty(ref object obj);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ByRef_Null(ref object obj);
+
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_ChangeVariantType(ref object obj, int expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Out(out object obj, int expected);
+
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Byte(ObjectWrapper wrapper, byte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_SByte(ObjectWrapper wrapper, sbyte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Int16(ObjectWrapper wrapper, short expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_UInt16(ObjectWrapper wrapper, ushort expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Int32(ObjectWrapper wrapper, int expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_UInt32(ObjectWrapper wrapper, uint expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Int64(ObjectWrapper wrapper, long expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_UInt64(ObjectWrapper wrapper, ulong expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Single(ObjectWrapper wrapper, float expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Double(ObjectWrapper wrapper, double expected);
+    [DllImport(nameof(VariantNative), CharSet = CharSet.Unicode)]
+    public static extern bool Marshal_Struct_ByValue_String(ObjectWrapper wrapper, [MarshalAs(UnmanagedType.BStr)] string expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Char(ObjectWrapper wrapper, char expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Boolean(ObjectWrapper wrapper, [MarshalAs(UnmanagedType.VariantBool)] bool expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_DateTime(ObjectWrapper wrapper, DateTime expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Decimal(ObjectWrapper wrapper, decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Currency(ObjectWrapper wrapper, [MarshalAs(UnmanagedType.Currency)] decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Missing(ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Object(ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Object_IUnknown(ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Empty(ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByValue_Null(ObjectWrapper wrapper);
+
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Byte(ref ObjectWrapper wrapper, byte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_SByte(ref ObjectWrapper wrapper, sbyte expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Int16(ref ObjectWrapper wrapper, short expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_UInt16(ref ObjectWrapper wrapper, ushort expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Int32(ref ObjectWrapper wrapper, int expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_UInt32(ref ObjectWrapper wrapper, uint expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Int64(ref ObjectWrapper wrapper, long expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_UInt64(ref ObjectWrapper wrapper, ulong expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Single(ref ObjectWrapper wrapper, float expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Double(ref ObjectWrapper wrapper, double expected);
+    [DllImport(nameof(VariantNative), CharSet = CharSet.Unicode)]
+    public static extern bool Marshal_Struct_ByRef_String(ref ObjectWrapper wrapper, [MarshalAs(UnmanagedType.BStr)] string expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Char(ref ObjectWrapper wrapper, char expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Boolean(ref ObjectWrapper wrapper, [MarshalAs(UnmanagedType.VariantBool)] bool expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_DateTime(ref ObjectWrapper wrapper, DateTime expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Decimal(ref ObjectWrapper wrapper, decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Currency(ref ObjectWrapper wrapper, [MarshalAs(UnmanagedType.Currency)] decimal expected);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Missing(ref ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Object(ref ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Object_IUnknown(ref ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Empty(ref ObjectWrapper wrapper);
+    [DllImport(nameof(VariantNative))]
+    public static extern bool Marshal_Struct_ByRef_Null(ref ObjectWrapper wrapper);
+}
diff --git a/tests/src/Interop/PInvoke/Variant/VariantNative.cpp b/tests/src/Interop/PInvoke/Variant/VariantNative.cpp
new file mode 100644 (file)
index 0000000..aea8519
--- /dev/null
@@ -0,0 +1,1115 @@
+// 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.
+
+#include <xplatform.h>
+#include "platformdefines.h"
+
+#define LCID_ENGLISH MAKELCID(MAKELANGID(0x09, 0x01), SORT_DEFAULT)
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Byte(VARIANT value, BYTE expected)
+{
+    if (value.vt != VT_UI1)
+    {
+        printf("Invalid format. Expected VT_UI1.\n");
+        return FALSE;
+    }
+
+    return value.bVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_SByte(VARIANT value, CHAR expected)
+{
+    if (value.vt != VT_I1)
+    {
+        printf("Invalid format. Expected VT_I1.\n");
+        return FALSE;
+    }
+
+    return value.cVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Int16(VARIANT value, SHORT expected)
+{
+    if (value.vt != VT_I2)
+    {
+        printf("Invalid format. Expected VT_I2.\n");
+        return FALSE;
+    }
+
+    return value.iVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_UInt16(VARIANT value, USHORT expected)
+{
+    if (value.vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return value.uiVal == expected ? TRUE : FALSE;
+}
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Int32(VARIANT value, LONG expected)
+{
+    if (value.vt != VT_I4)
+    {
+        printf("Invalid format. Expected VT_I4.\n");
+        return FALSE;
+    }
+
+    return value.lVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_UInt32(VARIANT value, ULONG expected)
+{
+    if (value.vt != VT_UI4)
+    {
+        printf("Invalid format. Expected VT_UI4.\n");
+        return FALSE;
+    }
+
+    return value.ulVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Int64(VARIANT value, LONGLONG expected)
+{
+    if (value.vt != VT_I8)
+    {
+        printf("Invalid format. Expected VT_I8.\n");
+        return FALSE;
+    }
+
+    return value.llVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_UInt64(VARIANT value, ULONGLONG expected)
+{
+    if (value.vt != VT_UI8)
+    {
+        printf("Invalid format. Expected VT_UI8.\n");
+        return FALSE;
+    }
+
+    return value.ullVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Single(VARIANT value, FLOAT expected)
+{
+    if (value.vt != VT_R4)
+    {
+        printf("Invalid format. Expected VT_R4.\n");
+        return FALSE;
+    }
+
+    return value.fltVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Double(VARIANT value, DOUBLE expected)
+{
+    if (value.vt != VT_R8)
+    {
+        printf("Invalid format. Expected VT_R8.\n");
+        return FALSE;
+    }
+
+    return value.dblVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Char(VARIANT value, WCHAR expected)
+{
+    if (value.vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return value.uiVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_String(VARIANT value, BSTR expected)
+{
+    if (value.vt != VT_BSTR)
+    {
+        printf("Invalid format. Expected VT_BSTR.\n");
+        return FALSE;
+    }
+
+    if (value.bstrVal == NULL || expected == NULL)
+    {
+        return value.bstrVal == NULL && expected == NULL;
+    }
+
+    size_t len = TP_SysStringByteLen(value.bstrVal);
+
+    return len == TP_SysStringByteLen(expected) && memcmp(value.bstrVal, expected, len) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Object(VARIANT value)
+{
+    
+    if (value.vt != VT_DISPATCH)
+    {
+        printf("Invalid format. Expected VT_DISPATCH.\n");
+        return FALSE;
+    }
+    
+
+    IDispatch* obj = value.pdispVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_ByValue (Native side) recieved an invalid IDispatch pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Object_IUnknown(VARIANT value)
+{
+    
+    if (value.vt != VT_UNKNOWN)
+    {
+        printf("Invalid format. Expected VT_UNKNOWN.\n");
+        return FALSE;
+    }
+    
+
+    IUnknown* obj = value.punkVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_ByValue (Native side) recieved an invalid IUnknown pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Missing(VARIANT value)
+{
+    if (value.vt != VT_ERROR)
+    {
+        printf("Invalid format. Expected VT_ERROR.\n");
+        return FALSE;
+    }
+
+    return value.scode == DISP_E_PARAMNOTFOUND ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Empty(VARIANT value)
+{
+    if (value.vt != VT_EMPTY)
+    {
+        printf("Invalid format. Expected VT_EMPTY. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Boolean(VARIANT value, VARIANT_BOOL expected)
+{
+    if (value.vt != VT_BOOL)
+    {
+        printf("Invalid format. Expected VT_BOOL.\n");
+        return FALSE;
+    }
+
+    return value.boolVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_DateTime(VARIANT value, DATE expected)
+{
+    if (value.vt != VT_DATE)
+    {
+        printf("Invalid format. Expected VT_BYREF.\n");
+        return FALSE;
+    }
+
+    return value.date == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Decimal(VARIANT value, DECIMAL expected)
+{
+    if (value.vt != VT_DECIMAL)
+    {
+        printf("Invalid format. Expected VT_DECIMAL.\n");
+        return FALSE;
+    }
+
+    expected.wReserved = VT_DECIMAL; // The wReserved field in DECIMAL overlaps with the vt field in VARIANT
+
+    return memcmp(&value.decVal, &expected, sizeof(DECIMAL)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Currency(VARIANT value, CY expected)
+{
+    if (value.vt != VT_CY)
+    {
+        printf("Invalid format. Expected VT_CY.\n");
+        return FALSE;
+    }
+
+    return memcmp(&value.cyVal, &expected, sizeof(CY)) == 0;
+}
+
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Null(VARIANT value)
+{
+    if (value.vt != VT_NULL)
+    {
+        printf("Invalid format. Expected VT_NULL. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByValue_Invalid(VARIANT value)
+{
+    return FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Byte(VARIANT* value, BYTE expected)
+{
+    if (value->vt != VT_UI1)
+    {
+        printf("Invalid format. Expected VT_UI1.\n");
+        return FALSE;
+    }
+
+    return value->bVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_SByte(VARIANT* value, CHAR expected)
+{
+    if (value->vt != VT_I1)
+    {
+        printf("Invalid format. Expected VT_I1.\n");
+        return FALSE;
+    }
+
+    return value->cVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Int16(VARIANT* value, SHORT expected)
+{
+    if (value->vt != VT_I2)
+    {
+        printf("Invalid format. Expected VT_I2.\n");
+        return FALSE;
+    }
+
+    return value->iVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_UInt16(VARIANT* value, USHORT expected)
+{
+    if (value->vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return value->uiVal == expected ? TRUE : FALSE;
+}
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Int32(VARIANT* value, LONG expected)
+{
+    if (value->vt != VT_I4)
+    {
+        printf("Invalid format. Expected VT_I4.\n");
+        return FALSE;
+    }
+
+    return value->lVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_UInt32(VARIANT* value, ULONG expected)
+{
+    if (value->vt != VT_UI4)
+    {
+        printf("Invalid format. Expected VT_UI4.\n");
+        return FALSE;
+    }
+
+    return value->ulVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Int64(VARIANT* value, LONGLONG expected)
+{
+    if (value->vt != VT_I8)
+    {
+        printf("Invalid format. Expected VT_I8.\n");
+        return FALSE;
+    }
+
+    return value->llVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_UInt64(VARIANT* value, ULONGLONG expected)
+{
+    if (value->vt != VT_UI8)
+    {
+        printf("Invalid format. Expected VT_UI8.\n");
+        return FALSE;
+    }
+
+    return value->ullVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Single(VARIANT* value, FLOAT expected)
+{
+    if (value->vt != VT_R4)
+    {
+        printf("Invalid format. Expected VT_R4.\n");
+        return FALSE;
+    }
+
+    return value->fltVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Double(VARIANT* value, DOUBLE expected)
+{
+    if (value->vt != VT_R8)
+    {
+        printf("Invalid format. Expected VT_R8.\n");
+        return FALSE;
+    }
+
+    return value->dblVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Char(VARIANT* value, WCHAR expected)
+{
+    if (value->vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return value->uiVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_String(VARIANT* value, BSTR expected)
+{
+    if (value->vt != VT_BSTR)
+    {
+        printf("Invalid format. Expected VT_BSTR.\n");
+        return FALSE;
+    }
+    
+    if (value->bstrVal == NULL || expected == NULL)
+    {
+        return value->bstrVal == NULL && expected == NULL;
+    }
+
+    size_t len = TP_SysStringByteLen(value->bstrVal);
+
+    return len == TP_SysStringByteLen(expected) && memcmp(value->bstrVal, expected, len) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Object(VARIANT* value)
+{
+    
+    if (value->vt != VT_DISPATCH)
+    {
+        printf("Invalid format. Expected VT_DISPATCH.\n");
+        return FALSE;
+    }
+    
+
+    IDispatch* obj = value->pdispVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_ByRef (Native side) recieved an invalid IDispatch pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Object_IUnknown(VARIANT* value)
+{
+    
+    if (value->vt != VT_UNKNOWN)
+    {
+        printf("Invalid format. Expected VT_UNKNOWN.\n");
+        return FALSE;
+    }
+    
+
+    IUnknown* obj = value->punkVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_ByRef (Native side) recieved an invalid IUnknown pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Missing(VARIANT* value)
+{
+    if (value->vt != VT_ERROR)
+    {
+        printf("Invalid format. Expected VT_ERROR.\n");
+        return FALSE;
+    }
+
+    return value->scode == DISP_E_PARAMNOTFOUND ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Empty(VARIANT* value)
+{
+    if (value->vt != VT_EMPTY)
+    {
+        printf("Invalid format. Expected VT_EMPTY. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Boolean(VARIANT* value, VARIANT_BOOL expected)
+{
+    if (value->vt != VT_BOOL)
+    {
+        printf("Invalid format. Expected VT_BOOL.\n");
+        return FALSE;
+    }
+
+    return value->boolVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_DateTime(VARIANT* value, DATE expected)
+{
+    if (value->vt != VT_DATE)
+    {
+        printf("Invalid format. Expected VT_BYREF.\n");
+        return FALSE;
+    }
+
+    return value->date == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Decimal(VARIANT* value, DECIMAL expected)
+{
+    if (value->vt != VT_DECIMAL)
+    {
+        printf("Invalid format. Expected VT_DECIMAL.\n");
+        return FALSE;
+    }
+
+    expected.wReserved = VT_DECIMAL; // The wReserved field in DECIMAL overlaps with the vt field in VARIANT*
+
+    return memcmp(&value->decVal, &expected, sizeof(DECIMAL)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Currency(VARIANT* value, CY expected)
+{
+    if (value->vt != VT_CY)
+    {
+        printf("Invalid format. Expected VT_CY.\n");
+        return FALSE;
+    }
+
+    return memcmp(&value->cyVal, &expected, sizeof(CY)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ByRef_Null(VARIANT* value)
+{
+    if (value->vt != VT_NULL)
+    {
+        printf("Invalid format. Expected VT_NULL. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Out(VARIANT* pValue, LONG expected)
+{
+    if (FAILED(VariantClear(pValue)))
+    {
+        printf("Failed to clear pValue.\n");
+        return FALSE;
+    }
+    pValue->vt = VT_I4;
+    pValue->lVal = expected;
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_ChangeVariantType(VARIANT* pValue, LONG expected)
+{
+    if (FAILED(VariantClear(pValue)))
+    {
+        printf("Failed to clear pValue.\n");
+        return FALSE;
+    }
+    pValue->vt = VT_I4;
+    pValue->lVal = expected;
+
+    return TRUE;
+}
+
+struct VariantWrapper
+{
+    VARIANT value;
+};
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Byte(VariantWrapper wrapper, BYTE expected)
+{
+    if (wrapper.value.vt != VT_UI1)
+    {
+        printf("Invalid format. Expected VT_UI1.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.bVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_SByte(VariantWrapper wrapper, CHAR expected)
+{
+    if (wrapper.value.vt != VT_I1)
+    {
+        printf("Invalid format. Expected VT_I1.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.cVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Int16(VariantWrapper wrapper, SHORT expected)
+{
+    if (wrapper.value.vt != VT_I2)
+    {
+        printf("Invalid format. Expected VT_I2.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.iVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_UInt16(VariantWrapper wrapper, USHORT expected)
+{
+    if (wrapper.value.vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.uiVal == expected ? TRUE : FALSE;
+}
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Int32(VariantWrapper wrapper, LONG expected)
+{
+    if (wrapper.value.vt != VT_I4)
+    {
+        printf("Invalid format. Expected VT_I4.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.lVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_UInt32(VariantWrapper wrapper, ULONG expected)
+{
+    if (wrapper.value.vt != VT_UI4)
+    {
+        printf("Invalid format. Expected VT_UI4.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.ulVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Int64(VariantWrapper wrapper, LONGLONG expected)
+{
+    if (wrapper.value.vt != VT_I8)
+    {
+        printf("Invalid format. Expected VT_I8.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.llVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_UInt64(VariantWrapper wrapper, ULONGLONG expected)
+{
+    if (wrapper.value.vt != VT_UI8)
+    {
+        printf("Invalid format. Expected VT_UI8.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.ullVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Single(VariantWrapper wrapper, FLOAT expected)
+{
+    if (wrapper.value.vt != VT_R4)
+    {
+        printf("Invalid format. Expected VT_R4.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.fltVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Double(VariantWrapper wrapper, DOUBLE expected)
+{
+    if (wrapper.value.vt != VT_R8)
+    {
+        printf("Invalid format. Expected VT_R8.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.dblVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Char(VariantWrapper wrapper, WCHAR expected)
+{
+    if (wrapper.value.vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.uiVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_String(VariantWrapper wrapper, BSTR expected)
+{
+    if (wrapper.value.vt != VT_BSTR)
+    {
+        printf("Invalid format. Expected VT_BSTR.\n");
+        return FALSE;
+    }
+    
+    if (wrapper.value.bstrVal == NULL || expected == NULL)
+    {
+        return wrapper.value.bstrVal == NULL && expected == NULL;
+    }
+
+    size_t len = TP_SysStringByteLen(wrapper.value.bstrVal);
+
+    return len == TP_SysStringByteLen(expected) && memcmp(wrapper.value.bstrVal, expected, len) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Object(VariantWrapper wrapper)
+{
+    
+    if (wrapper.value.vt != VT_DISPATCH)
+    {
+        printf("Invalid format. Expected VT_DISPATCH.\n");
+        return FALSE;
+    }
+    
+
+    IDispatch* obj = wrapper.value.pdispVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_Struct_ByValue (Native side) recieved an invalid IDispatch pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Object_IUnknown(VariantWrapper wrapper)
+{
+    
+    if (wrapper.value.vt != VT_UNKNOWN)
+    {
+        printf("Invalid format. Expected VT_UNKNOWN.\n");
+        return FALSE;
+    }
+    
+
+    IUnknown* obj = wrapper.value.punkVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_Struct_ByValue (Native side) recieved an invalid IUnknown pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Missing(VariantWrapper wrapper)
+{
+    if (wrapper.value.vt != VT_ERROR)
+    {
+        printf("Invalid format. Expected VT_ERROR.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.scode == DISP_E_PARAMNOTFOUND ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Empty(VariantWrapper wrapper)
+{
+    if (wrapper.value.vt != VT_EMPTY)
+    {
+        printf("Invalid format. Expected VT_EMPTY. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Boolean(VariantWrapper wrapper, VARIANT_BOOL expected)
+{
+    if (wrapper.value.vt != VT_BOOL)
+    {
+        printf("Invalid format. Expected VT_BOOL.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.boolVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_DateTime(VariantWrapper wrapper, DATE expected)
+{
+    if (wrapper.value.vt != VT_DATE)
+    {
+        printf("Invalid format. Expected VT_Struct_ByValue.\n");
+        return FALSE;
+    }
+
+    return wrapper.value.date == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Decimal(VariantWrapper wrapper, DECIMAL expected)
+{
+    if (wrapper.value.vt != VT_DECIMAL)
+    {
+        printf("Invalid format. Expected VT_DECIMAL.\n");
+        return FALSE;
+    }
+
+    expected.wReserved = VT_DECIMAL; // The wReserved field in DECIMAL overlaps with the vt field in VARIANT*
+
+    return memcmp(&wrapper.value.decVal, &expected, sizeof(DECIMAL)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Currency(VariantWrapper wrapper, CY expected)
+{
+    if (wrapper.value.vt != VT_CY)
+    {
+        printf("Invalid format. Expected VT_CY.\n");
+        return FALSE;
+    }
+
+    return memcmp(&wrapper.value.cyVal, &expected, sizeof(CY)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByValue_Null(VariantWrapper wrapper)
+{
+    if (wrapper.value.vt != VT_NULL)
+    {
+        printf("Invalid format. Expected VT_NULL. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Byte(VariantWrapper* pWrapper, BYTE expected)
+{
+    if (pWrapper->value.vt != VT_UI1)
+    {
+        printf("Invalid format. Expected VT_UI1.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.bVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_SByte(VariantWrapper* pWrapper, CHAR expected)
+{
+    if (pWrapper->value.vt != VT_I1)
+    {
+        printf("Invalid format. Expected VT_I1.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.cVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Int16(VariantWrapper* pWrapper, SHORT expected)
+{
+    if (pWrapper->value.vt != VT_I2)
+    {
+        printf("Invalid format. Expected VT_I2.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.iVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_UInt16(VariantWrapper* pWrapper, USHORT expected)
+{
+    if (pWrapper->value.vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.uiVal == expected ? TRUE : FALSE;
+}
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Int32(VariantWrapper* pWrapper, LONG expected)
+{
+    if (pWrapper->value.vt != VT_I4)
+    {
+        printf("Invalid format. Expected VT_I4.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.lVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_UInt32(VariantWrapper* pWrapper, ULONG expected)
+{
+    if (pWrapper->value.vt != VT_UI4)
+    {
+        printf("Invalid format. Expected VT_UI4.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.ulVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Int64(VariantWrapper* pWrapper, LONGLONG expected)
+{
+    if (pWrapper->value.vt != VT_I8)
+    {
+        printf("Invalid format. Expected VT_I8.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.llVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_UInt64(VariantWrapper* pWrapper, ULONGLONG expected)
+{
+    if (pWrapper->value.vt != VT_UI8)
+    {
+        printf("Invalid format. Expected VT_UI8.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.ullVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Single(VariantWrapper* pWrapper, FLOAT expected)
+{
+    if (pWrapper->value.vt != VT_R4)
+    {
+        printf("Invalid format. Expected VT_R4.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.fltVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Double(VariantWrapper* pWrapper, DOUBLE expected)
+{
+    if (pWrapper->value.vt != VT_R8)
+    {
+        printf("Invalid format. Expected VT_R8.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.dblVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Char(VariantWrapper* pWrapper, WCHAR expected)
+{
+    if (pWrapper->value.vt != VT_UI2)
+    {
+        printf("Invalid format. Expected VT_UI2.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.uiVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_String(VariantWrapper* pWrapper, BSTR expected)
+{
+    if (pWrapper->value.vt != VT_BSTR)
+    {
+        printf("Invalid format. Expected VT_BSTR.\n");
+        return FALSE;
+    }
+    
+    if (pWrapper->value.bstrVal == NULL || expected == NULL)
+    {
+        return pWrapper->value.bstrVal == NULL && expected == NULL;
+    }
+
+    size_t len = TP_SysStringByteLen(pWrapper->value.bstrVal);
+
+    return len == TP_SysStringByteLen(expected) && memcmp(pWrapper->value.bstrVal, expected, len) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Object(VariantWrapper* pWrapper)
+{
+    
+    if (pWrapper->value.vt != VT_DISPATCH)
+    {
+        printf("Invalid format. Expected VT_DISPATCH.\n");
+        return FALSE;
+    }
+    
+
+    IDispatch* obj = pWrapper->value.pdispVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_Struct_ByRef (Native side) recieved an invalid IDispatch pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Object_IUnknown(VariantWrapper* pWrapper)
+{
+    
+    if (pWrapper->value.vt != VT_UNKNOWN)
+    {
+        printf("Invalid format. Expected VT_UNKNOWN.\n");
+        return FALSE;
+    }
+    
+
+    IUnknown* obj = pWrapper->value.punkVal;
+
+    if (obj == NULL)
+    {
+        printf("Marshal_Struct_ByRef (Native side) recieved an invalid IUnknown pointer\n");
+        return FALSE;
+    }
+
+    obj->AddRef();
+
+    obj->Release();
+
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Missing(VariantWrapper* pWrapper)
+{
+    if (pWrapper->value.vt != VT_ERROR)
+    {
+        printf("Invalid format. Expected VT_ERROR.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.scode == DISP_E_PARAMNOTFOUND ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Empty(VariantWrapper* pWrapper)
+{
+    if (pWrapper->value.vt != VT_EMPTY)
+    {
+        printf("Invalid format. Expected VT_EMPTY. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Boolean(VariantWrapper* pWrapper, VARIANT_BOOL expected)
+{
+    if (pWrapper->value.vt != VT_BOOL)
+    {
+        printf("Invalid format. Expected VT_BOOL.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.boolVal == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_DateTime(VariantWrapper* pWrapper, DATE expected)
+{
+    if (pWrapper->value.vt != VT_DATE)
+    {
+        printf("Invalid format. Expected VT_Struct_ByRef.\n");
+        return FALSE;
+    }
+
+    return pWrapper->value.date == expected ? TRUE : FALSE;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Decimal(VariantWrapper* pWrapper, DECIMAL expected)
+{
+    if (pWrapper->value.vt != VT_DECIMAL)
+    {
+        printf("Invalid format. Expected VT_DECIMAL.\n");
+        return FALSE;
+    }
+
+    expected.wReserved = VT_DECIMAL; // The wReserved field in DECIMAL overlaps with the vt field in VARIANT*
+
+    return memcmp(&pWrapper->value.decVal, &expected, sizeof(DECIMAL)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Currency(VariantWrapper* pWrapper, CY expected)
+{
+    if (pWrapper->value.vt != VT_CY)
+    {
+        printf("Invalid format. Expected VT_CY.\n");
+        return FALSE;
+    }
+
+    return memcmp(&pWrapper->value.cyVal, &expected, sizeof(CY)) == 0;
+}
+
+extern "C" BOOL DLL_EXPORT STDMETHODCALLTYPE Marshal_Struct_ByRef_Null(VariantWrapper* pWrapper)
+{
+    if (pWrapper->value.vt != VT_NULL)
+    {
+        printf("Invalid format. Expected VT_NULL. \n");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
diff --git a/tests/src/Interop/PInvoke/Variant/VariantTest.cs b/tests/src/Interop/PInvoke/Variant/VariantTest.cs
new file mode 100644 (file)
index 0000000..ab16781
--- /dev/null
@@ -0,0 +1,294 @@
+// 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;
+using TestLibrary;
+using static VariantNative;
+
+#pragma warning disable CS0612, CS0618
+class Test
+{
+    private const byte NumericValue = 15;
+
+    private const char CharValue = 'z';
+
+    private const string StringValue = "Abcdefg";
+
+    private const decimal DecimalValue = 74.25M;
+
+    private static readonly DateTime DateValue = new DateTime(2018, 11, 6);
+
+    private unsafe static void TestByValue()
+    {
+        Assert.IsTrue(Marshal_ByValue_Byte((byte)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_SByte((sbyte)NumericValue, (sbyte)NumericValue));
+        Assert.IsTrue(Marshal_ByValue_Int16((short)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_UInt16((ushort)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_Int32((int)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_UInt32((uint)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_Int64((long)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_UInt64((ulong)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_Single((float)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_Double((double)NumericValue, NumericValue));
+        Assert.IsTrue(Marshal_ByValue_String(StringValue, StringValue));
+        Assert.IsTrue(Marshal_ByValue_String(new BStrWrapper(null), null));
+        Assert.IsTrue(Marshal_ByValue_Char(CharValue, CharValue));
+        Assert.IsTrue(Marshal_ByValue_Boolean(true, true));
+        Assert.IsTrue(Marshal_ByValue_DateTime(DateValue, DateValue));
+        Assert.IsTrue(Marshal_ByValue_Decimal(DecimalValue, DecimalValue));
+        Assert.IsTrue(Marshal_ByValue_Currency(new CurrencyWrapper(DecimalValue), DecimalValue));
+        Assert.IsTrue(Marshal_ByValue_Null(DBNull.Value));
+        Assert.IsTrue(Marshal_ByValue_Missing(System.Reflection.Missing.Value));
+        Assert.IsTrue(Marshal_ByValue_Empty(null));
+        Assert.IsTrue(Marshal_ByValue_Object(new object()));
+        Assert.IsTrue(Marshal_ByValue_Object_IUnknown(new UnknownWrapper(new object())));
+        Assert.Throws<ArgumentException>(() => Marshal_ByValue_Invalid(TimeSpan.Zero));
+        Assert.Throws<NotSupportedException>(() => Marshal_ByValue_Invalid(new CustomStruct()));
+        Assert.Throws<ArgumentException>(() => Marshal_ByValue_Invalid(new VariantWrapper(CharValue)));
+    }
+
+    private unsafe static void TestByRef()
+    {
+        object obj;
+
+        obj = (byte)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_Byte(ref obj, NumericValue));
+        
+        obj = (sbyte)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_SByte(ref obj, (sbyte)NumericValue));
+        
+        obj = (short)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_Int16(ref obj, NumericValue));
+        
+        obj = (ushort)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_UInt16(ref obj, NumericValue));
+        
+        obj = (int)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_Int32(ref obj, NumericValue));
+        
+        obj = (uint)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_UInt32(ref obj, NumericValue));
+        
+        obj = (long)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_Int64(ref obj, NumericValue));
+        
+        obj = (ulong)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_UInt64(ref obj, NumericValue));
+        
+        obj = (float)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_Single(ref obj, NumericValue));
+        
+        obj = (double)NumericValue;
+        Assert.IsTrue(Marshal_ByRef_Double(ref obj, NumericValue));
+        
+        obj = StringValue;
+        Assert.IsTrue(Marshal_ByRef_String(ref obj, StringValue));
+
+        obj = new BStrWrapper(null);
+        Assert.IsTrue(Marshal_ByRef_String(ref obj, null));
+        
+        obj = CharValue;
+        Assert.IsTrue(Marshal_ByRef_Char(ref obj, CharValue));
+        
+        obj = true;
+        Assert.IsTrue(Marshal_ByRef_Boolean(ref obj, true));
+        
+        obj = DateValue;
+        Assert.IsTrue(Marshal_ByRef_DateTime(ref obj, DateValue));
+        
+        obj = DecimalValue;
+        Assert.IsTrue(Marshal_ByRef_Decimal(ref obj, DecimalValue));
+
+        obj = new CurrencyWrapper(DecimalValue);
+        Assert.IsTrue(Marshal_ByRef_Currency(ref obj, DecimalValue));
+        
+        obj = DBNull.Value;
+        Assert.IsTrue(Marshal_ByRef_Null(ref obj));
+        
+        obj = System.Reflection.Missing.Value;
+        Assert.IsTrue(Marshal_ByRef_Missing(ref obj));
+        
+        obj = null;
+        Assert.IsTrue(Marshal_ByRef_Empty(ref obj));
+        
+        obj = new object();
+        Assert.IsTrue(Marshal_ByRef_Object(ref obj));
+
+        obj = new UnknownWrapper(new object());
+        Assert.IsTrue(Marshal_ByRef_Object_IUnknown(ref obj));
+
+        obj = DecimalValue;
+        Assert.IsTrue(Marshal_ChangeVariantType(ref obj, NumericValue));
+        Assert.IsTrue(obj is int);
+        Assert.AreEqual(NumericValue, (int)obj);
+    }
+
+    private unsafe static void TestOut()
+    {
+        Assert.IsTrue(Marshal_Out(out object obj, NumericValue));
+        Assert.IsTrue(obj is int);
+        Assert.AreEqual(NumericValue, (int)obj);
+    }
+    
+    private unsafe static void TestFieldByValue()
+    {
+        ObjectWrapper wrapper = new ObjectWrapper();
+
+        wrapper.value = (byte)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Byte(wrapper, NumericValue));
+        
+        wrapper.value = (sbyte)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_SByte(wrapper, (sbyte)NumericValue));
+        
+        wrapper.value = (short)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Int16(wrapper, NumericValue));
+        
+        wrapper.value = (ushort)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_UInt16(wrapper, NumericValue));
+        
+        wrapper.value = (int)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Int32(wrapper, NumericValue));
+        
+        wrapper.value = (uint)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_UInt32(wrapper, NumericValue));
+        
+        wrapper.value = (long)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Int64(wrapper, NumericValue));
+        
+        wrapper.value = (ulong)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_UInt64(wrapper, NumericValue));
+        
+        wrapper.value = (float)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Single(wrapper, NumericValue));
+        
+        wrapper.value = (double)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Double(wrapper, NumericValue));
+        
+        wrapper.value = StringValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_String(wrapper, StringValue));
+
+        wrapper.value = new BStrWrapper(null);
+        Assert.IsTrue(Marshal_Struct_ByValue_String(wrapper, null));
+        
+        wrapper.value = CharValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Char(wrapper, CharValue));
+        
+        wrapper.value = true;
+        Assert.IsTrue(Marshal_Struct_ByValue_Boolean(wrapper, true));
+        
+        wrapper.value = DateValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_DateTime(wrapper, DateValue));
+        
+        wrapper.value = DecimalValue;
+        Assert.IsTrue(Marshal_Struct_ByValue_Decimal(wrapper, DecimalValue));
+
+        wrapper.value = new CurrencyWrapper(DecimalValue);
+        Assert.IsTrue(Marshal_Struct_ByValue_Currency(wrapper, DecimalValue));
+        
+        wrapper.value = DBNull.Value;
+        Assert.IsTrue(Marshal_Struct_ByValue_Null(wrapper));
+        
+        wrapper.value = System.Reflection.Missing.Value;
+        Assert.IsTrue(Marshal_Struct_ByValue_Missing(wrapper));
+        
+        wrapper.value = null;
+        Assert.IsTrue(Marshal_Struct_ByValue_Empty(wrapper));
+        
+        wrapper.value = new object();
+        Assert.IsTrue(Marshal_Struct_ByValue_Object(wrapper));
+        
+        wrapper.value = new UnknownWrapper(new object());
+        Assert.IsTrue(Marshal_Struct_ByValue_Object_IUnknown(wrapper));
+    }
+
+    private unsafe static void TestFieldByRef()
+    {
+        ObjectWrapper wrapper = new ObjectWrapper();
+
+        wrapper.value = (byte)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Byte(ref wrapper, NumericValue));
+        
+        wrapper.value = (sbyte)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_SByte(ref wrapper, (sbyte)NumericValue));
+        
+        wrapper.value = (short)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Int16(ref wrapper, NumericValue));
+        
+        wrapper.value = (ushort)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_UInt16(ref wrapper, NumericValue));
+        
+        wrapper.value = (int)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Int32(ref wrapper, NumericValue));
+        
+        wrapper.value = (uint)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_UInt32(ref wrapper, NumericValue));
+        
+        wrapper.value = (long)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Int64(ref wrapper, NumericValue));
+        
+        wrapper.value = (ulong)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_UInt64(ref wrapper, NumericValue));
+        
+        wrapper.value = (float)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Single(ref wrapper, NumericValue));
+        
+        wrapper.value = (double)NumericValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Double(ref wrapper, NumericValue));
+        
+        wrapper.value = StringValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_String(ref wrapper, StringValue));
+
+        wrapper.value = new BStrWrapper(null);
+        Assert.IsTrue(Marshal_Struct_ByRef_String(ref wrapper, null));
+        
+        wrapper.value = CharValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Char(ref wrapper, CharValue));
+        
+        wrapper.value = true;
+        Assert.IsTrue(Marshal_Struct_ByRef_Boolean(ref wrapper, true));
+        
+        wrapper.value = DateValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_DateTime(ref wrapper, DateValue));
+        
+        wrapper.value = DecimalValue;
+        Assert.IsTrue(Marshal_Struct_ByRef_Decimal(ref wrapper, DecimalValue));
+        
+        wrapper.value = new CurrencyWrapper(DecimalValue);
+        Assert.IsTrue(Marshal_Struct_ByRef_Currency(ref wrapper, DecimalValue));
+        
+        wrapper.value = DBNull.Value;
+        Assert.IsTrue(Marshal_Struct_ByRef_Null(ref wrapper));
+        
+        wrapper.value = System.Reflection.Missing.Value;
+        Assert.IsTrue(Marshal_Struct_ByRef_Missing(ref wrapper));
+        
+        wrapper.value = null;
+        Assert.IsTrue(Marshal_Struct_ByRef_Empty(ref wrapper));
+        
+        wrapper.value = new object();
+        Assert.IsTrue(Marshal_Struct_ByRef_Object(ref wrapper));
+        
+        wrapper.value = new UnknownWrapper(new object());
+        Assert.IsTrue(Marshal_Struct_ByRef_Object_IUnknown(ref wrapper));
+    }
+
+    public static int Main()
+    {
+        try
+        {
+            TestByValue();
+            TestByRef();
+            TestOut();
+            TestFieldByValue();
+            TestFieldByRef();
+        }
+        catch (Exception e)
+        {
+            Console.WriteLine($"Test failed: {e}");
+            return 101;
+        }
+        return 100;
+    }
+}
diff --git a/tests/src/Interop/PInvoke/Variant/VariantTest.csproj b/tests/src/Interop/PInvoke/Variant/VariantTest.csproj
new file mode 100644 (file)
index 0000000..3826f46
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <Import Project="../../Interop.settings.targets" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>VariantTest</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+
+    <!-- Test unsupported outside of windows -->
+    <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+    <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"></PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="*.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="CMakeLists.txt" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
index 23eeb2f..edbc8cb 100644 (file)
@@ -173,4 +173,74 @@ extern "C" DLL_EXPORT bool STDMETHODCALLTYPE Marshal_As_Out(/*[Out]*/bool boolVa
        //Return
        return true;
 }
+
+#ifdef _WIN32
+extern "C" DLL_EXPORT bool STDMETHODCALLTYPE Marshal_ByValue_Variant(VARIANT_BOOL boolValue, bool expected)
+{
+    if (boolValue != (expected ? VARIANT_TRUE : VARIANT_FALSE))
+    {
+        printf("Error in function Marshal_ByValue_Variant(Native Client)\n");
+
+        printf("Expected %s ", expected ? "true" : "false");
+        printf("Actual %s (%hi)", boolValue == VARIANT_FALSE ? "false" : "(unknown variant value)", boolValue);
+
+        return false;
+    }
+
+    return true;
+}
+
+extern "C" DLL_EXPORT bool STDMETHODCALLTYPE Marshal_Ref_Variant(VARIANT_BOOL* pBoolValue)
+{
+    if (*pBoolValue != (boolManaged ? VARIANT_TRUE : VARIANT_FALSE))
+    {
+        printf("Error in function Marshal_ByValue_Variant(Native Client)\n");
+
+        printf("Expected %s ", boolManaged ? "true" : "false");
+        printf("Actual %s (%hi)", *pBoolValue == VARIANT_FALSE ? "false" : "(unknown variant value)", *pBoolValue);
+
+        return false;
+    }
+
+    *pBoolValue = (boolNative ? VARIANT_TRUE : VARIANT_FALSE);
+    return true;
+}
+
+struct ContainsVariantBool
+{
+    VARIANT_BOOL value;
+};
+
+extern "C" DLL_EXPORT bool STDMETHODCALLTYPE Marshal_ByValue_Struct_Variant(ContainsVariantBool value, bool expected)
+{
+    if (value.value != (expected ? VARIANT_TRUE : VARIANT_FALSE))
+    {
+        printf("Error in function Marshal_ByValue_Variant(Native Client)\n");
+
+        printf("Expected %s ", expected ? "true" : "false");
+        printf("Actual %s (%hi)", value.value == VARIANT_FALSE ? "false" : "(unknown variant value)", value.value);
+
+        return false;
+    }
+
+    return true;
+}
+
+extern "C" DLL_EXPORT bool STDMETHODCALLTYPE Marshal_Ref_Struct_Variant(ContainsVariantBool* pBoolValue)
+{
+    if (pBoolValue->value != (boolManaged ? VARIANT_TRUE : VARIANT_FALSE))
+    {
+        printf("Error in function Marshal_ByValue_Variant(Native Client)\n");
+
+        printf("Expected %s ", boolManaged ? "true" : "false");
+        printf("Actual %s (%hi)", pBoolValue->value == VARIANT_FALSE ? "false" : "(unknown variant value)", pBoolValue->value);
+
+        return false;
+    }
+
+    pBoolValue->value = (boolNative ? VARIANT_TRUE : VARIANT_FALSE);
+    return true;
+}
+
+#endif
 #pragma warning(pop)
index 72b80c0..29db00a 100644 (file)
@@ -9,6 +9,9 @@ using System.Text;
 
 class Test
 {
+    const bool boolManaged = true;
+    const bool boolNative = false;
+
     static void ReportFailure(string describe, bool expect, bool actual)
     {
         throw new Exception(" === Fail: " + describe + "\n\tExpected:" + expect + "\n\tActual:" + actual);        
@@ -16,12 +19,9 @@ class Test
     
     public static int Main(string[] args)
     {
-        const bool boolManaged = true;
-        const bool boolNative = false;
-        
         //Test Method1
         bool boolValue1 = boolManaged;
-        bool boolValueRet1 = NativeMethods.Marshal_In(boolValue1);
+        bool boolValueRet1 = BoolNative.Marshal_In(boolValue1);
         if (!boolValueRet1)
         {
             ReportFailure("Method Marshal_In[Managed Side],The return value is wrong", true, boolValueRet1);
@@ -29,7 +29,7 @@ class Test
 
         //TestMethod2
         bool boolValue2 = boolManaged;
-        bool boolValueRet2 = NativeMethods.Marshal_InOut(boolValue2);
+        bool boolValueRet2 = BoolNative.Marshal_InOut(boolValue2);
         if (!boolValueRet2)
         {
             ReportFailure("Method Marshal_InOut[Managed Side],The return value is wrong", true, boolValueRet2);
@@ -41,7 +41,7 @@ class Test
 
         //TestMethod3
         bool boolValue3 = boolManaged;
-        bool boolValueRet3 = NativeMethods.Marshal_Out(boolValue3);
+        bool boolValueRet3 = BoolNative.Marshal_Out(boolValue3);
         if (!boolValueRet3)
         {
             ReportFailure("Method Marshal_Out[Managed Side],The return value is wrong", true, boolValueRet3);
@@ -53,7 +53,7 @@ class Test
 
         //TestMethod4
         bool boolValue4 = boolManaged;
-        bool boolValueRet4 = NativeMethods.MarshalPointer_In(ref boolValue4);
+        bool boolValueRet4 = BoolNative.MarshalPointer_In(ref boolValue4);
         if (!boolValueRet4)
         {
             ReportFailure("Method MarshalPointer_In[Managed Side],The return value is wrong", true, boolValueRet4);
@@ -65,7 +65,7 @@ class Test
 
         //TestMethod5
         bool boolValue5 = boolManaged;
-        bool boolValueRet5 = NativeMethods.MarshalPointer_InOut(ref boolValue5);
+        bool boolValueRet5 = BoolNative.MarshalPointer_InOut(ref boolValue5);
         if (!boolValueRet5)
         {
             ReportFailure("Method MarshalPointer_InOut[Managed Side],The return value is wrong", true, boolValueRet5);
@@ -77,7 +77,7 @@ class Test
 
         //TestMethod6
         bool boolValue6 = boolManaged;
-        bool boolValueRet6 = NativeMethods.MarshalPointer_Out(out boolValue6);
+        bool boolValueRet6 = BoolNative.MarshalPointer_Out(out boolValue6);
         if (!boolValueRet6)
         {
             ReportFailure("Method Marshal_Out[Managed Side],The return value is wrong", true, boolValueRet6);
@@ -89,18 +89,18 @@ class Test
 
         //Test Method7
         bool boolValue7 = boolManaged;
-        bool boolValueRet7 = NativeMethods.Marshal_As_In(boolValue7);
+        bool boolValueRet7 = BoolNative.Marshal_As_In(boolValue7);
         if (!boolValueRet7)
         {
-            ReportFailure("Method Marshal_As_In[Managed Side],The return value is wrong", true, boolValueRet1);
+            ReportFailure("Method Marshal_As_In[Managed Side],The return value is wrong", true, boolValueRet7);
         }
 
         //TestMethod8
         bool boolValue8 = boolManaged;
-        bool boolValueRet8 = NativeMethods.Marshal_As_InOut(boolValue8);
+        bool boolValueRet8 = BoolNative.Marshal_As_InOut(boolValue8);
         if (!boolValueRet8)
         {
-            ReportFailure("Method Marshal_As_InOut[Managed Side],The return value is wrong", true, boolValueRet2);
+            ReportFailure("Method Marshal_As_InOut[Managed Side],The return value is wrong", true, boolValueRet8);
         }
         if (boolValue8 != boolManaged)
         {
@@ -109,15 +109,83 @@ class Test
 
         //TestMethod9
         bool boolValue9 = boolManaged;
-        bool boolValueRet9 = NativeMethods.Marshal_As_Out(boolValue9);
+        bool boolValueRet9 = BoolNative.Marshal_As_Out(boolValue9);
         if (!boolValueRet9)
         {
-            ReportFailure("Method Marshal_As_Out[Managed Side],The return value is wrong", true, boolValueRet3);
+            ReportFailure("Method Marshal_As_Out[Managed Side],The return value is wrong", true, boolValueRet9);
         }
         if (boolValue9 != boolManaged)
         {
-            ReportFailure("Method Marshal_As_Out[Managed Side],The parameter value is changed", boolManaged, boolValue3);
+            ReportFailure("Method Marshal_As_Out[Managed Side],The parameter value is changed", boolManaged, boolValue9);
+        }
+
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+        {
+            TestVariantBool();
         }
+        
         return 100;
     }
+
+    private static void TestVariantBool()
+    {
+        
+        if (!BoolNative.Marshal_ByValue_Variant(true, true))
+        {
+            ReportFailure("Method Marshal_ByValue_Variant[Managed Side], The return value is wrong", true, true);
+        }
+        
+        if (!BoolNative.Marshal_ByValue_Variant(false, false))
+        {
+            ReportFailure("Method Marshal_ByValue_Variant[Managed Side], The return value is wrong", false, false);
+        }
+
+        bool boolValue10 = boolManaged;
+        bool boolValueRet10 = BoolNative.Marshal_Ref_Variant(ref boolValue10);
+
+        if (!boolValueRet10)
+        {
+            ReportFailure("Method Marshal_Ref_Variant[Managed Side], The return value is wrong.", true, boolValueRet10);
+        }
+        if (boolValue10 != boolNative)
+        {
+            ReportFailure("Method Marshal_Ref_Variant[Managed Side],The passed value is wrong", boolNative, boolValue10);
+        } 
+        
+        var trueStruct = new BoolNative.ContainsVariantBool
+        {
+            value = true
+        };
+
+        var falseStruct = new BoolNative.ContainsVariantBool
+        {
+            value = false
+        };
+        
+        if (!BoolNative.Marshal_ByValue_Struct_Variant(trueStruct, true))
+        {
+            ReportFailure("Method Marshal_ByValue_Variant[Managed Side], The return value is wrong", true, true);
+        }
+        
+        if (!BoolNative.Marshal_ByValue_Struct_Variant(falseStruct, false))
+        {
+            ReportFailure("Method Marshal_ByValue_Variant[Managed Side], The return value is wrong", false, false);
+        }
+
+        var boolValue11 = new BoolNative.ContainsVariantBool
+        {
+            value = boolManaged
+        };
+        
+        bool boolValueRet11 = BoolNative.Marshal_Ref_Struct_Variant(ref boolValue11);
+
+        if (!boolValueRet11)
+        {
+            ReportFailure("Method Marshal_Ref_Variant[Managed Side], The return value is wrong.", true, boolValueRet11);
+        }
+        if (boolValue11.value != boolNative)
+        {
+            ReportFailure("Method Marshal_Ref_Variant[Managed Side],The passed value is wrong", boolNative, boolValue11.value);
+        }
+    }
 }
index b46015f..4d29f70 100644 (file)
@@ -7,41 +7,69 @@ using System.Runtime.InteropServices;
 using System.Reflection;
 using System.Text;
 
-public class NativeMethods
+public class BoolNative
 {
-
-    public const string NativeSharedBinaryName = "BoolNative";
-
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     public static extern bool Marshal_In([In]bool boolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     public static extern bool Marshal_InOut([In, Out]bool boolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     public static extern bool Marshal_Out([Out]bool boolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     public static extern bool MarshalPointer_In([In]ref bool pboolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     public static extern bool MarshalPointer_InOut(ref bool pboolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     public static extern bool MarshalPointer_Out(out bool pboolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     [return: MarshalAs(UnmanagedType.U1)]
     public static extern bool Marshal_As_In(
       [In, MarshalAs(UnmanagedType.U1)]bool boolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     [return: MarshalAs(UnmanagedType.U1)]
     public static extern bool Marshal_As_InOut(
       [In, Out, MarshalAs(UnmanagedType.U1)]bool boolValue);
 
-    [DllImport(NativeSharedBinaryName, CallingConvention = CallingConvention.StdCall)]
+    [DllImport(nameof(BoolNative))]
     [return: MarshalAs(UnmanagedType.U1)]
     public static extern bool Marshal_As_Out(
       [Out, MarshalAs(UnmanagedType.U1)]bool boolValue);
+
+#pragma warning disable CS0612, CS0618
+    public struct ContainsVariantBool
+    {
+        [MarshalAs(UnmanagedType.VariantBool)]
+        public bool value;
+    }
+
+    [DllImport(nameof(BoolNative))]
+    [return: MarshalAs(UnmanagedType.U1)]
+    public static extern bool Marshal_ByValue_Variant(
+        [MarshalAs(UnmanagedType.VariantBool)] bool value,
+        [MarshalAs(UnmanagedType.U1)] bool expected);
+
+    [DllImport(nameof(BoolNative))]
+    [return: MarshalAs(UnmanagedType.U1)]
+    public static extern bool Marshal_Ref_Variant(
+        [MarshalAs(UnmanagedType.VariantBool)] ref bool value);
+    
+    [DllImport(nameof(BoolNative))]
+    [return: MarshalAs(UnmanagedType.U1)]
+    public static extern bool Marshal_ByValue_Struct_Variant(
+        ContainsVariantBool value,
+        [MarshalAs(UnmanagedType.U1)] bool expected);
+
+    [DllImport(nameof(BoolNative))]
+    [return: MarshalAs(UnmanagedType.U1)]
+    public static extern bool Marshal_Ref_Struct_Variant(ref ContainsVariantBool value);
+
+#pragma warning restore CS0612, CS0618
+
 }