typedef int HRESULT;
#define LONGLONG long long
#define ULONGLONG unsigned LONGLONG
-typedef unsigned long ULONG, *PULONG;
+typedef unsigned int ULONG, *PULONG;
#define S_OK 0x0
#define SUCCEEDED(_hr) ((HRESULT)(_hr) >= 0)
#define FAILED(_hr) ((HRESULT)(_hr) < 0)
add_subdirectory(PInvoke/Delegate/MarshalDelegateAsField)
add_subdirectory(PInvoke/Delegate/MarshalDelegateAsParam)
add_subdirectory(PInvoke/Primitives/Int)
+add_subdirectory(PInvoke/SizeParamIndex/PInvoke/PassingByOut)
+add_subdirectory(PInvoke/SizeParamIndex/PInvoke/PassingByRef)
+add_subdirectory(PInvoke/SizeParamIndex/ReversePInvoke/PassingByOut)
+add_subdirectory(PInvoke/SizeParamIndex/ReversePInvoke/PassingByRef)
add_subdirectory(PInvoke/Array/MarshalArrayAsField/LPArrayNative)
add_subdirectory(PInvoke/Array/MarshalArrayAsParam/LPArrayNative)
add_subdirectory(PInvoke/Miscellaneous/HandleRef)
--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+project (PInvokePassingByOutNative)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+include_directories("..")
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES
+ PInvokePassingByOutNative.cpp
+)
+# add the executable
+add_library (PInvokePassingByOutNative SHARED ${SOURCES})
+target_link_libraries(PInvokePassingByOutNative ${LINK_LIBRARIES_ADDITIONAL})
+# add the install targets
+install (TARGETS PInvokePassingByOutNative DESTINATION bin)
--- /dev/null
+// 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.
+
+// PInvokePassingByOutNative.cpp : Defines the entry point for the DLL application.
+//
+#include <xplatform.h>
+#include <limits.h>
+#include "platformdefines.h"
+#include "helper.h"
+
+//#####################################################################
+//ByOut Array, ByRef SizeParamIndex
+//#####################################################################
+
+//BYTE 0 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayByte_AsByOut_AsSizeParamIndex(BYTE* arrSize, BYTE** ppActual)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (BYTE)1);
+}
+
+//CHAR 1 ==> CHAR.Max size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArraySbyte_AsByOut_AsSizeParamIndex(CHAR* arrSize, CHAR** ppActual)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (CHAR)SCHAR_MAX);
+}
+
+//SHORT -1 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayShort_AsByOut_AsSizeParamIndex(/*out*/SHORT* arrSize, SHORT** ppActual)
+{
+ short shortArray_Size = 16384;//SHRT_MAX+1/2
+
+ *ppActual = (SHORT*)CoreClrAlloc(sizeof(SHORT)*shortArray_Size);
+
+ *arrSize = shortArray_Size;
+
+ for(SHORT i = 0; i < shortArray_Size; ++i)
+ {
+ (*ppActual)[i] = shortArray_Size - 1 - i;
+ }
+ return TRUE;
+}
+
+//SHORT 10 ==> -1 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayShortReturnNegative_AsByOut_AsSizeParamIndex(SHORT* arrSize, SHORT** ppActual)
+{
+ *ppActual = (SHORT*)CoreClrAlloc(sizeof(SHORT)*CArray_Size);
+ *arrSize = -1;
+
+ for(SHORT i = 0; i < CArray_Size; ++i)
+ {
+ (*ppActual)[i] = CArray_Size - 1 - i;
+ }
+ return TRUE;
+}
+
+//USHORT ? ==> ushort.Max ==> size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayUshort_AsByOut_AsSizeParamIndex(USHORT** ppActual, USHORT* arrSize)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (USHORT)USHRT_MAX);
+}
+
+//Int32 ? ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayInt_AsByOut_AsSizeParamIndex(LONG* arrSize,LONG** ppActual)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (LONG)0);
+}
+
+//ULONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayUInt_AsByOut_AsSizeParamIndex(ULONG* arrSize, ULONG** ppActual)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (ULONG)20);
+}
+
+//LONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayLong_AsByOut_AsSizeParamIndex(LONGLONG* arrSize, LONGLONG** ppActual)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (LONGLONG)20);
+}
+
+//ULONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayUlong_AsByOut_AsSizeParamIndex(ULONGLONG** ppActual,ULONGLONG* arrSize,ULONGLONG _unused)
+{
+ return CheckAndChangeArrayByOut(ppActual, arrSize, (ULONGLONG)1000);
+}
+#ifdef _WIN32
+//String 10 size Array ==> BSTR 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayString_AsByOut_AsSizeParamIndex(BSTR** ppBSTR,short* arrSize)
+{
+ *ppBSTR = (BSTR*)CoreClrAlloc(sizeof(BSTR)*CArray_Size);
+ for(int i = 0;i<CArray_Size;++i)
+ {
+ (*ppBSTR)[i] = ToBSTR(CArray_Size - 1 - i);
+ }
+
+ *arrSize = CArray_Size;
+
+ return TRUE;
+}
+#endif
--- /dev/null
+// 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;
+
+/// <summary>
+/// Pass Array Size by out keyword using SizeParamIndex Attributes
+/// </summary>
+public class ClientMarshalArrayAsSizeParamIndexByOutTest
+{
+
+ #region ByOut
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayByte_AsByOut_AsSizeParamIndex(
+ out byte arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out byte[] arrByte);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArraySbyte_AsByOut_AsSizeParamIndex(
+ out sbyte arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out sbyte[] arrSbyte);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayShort_AsByOut_AsSizeParamIndex(
+ out short arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out short[] arrShort);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayShortReturnNegative_AsByOut_AsSizeParamIndex(
+ out short arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out short[] arrShort);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayUshort_AsByOut_AsSizeParamIndex(
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out ushort[] arrUshort, out ushort arrSize);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayInt_AsByOut_AsSizeParamIndex(
+ out Int32 arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out Int32[] arrInt32);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayUInt_AsByOut_AsSizeParamIndex(
+ out UInt32 arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out UInt32[] arrUInt32);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayLong_AsByOut_AsSizeParamIndex(
+ out long arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out long[] arrLong);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayUlong_AsByOut_AsSizeParamIndex(
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out ulong[] arrUlong, out ulong arrSize, ulong unused);
+
+ [DllImport("PInvokePassingByOutNative")]
+ private static extern bool MarshalCStyleArrayString_AsByOut_AsSizeParamIndex(
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1, ArraySubType = UnmanagedType.BStr)] out string[] arrInt32, out int arrSize);
+
+ #endregion
+
+ static void SizeParamTypeIsByte()
+ {
+ string strDescription = "Scenario(byte ==> BYTE): Array_Size(N->M) = 1";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ byte byte_Array_Size;
+ byte[] arrByte;
+ Assert.IsTrue(MarshalCStyleArrayByte_AsByOut_AsSizeParamIndex(out byte_Array_Size, out arrByte));
+
+ //Construct Expected array
+ int expected_ByteArray_Size = 1;
+ byte[] expectedArrByte = Helper.GetExpChangeArray<byte>(expected_ByteArray_Size);
+ Assert.IsTrue(Helper.EqualArray<byte>(arrByte, (int)byte_Array_Size, expectedArrByte, (int)expectedArrByte.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsSByte()
+ {
+ string strDescription = "Scenario(sbyte ==> CHAR):Array_Size(N->M) = sbyte.Max";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ sbyte sbyte_Array_Size;
+ sbyte[] arrSbyte;
+ Assert.IsTrue(MarshalCStyleArraySbyte_AsByOut_AsSizeParamIndex(out sbyte_Array_Size, out arrSbyte));
+
+ sbyte[] expectedArrSbyte = Helper.GetExpChangeArray<sbyte>(sbyte.MaxValue);
+ Assert.IsTrue(Helper.EqualArray<sbyte>(arrSbyte, (int)sbyte_Array_Size, expectedArrSbyte, (int)expectedArrSbyte.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsShort1()
+ {
+ string strDescription = "Scenario(short ==> SHORT)1,Array_Size(M->N) = -1, Array_Size(N->M)=(ShortMax+1)/2";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ short shortArray_Size = (short)-1;
+ short[] arrShort = Helper.InitArray<short>(10);
+ Assert.IsTrue(MarshalCStyleArrayShort_AsByOut_AsSizeParamIndex(out shortArray_Size, out arrShort));
+
+ //Construct Expected Array
+ int expected_ShortArray_Size = 16384;//(SHRT_MAX+1)/2
+ short[] expectedArrShort = Helper.GetExpChangeArray<short>(expected_ShortArray_Size);
+ Assert.IsTrue(Helper.EqualArray<short>(arrShort, (int)shortArray_Size, expectedArrShort, (int)expectedArrShort.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsShort2()
+ {
+ string strDescription = "Scenario(short ==> SHORT)2, Array_Size = 10, Array_Size(N->M) = -1";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ short short_Array_Size = (short)10;
+ short[] arrShort = Helper.InitArray<short>(short_Array_Size);
+ Assert.Throws<OverflowException>(() => MarshalCStyleArrayShortReturnNegative_AsByOut_AsSizeParamIndex(out short_Array_Size, out arrShort));
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsUShort()
+ {
+ string strDescription = "Scenario(ushort==>USHORT): Array_Size(N->M) = ushort.MaxValue";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ ushort ushort_Array_Size;
+ ushort[] arrUshort;
+ Assert.IsTrue(MarshalCStyleArrayUshort_AsByOut_AsSizeParamIndex(out arrUshort, out ushort_Array_Size));
+
+ //Expected Array
+ ushort[] expectedArrUshort = Helper.GetExpChangeArray<ushort>(ushort.MaxValue);
+ Assert.IsTrue(Helper.EqualArray<ushort>(arrUshort, (int)ushort_Array_Size, expectedArrUshort, (ushort)expectedArrUshort.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsInt32()
+ {
+ string strDescription = "Scenario(Int32 ==> LONG): Array_Size(N->M) = 0 ";
+
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ Int32 Int32_Array_Size;
+ Int32[] arrInt32;
+ Assert.IsTrue(MarshalCStyleArrayInt_AsByOut_AsSizeParamIndex(out Int32_Array_Size, out arrInt32));
+
+ //Expected Array
+ Int32[] expectedArrInt32 = Helper.GetExpChangeArray<Int32>(0);
+ Assert.IsTrue(Helper.EqualArray<Int32>(arrInt32, Int32_Array_Size, expectedArrInt32, expectedArrInt32.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsUInt32()
+ {
+ string strDescription = "Scenario(UInt32 ==> ULONG): Array_Size(N->M) = 20";
+
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ int expected_UInt32ArraySize = 20;
+
+ UInt32 UInt32_Array_Size = (UInt32)10;
+ UInt32[] arrUInt32 = Helper.InitArray<UInt32>((Int32)UInt32_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayUInt_AsByOut_AsSizeParamIndex(out UInt32_Array_Size, out arrUInt32));
+
+ //Construct expected
+ UInt32[] expectedArrUInt32 = Helper.GetExpChangeArray<UInt32>(expected_UInt32ArraySize);
+ Assert.IsTrue(Helper.EqualArray<UInt32>(arrUInt32, (Int32)UInt32_Array_Size, expectedArrUInt32, (Int32)expectedArrUInt32.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsLong()
+ {
+ string strDescription = "Scenario(long ==> LONGLONG): Array_Size(N->M) = 20";
+
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ int expected_LongArraySize = 20;
+
+ long long_Array_Size = (long)10;
+ long[] arrLong = Helper.InitArray<long>((Int32)long_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayLong_AsByOut_AsSizeParamIndex(out long_Array_Size, out arrLong));
+
+ long[] expectedArrLong = Helper.GetExpChangeArray<long>(expected_LongArraySize);
+ Assert.IsTrue(Helper.EqualArray<long>(arrLong, (Int32)long_Array_Size, expectedArrLong, (Int32)expectedArrLong.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsULong()
+ {
+ string strDescription = "Scenario(ulong ==> ULONGLONG): Array_Size(N->M) = 1000";
+
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ int expected_ULongArraySize = 1000;
+
+ ulong ulong_Array_Size = (ulong)10;
+ ulong[] arrUlong = Helper.InitArray<ulong>((Int32)ulong_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayUlong_AsByOut_AsSizeParamIndex(out arrUlong, out ulong_Array_Size, ulong_Array_Size));
+
+ ulong[] expectedArrUlong = Helper.GetExpChangeArray<ulong>(expected_ULongArraySize);
+ Assert.IsTrue(Helper.EqualArray<ulong>(arrUlong, (Int32)ulong_Array_Size, expectedArrUlong, (Int32)expectedArrUlong.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsString()
+ {
+ string strDescription = "Scenario(String ==> BSTR): Array_Size(N->M) = 20";
+
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ int expected_StringArraySize = 20;
+ int string_Array_Size = 10;
+ String[] arrString = Helper.InitArray<String>(string_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayString_AsByOut_AsSizeParamIndex(out arrString, out string_Array_Size));
+
+ String[] expArrString = Helper.GetExpChangeArray<String>(expected_StringArraySize);
+ Assert.IsTrue(Helper.EqualArray<String>(arrString, string_Array_Size, expArrString, expArrString.Length));
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static int Main()
+ {
+ try{
+ SizeParamTypeIsByte();
+ SizeParamTypeIsSByte();
+ SizeParamTypeIsShort1();
+ SizeParamTypeIsShort2();
+ SizeParamTypeIsUShort();
+ SizeParamTypeIsInt32();
+ SizeParamTypeIsUInt32();
+ SizeParamTypeIsLong();
+ SizeParamTypeIsULong();
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ SizeParamTypeIsString();
+ }
+ return 100;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+ }
+}
--- /dev/null
+<?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" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>PassingByOutTest</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>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </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="PassingByOutTest.cs" />
+ <Compile Include="..\helper.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="../../../../Interop.settings.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+project (PInvokePassingByRefNative)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+include_directories("..")
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES
+ PInvokePassingByRefNative.cpp
+)
+# add the executable
+add_library (PInvokePassingByRefNative SHARED ${SOURCES})
+target_link_libraries(PInvokePassingByRefNative ${LINK_LIBRARIES_ADDITIONAL})
+# add the install targets
+install (TARGETS PInvokePassingByRefNative DESTINATION bin)
--- /dev/null
+// 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.
+
+// PInvokePassingByRefNative.cpp : Defines the entry point for the DLL application.
+//
+#include <xplatform.h>
+#include <limits.h>
+#include "helper.h"
+
+//#####################################################################
+//ByRef Array, ByRef SizeParamIndex
+//#####################################################################
+
+//BYTE 1 ==> 0 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayByte_AsByRef_AsSizeParamIndex(BYTE* arrSize, BYTE** ppActual)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (BYTE)1, (BYTE)0);
+}
+
+//CHAR 10 ==> CHAR.Max size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArraySbyte_AsByRef_AsSizeParamIndex(CHAR* arrSize, CHAR** ppActual)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (CHAR)10, (CHAR)CHAR_MAX);
+}
+
+//SHORT -1 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayShort_AsByRef_AsSizeParamIndex(SHORT* arrSize, SHORT** ppActual)
+{
+ if(*arrSize != -1)
+ {
+ printf("%s,ManagedtoNative Error!\n",__FUNCTION__);
+ printf("arrSize != -1");
+ return FALSE;
+ }
+
+ SHORT* pExpectedArr = InitArray<SHORT>((SHORT)Array_Size);
+
+ if(!EqualArray(*ppActual, (SHORT)Array_Size, pExpectedArr, (SHORT)Array_Size))
+ {
+ printf("%s,ManagedtoNative Error!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(*ppActual);
+ *ppActual = (SHORT*)CoreClrAlloc(sizeof(SHORT)*CArray_Size);
+
+ *arrSize = CArray_Size;
+
+ for(SHORT i = 0; i < CArray_Size; ++i)
+ {
+ (*ppActual)[i] = CArray_Size - 1 - i;
+ }
+ return TRUE;
+}
+
+//SHORT 10 ==> -1 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayShortReturnNegative_AsByRef_AsSizeParamIndex(SHORT* arrSize, SHORT** ppActual)
+{
+ SHORT* pExpectedArr = InitArray<SHORT>((SHORT)Array_Size);
+
+ if(!EqualArray(*ppActual, (SHORT)Array_Size, pExpectedArr, (SHORT)Array_Size))
+ {
+ printf("%s,ManagedtoNative Error!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(*ppActual);
+ *ppActual = (SHORT*)CoreClrAlloc(sizeof(SHORT)*CArray_Size);
+
+ *arrSize = (SHORT)-1;
+
+ for(SHORT i = 0; i < CArray_Size; ++i)
+ {
+ (*ppActual)[i] = CArray_Size - 1 - i;
+ }
+ return TRUE;
+}
+
+//USHORT 20 ==> ushort.Max size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayUshort_AsByRef_AsSizeParamIndex(USHORT** ppActual, USHORT* arrSize)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (USHORT)20, (USHORT)65535);
+}
+
+//Int32 10 ==> 1 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayInt_AsByRef_AsSizeParamIndex(LONG* arrSize,LONG unused,LONG** ppActual)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (LONG)10, (LONG)1);
+}
+
+//ULONG 1234 ==> 4321 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayUInt_AsByRef_AsSizeParamIndex(ULONG** ppActual,ULONG unused, ULONG* arrSize)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (ULONG)1234, (ULONG)4321);
+}
+
+//LONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayLong_AsByRef_AsSizeParamIndex(LONGLONG* arrSize, LONGLONG** ppActual)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (LONGLONG)10, (LONGLONG)20);
+}
+
+//ULONGLONG 0 ==> 0 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayUlong_AsByRef_AsSizeParamIndex(ULONGLONG* arrSize, ULONGLONG** ppActual)
+{
+ return CheckAndChangeArrayByRef(ppActual, arrSize, (ULONGLONG)0, (ULONGLONG)0);
+}
+#ifdef _WIN32
+//String size Array 20 ==> BSTR 10 size Array
+extern "C" DLL_EXPORT BOOL __stdcall MarshalCStyleArrayString_AsByRef_AsSizeParamIndex(short* arrSize, BSTR** ppBSTR,char *** pppStr)
+{
+ BSTR* pExpectedArr = InitArrayBSTR(20);
+
+ if(!EqualArrayBSTR(*ppBSTR,*arrSize,pExpectedArr,20))
+ {
+ printf("%s,ManagedtoNative Error!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(*ppBSTR);
+
+ *ppBSTR = (BSTR*)CoreClrAlloc(sizeof(BSTR)*10);
+ for(int i = 0;i<10;++i)
+ {
+ (*ppBSTR)[i] = ToBSTR(10 - 1 - i);
+ }
+
+ *arrSize = 10;
+
+ return TRUE;
+}
+#endif
--- /dev/null
+// 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;
+
+/// <summary>
+/// Pass LPArray Size by ref keyword using SizeParamIndex Attributes
+/// </summary>
+
+public class ClientMarshalArrayAsSizeParamIndexByRefTest
+{
+
+ #region ByRef
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayByte_AsByRef_AsSizeParamIndex(
+ ref byte arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref byte[] arrByte);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArraySbyte_AsByRef_AsSizeParamIndex(
+ ref sbyte arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref sbyte[] arrSbyte);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayShort_AsByRef_AsSizeParamIndex(
+ ref short arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref short[] arrShort);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayShortReturnNegative_AsByRef_AsSizeParamIndex(
+ ref short arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref short[] arrShort);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayUshort_AsByRef_AsSizeParamIndex(
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref ushort[] arrUshort, ref ushort arrSize);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayInt_AsByRef_AsSizeParamIndex(
+ ref Int32 arrSize, Int32 unused, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref Int32[] arrInt32);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayUInt_AsByRef_AsSizeParamIndex(
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] ref UInt32[] arrUInt32, UInt32 unused, ref UInt32 arrSize);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayLong_AsByRef_AsSizeParamIndex(
+ ref long arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref long[] arrLong);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayUlong_AsByRef_AsSizeParamIndex(
+ ref ulong arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref ulong[] arrUlong);
+
+ [DllImport("PInvokePassingByRefNative")]
+ private static extern bool MarshalCStyleArrayString_AsByRef_AsSizeParamIndex(
+ ref int arrSize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, ArraySubType = UnmanagedType.BStr)] ref string[] arrStr,
+ [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, ArraySubType = UnmanagedType.LPStr)] ref string[] arrStr2);
+
+ #endregion
+
+ static void SizeParamTypeIsByte()
+ {
+ string strDescription = "Scenario(byte==>BYTE):Array_Size(M->N)=1,Array_Size(N->M)= byte.MinValue";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ byte byte_Array_Size = 1;
+ byte[] arrByte = Helper.InitArray<byte>(byte_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayByte_AsByRef_AsSizeParamIndex(ref byte_Array_Size, ref arrByte));
+
+ //Construct Expected array
+ int expected_ByteArray_Size = Byte.MinValue;
+ byte[] expectedArrByte = Helper.GetExpChangeArray<byte>(expected_ByteArray_Size);
+ Assert.IsTrue(Helper.EqualArray<byte>(arrByte, (int)byte_Array_Size, expectedArrByte, (int)expectedArrByte.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsSByte()
+ {
+ string strDescription = "Scenario(sbyte==>CHAR): Array_Size(M->N) = 10, Array_Size(N->M) = sbyte.Max";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ sbyte sbyte_Array_Size = (sbyte)10;
+ sbyte[] arrSbyte = Helper.InitArray<sbyte>(sbyte_Array_Size);
+
+ Assert.IsTrue(MarshalCStyleArraySbyte_AsByRef_AsSizeParamIndex(ref sbyte_Array_Size, ref arrSbyte));
+
+ //Construct Expected
+ sbyte[] expectedArrSbyte = Helper.GetExpChangeArray<sbyte>(sbyte.MaxValue);
+ Assert.IsTrue(Helper.EqualArray<sbyte>(arrSbyte, (int)sbyte_Array_Size, expectedArrSbyte, (int)sbyte.MaxValue));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsShort1()
+ {
+ string strDescription = "Scenario(short==>SHORT)1: Array_Size(M->N) = -1, Array_Size(N->M) = 20";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ short short_Array_Size = (short)-1;
+ short[] arrShort = Helper.InitArray<short>(10);
+ int expected_ByteArraySize = 20;
+
+ Assert.IsTrue(MarshalCStyleArrayShort_AsByRef_AsSizeParamIndex(ref short_Array_Size, ref arrShort));
+
+ //Construct Expected
+ short[] expectedArrShort = Helper.GetExpChangeArray<short>(expected_ByteArraySize);
+ Assert.IsTrue(Helper.EqualArray<short>(arrShort, (int)short_Array_Size, expectedArrShort, expectedArrShort.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsShort2()
+ {
+ string strDescription = "Scenario(short==>SHORT)2: Array_Size(M->N) = 10, Array_Size(N->M) = -1";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ short short_Array_Size = (short)10;
+ short[] arrShort = Helper.InitArray<short>(10);
+ Assert.Throws<OverflowException>(() => MarshalCStyleArrayShortReturnNegative_AsByRef_AsSizeParamIndex(ref short_Array_Size, ref arrShort));
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsUShort()
+ {
+ string strDescription = "Scenario(ushort==>USHORT): Array_Size(M->N) = 0, Array_Size(N->M) = ushort.MaxValue";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ ushort ushort_Array_Size = 20;
+ ushort[] arrUshort = Helper.InitArray<ushort>(ushort_Array_Size);
+
+ int expected_UshortArraySize = ushort.MaxValue;
+ Assert.IsTrue(MarshalCStyleArrayUshort_AsByRef_AsSizeParamIndex(ref arrUshort, ref ushort_Array_Size));
+
+ //Construct Expected
+ ushort[] expectedArrShort = Helper.GetExpChangeArray<ushort>(expected_UshortArraySize);
+ Assert.IsTrue(Helper.EqualArray<ushort>(arrUshort, (int)ushort_Array_Size, expectedArrShort, expectedArrShort.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsInt32()
+ {
+ string strDescription = "Scenario(Int32==>LONG):Array_Size(M->N)=10, Array_Size(N->M)=1";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ Int32 Int32_Array_Size = (Int32)10;
+ Int32[] arrInt32 = Helper.InitArray<Int32>(Int32_Array_Size);
+
+ Assert.IsTrue(MarshalCStyleArrayInt_AsByRef_AsSizeParamIndex(ref Int32_Array_Size, Int32.MaxValue, ref arrInt32));
+
+ //Construct Expected
+ int expected_UshortArraySize = 1;
+ Int32[] expectedArrInt32 = Helper.GetExpChangeArray<Int32>(expected_UshortArraySize);
+ Assert.IsTrue(Helper.EqualArray<Int32>(arrInt32, Int32_Array_Size, expectedArrInt32, expectedArrInt32.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsUInt32()
+ {
+ string strDescription = "Scenario(UInt32==>ULONG):Array_Size(M->N)=1234,Array_Size(N->M)=4321";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ UInt32 UInt32_Array_Size = (UInt32)1234;
+ UInt32[] arrUInt32 = Helper.InitArray<UInt32>((Int32)UInt32_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayUInt_AsByRef_AsSizeParamIndex(ref arrUInt32, 1234, ref UInt32_Array_Size));
+
+ //Construct Expected
+ int expected_UInt32ArraySize = 4321;
+ UInt32[] expectedArrUInt32 = Helper.GetExpChangeArray<UInt32>(expected_UInt32ArraySize);
+ Assert.IsTrue(Helper.EqualArray<UInt32>(arrUInt32, (Int32)UInt32_Array_Size, expectedArrUInt32, (Int32)expectedArrUInt32.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsLong()
+ {
+ string strDescription = "Scenario(long==>LONGLONG):Array_Size(M->N)=10,Array_Size(N->M)=20";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ long long_Array_Size = (long)10;
+ long[] arrLong = Helper.InitArray<long>((Int32)long_Array_Size);
+ Assert.IsTrue(MarshalCStyleArrayLong_AsByRef_AsSizeParamIndex(ref long_Array_Size, ref arrLong));
+
+ //Construct Expected Array
+ int expected_LongArraySize = 20;
+ long[] expectedArrLong = Helper.GetExpChangeArray<long>(expected_LongArraySize);
+ Assert.IsTrue(Helper.EqualArray<long>(arrLong, (Int32)long_Array_Size, expectedArrLong, (Int32)expectedArrLong.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsULong()
+ {
+ string strDescription = "Scenario(ulong==>ULONGLONG):Array_Size(M->N)=0, Array_Size(N->M)=0";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ ulong ulong_Array_Size = (ulong)0;
+ ulong[] arrUlong = Helper.InitArray<ulong>((Int32)ulong_Array_Size);
+
+ Assert.IsTrue(MarshalCStyleArrayUlong_AsByRef_AsSizeParamIndex(ref ulong_Array_Size, ref arrUlong));
+
+ //Construct Expected
+ int expected_ULongArraySize = 0;
+ ulong[] expectedArrUlong = Helper.GetExpChangeArray<ulong>(expected_ULongArraySize);
+ Assert.IsTrue(Helper.EqualArray<ulong>(arrUlong, (Int32)ulong_Array_Size, expectedArrUlong, (Int32)expectedArrUlong.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static void SizeParamTypeIsString()
+ {
+ string strDescription = "Scenario(String==>BSTR):Array_Size(M->N)= 20, Array_Size(N->M)=10";
+ Console.WriteLine();
+ Console.WriteLine(strDescription + " Starts!");
+
+ int array_Size = 20;
+ String[] arrString = Helper.InitArray<String>(array_Size);
+ String[] arrString2 = Helper.InitArray<String>(array_Size);
+
+ Assert.IsTrue(MarshalCStyleArrayString_AsByRef_AsSizeParamIndex(ref array_Size, ref arrString, ref arrString2));
+
+ //Construct Expected
+ int expected_StringArraySize = 10;
+ String[] expArrString = Helper.GetExpChangeArray<String>(expected_StringArraySize);
+ Assert.IsTrue(Helper.EqualArray<String>(arrString, array_Size, expArrString, expArrString.Length));
+
+ Console.WriteLine(strDescription + " Ends!");
+ }
+
+ static int Main()
+ {
+ try{
+ SizeParamTypeIsByte();
+ SizeParamTypeIsSByte();
+ SizeParamTypeIsShort1();
+ SizeParamTypeIsShort2();
+ SizeParamTypeIsUShort();
+ SizeParamTypeIsInt32();
+ SizeParamTypeIsUInt32();
+ SizeParamTypeIsLong();
+ SizeParamTypeIsULong();
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ SizeParamTypeIsString();
+ }
+ return 100;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+ }
+}
--- /dev/null
+<?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" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>PassingByRefTest</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>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </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="PassingByRefTest.cs" />
+ <Compile Include="..\helper.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="../../../../Interop.settings.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+// 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;
+
+public class Helper
+{
+
+ #region General method
+
+ public static T[] InitArray<T>(int arrSize)
+ {
+ T[] array = new T[arrSize];
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = (T)Convert.ChangeType(i, typeof(T));
+ }
+ return array;
+ }
+
+ public static bool EqualArray<T>(T[] actualArray, int actualSize, T[] expectedArray, int expectedSize)
+ {
+ int failures = 0;
+ if (actualArray == null && expectedArray == null)
+ {
+ Console.WriteLine("\tTwo array are equal.Both of them null");
+ return true;
+ }
+ else if (actualArray == null && expectedArray != null)
+ {
+ Console.WriteLine("\tTwo array are not equal.The sourcArr is null,but the expectedArray is not null");
+ return false;
+ }
+ else if (actualArray != null && expectedArray == null)
+ {
+ Console.WriteLine("\tTwo array are not equal.The sourcArr is not null but the expectedArray is null");
+ return false;
+ }
+ else if (!actualSize.Equals(expectedSize))
+ {
+ Console.WriteLine("\tTwo array are not equal.The sizes are not equal:Expected:{0},Actaul:{1}", expectedSize, actualSize);
+ return false;
+ }
+ for (int i = 0; i < expectedSize; ++i)
+ {
+ if (!actualArray[i].Equals(expectedArray[i]))
+ {
+ Console.WriteLine("\tTwo array are not equal.The values of index {0} are not equal!", i);
+ Console.WriteLine("\t\tThe actualArray is {0},the expectedArray is {1}", actualArray[i].ToString(), expectedArray[i].ToString());
+ failures++;
+ }
+ }
+ if (failures > 0)
+ return false;
+ return true;
+ }
+
+ public static T[] GetExpChangeArray<T>(int cSize)
+ {
+ T[] array = new T[cSize];
+
+ for (int i = array.Length - 1; i >= 0; --i)
+ array[i] = (T)Convert.ChangeType(array.Length - 1 - i, typeof(T));
+
+ return array;
+ }
+
+ public static bool CheckAndChangeArray<T>(ref T[] arrArg, ref T arrSize, int actualArrSize, int expectedArrSize)
+ {
+ T[] actualArr = InitArray<T>(actualArrSize);
+ if (!EqualArray<T>(arrArg, actualArrSize, actualArr, actualArrSize))
+ {
+ return false;
+ }
+
+ arrSize = (T)Convert.ChangeType(expectedArrSize, typeof(T));
+ arrArg = GetExpChangeArray<T>(expectedArrSize);
+ return true;
+ }
+
+ #endregion
+
+}
\ No newline at end of file
--- /dev/null
+// 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.
+
+// helper.h : Defines helper functions
+#include <xplatform.h>
+#include "platformdefines.h"
+
+
+const LONG Array_Size = 10;
+const LONG CArray_Size = 20;
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify helper methods
+//////////////////////////////////////////////////////////////////////////////
+template<typename T> BOOL IsObjectEquals(T o1, T o2)
+{
+ // T::operator== required.
+ return o1 == o2;
+}
+
+//Int32 helper
+template<typename T>
+T* InitArray(SIZE_T arrSize)
+{
+ T* pExpectArr = (T*)CoreClrAlloc(sizeof(T)*arrSize);
+ for(SIZE_T i = 0;i<arrSize;++i)
+ {
+ pExpectArr[i] = (T)i;
+ }
+ return pExpectArr;
+}
+
+template<typename T>
+T* InitExpectedArray(SIZE_T arrSize)
+{
+ T* pExpectArr = (T*)CoreClrAlloc(sizeof(T)*arrSize);
+ for(SIZE_T i = 0;i<arrSize;++i)
+ {
+ pExpectArr[i] = arrSize - 1 - i;
+ }
+ return pExpectArr;
+}
+
+template<typename T>
+BOOL EqualArray(T* actualArray, SIZE_T actualSize, T* expectedArray, SIZE_T expectedSize)
+{
+ int failures = 0;
+
+ if(actualArray == NULL && expectedArray == NULL)
+ {
+ printf("Two arrays are equal. Both of them are NULL\n");
+ return TRUE;
+ }
+ else if(actualArray == NULL && expectedArray != NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is NULL,but the Compared is not NULL!\n");
+ return FALSE;
+ }
+ else if(actualArray != NULL && expectedArray == NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is not NULL,but the Compared is NULL!\n");
+ return FALSE;
+ }
+ else if(actualSize != expectedSize)
+ {
+ printf("Two arrays aren't equal. The arrays size are not equal. Expected:%d, Actual:%d!\n",(int)expectedSize,(int)actualSize);
+ return FALSE;
+ }
+ for(SIZE_T i = 0;i<actualSize;++i)
+ {
+ if(actualArray[i] != expectedArray[i])
+ {
+ printf("Two arrays aren't equal.The value of index of %d isn't equal!\n",(int)i);
+ printf("\tThe value in array from managed to native is %d\n",(int)actualArray[i]);
+ printf("\tThe value in expected array is %d\n",(int)expectedArray[i]);
+ failures++;
+ }
+ }
+ if(failures>0)
+ return FALSE;
+ return TRUE;
+}
+
+template<typename T>
+BOOL CheckAndChangeArrayByRef(T ** ppActual, T* Actual_Array_Size, SIZE_T Expected_Array_Size, SIZE_T Return_Array_Size)
+{
+ T* pExpectedArr = InitArray<T>(Expected_Array_Size);
+ if(!EqualArray(*ppActual, (SIZE_T)*Actual_Array_Size, pExpectedArr, Expected_Array_Size))
+ {
+ printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(pExpectedArr);
+ CoreClrFree(*ppActual);
+ *ppActual = (T*)CoreClrAlloc(sizeof(T)*Return_Array_Size);
+
+ *Actual_Array_Size = ((T)Return_Array_Size);
+ for(SIZE_T i = 0; i < Return_Array_Size; ++i)
+ {
+ (*ppActual)[i] = (T)(Return_Array_Size - 1 - i);
+ }
+ return TRUE;
+}
+
+template<typename T>
+BOOL CheckAndChangeArrayByOut(T ** ppActual, T* Actual_Array_Size, SIZE_T Array_Size)
+{
+ *ppActual = (T*)CoreClrAlloc(sizeof(T)*Array_Size);
+ *Actual_Array_Size = ((T)Array_Size);
+
+ for(SIZE_T i = 0; i < Array_Size; ++i)
+ {
+ (*ppActual)[i] = (T)(Array_Size - 1 - i);
+ }
+ return TRUE;
+}
+
+//template<typename T>
+//BOOL CheckReturnArray(T* pReturnArr, T Actual_Array_Size, T Expected_Array_Size)
+//{
+// T* pExpectedArr = InitExpectedArray(Expected_Array_Size);
+//
+// if(!EqualArray(pReturnArr, Actual_Array_Size, pExpectedArr, Expected_Array_Size))
+// {
+// printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+// CoreClrFree(pExpectedArr);
+// return FALSE;
+// }
+// else
+// {
+// //printf("Managed to Native:Passed!\n");
+// CoreClrFree(pExpectedArr);
+// return TRUE;
+// }
+//}
+
+//BSTR helper
+#ifdef _WIN32
+template<> BOOL IsObjectEquals(BSTR o1, BSTR o2)
+{
+ if ( o1 == NULL && o2 == NULL )
+ return TRUE;
+ else if ( o1 == NULL && o2 != NULL )
+ return FALSE;
+ else if ( o1 != NULL && o2 == NULL )
+ return FALSE;
+
+ UINT uLen1 = SysStringLen(o1);
+ UINT uLen2 = SysStringLen(o2);
+
+ if (uLen1 != uLen2 )
+ return FALSE;
+
+ return memcmp(o1, o2, uLen1) == 0;
+}
+
+BSTR ToBSTR(int i)
+{
+ BSTR bstrRet = NULL;
+ VarBstrFromI4(i, 0, 0, &bstrRet);
+
+ return bstrRet;
+}
+
+BOOL CmpBSTR(BSTR bstr1, BSTR bstr2)
+{
+ UINT uLen1 = SysStringLen(bstr1);
+ UINT uLen2 = SysStringLen(bstr2);
+
+ if (uLen1 != uLen2 )
+ return FALSE;
+ return memcmp(bstr1, bstr2, uLen1) == 0;
+}
+
+BSTR* InitArrayBSTR(LONG arrSize)
+{
+ BSTR* pExpectArr = (BSTR*)CoreClrAlloc(sizeof(BSTR)*arrSize);
+ for(LONG i = 0;i<arrSize;++i)
+ {
+ pExpectArr[i] = ToBSTR(i);
+ }
+ return pExpectArr;
+}
+
+BOOL EqualArrayBSTR(BSTR* ArrBSTR, LONG arrSize1, BSTR* CArrBSTR, LONG arrSize2)
+{
+ int failures = 0;
+
+ if(ArrBSTR == NULL && CArrBSTR == NULL)
+ {
+ printf("Two arrays are equal. Both of them NULL\n");
+ return TRUE;
+ }
+ else if(ArrBSTR == NULL && CArrBSTR != NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is NULL,but the Compared is not NULL!\n");
+ return FALSE;
+ }
+ else if(ArrBSTR != NULL && CArrBSTR == NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is not NULL,but the Compared is NULL!\n");
+ return FALSE;
+ }
+ else if(arrSize1 != arrSize2)
+ {
+ printf("Two arrays aren't equal. The arrays size are not equal!\n");
+ return FALSE;
+ }
+ for(int i = 0;i<arrSize1;++i)
+ {
+ if(!CmpBSTR(ArrBSTR[i],CArrBSTR[i]))
+ {
+ printf("Two arrays aren't equal.The value of index of %d isn't equal!\n",i);
+ printf("\tThe value in array from managed to native is %S\n",ArrBSTR[i]);
+ printf("\tThe value in expected array is %S\n",CArrBSTR[i]);
+ failures++;
+ }
+ }
+ if(failures>0)
+ return FALSE;
+ return TRUE;
+}
+#endif
--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+project (ReversePInvokePassingByOutNative)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+include_directories("..")
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES
+ ReversePInvokePassingByOutNative.cpp
+)
+# Additional files to reference:
+# add the executable
+add_library (ReversePInvokePassingByOutNative SHARED ${SOURCES})
+target_link_libraries(ReversePInvokePassingByOutNative ${LINK_LIBRARIES_ADDITIONAL})
+# add the install targets
+install (TARGETS ReversePInvokePassingByOutNative DESTINATION bin)
--- /dev/null
+// 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;
+
+public class ReversePInvoke_MashalArrayByOut_AsManagedTest
+{
+ public static int arrSize = 10;
+
+ public static int failures = 0;
+
+ #region Func Sig
+
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalByteArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelByteArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalSbyteArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelSbyteArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalShortArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelShortArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelShortArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalUshortArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelUshortArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalInt32Array_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelInt32ArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalUint32Array_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelUint32ArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalLongArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelLongArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalUlongArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelUlongArrByOutAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByOutNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalStringArray_AsParam_AsByOut([MarshalAs(UnmanagedType.FunctionPtr)]DelStringArrByOutAsCdeclCaller caller);
+
+ #endregion
+
+ #region Delegate Method
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelByteArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out byte[] arrArg, out byte arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelSbyteArrByOutAsCdeclCaller(out sbyte arraySize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out sbyte[] arrArg);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelShortArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out short[] arrArg, out short arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelUshortArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out ushort[] arrArg, out ushort arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelInt32ArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out Int32[] arrArg, out Int32 arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelUint32ArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out UInt32[] arrArg, out UInt32 arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelLongArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out long[] arrArg, out long arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelUlongArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out ulong[] arrArg, out ulong arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelStringArrByOutAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1, ArraySubType = UnmanagedType.BStr)] out string[] arrArg, out Int32 arraySize);
+
+ #endregion
+
+ #region Test Method
+
+ //Type: byte ==> BYTE Array Size: byte.MinValue ==> 20
+ public static bool TestMethodForByteArray_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out byte[] arrArg, out byte arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<byte>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: sbyte ==> CHAR Array Size: 1 ==> sbyte.MaxValue
+ public static bool TestMethodForSbyteArray_AsReversePInvokeByOut_AsCdecl(out sbyte arraySize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out sbyte[] arrArg)
+ {
+ arrArg = Helper.GetExpChangeArray<sbyte>(sbyte.MaxValue);
+ arraySize = sbyte.MaxValue;
+ return true;
+ }
+
+ //Type: short ==> SHORT Array Size: -1 ==> 20(Actual 10 ==> 20)
+ public static bool TestMethodForShortArray_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out short[] arrArg, out short arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<short>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: short ==> SHORT Array Size: 10 ==> -1(Actual 10 ==> 20)
+ public static bool TestMethodForShortArrayReturnNegativeSize_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out short[] arrArg, out short arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<short>(20);
+ arraySize = -1;
+ return true;
+ }
+
+ //Type: ushort ==> USHORT Array Size: ushort.MaxValue ==> 20
+ public static bool TestMethodForUshortArray_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out ushort[] arrArg, out ushort arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<ushort>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: Int32 ==> LONG Array Size: 10 ==> 20
+ public static bool TestMethodForInt32Array_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out Int32[] arrArg, out Int32 arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<Int32>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: UInt32 ==> ULONG Array Size: 10 ==> 20
+ public static bool TestMethodForUint32Array_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out UInt32[] arrArg, out UInt32 arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<UInt32>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: long ==> LONGLONG Array Size: 10 ==> 20
+ public static bool TestMethodForLongArray_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out long[] arrArg, out long arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<long>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: ulong ==> ULONGLONG Array Size: 10 ==> 20
+ public static bool TestMethodForUlongArray_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out ulong[] arrArg, out ulong arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<ulong>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ //Type: string ==> BSTR Array Size: 10 ==> 20
+ public static bool TestMethodForStringArray_AsReversePInvokeByOut_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1, ArraySubType = UnmanagedType.BStr)] out string[] arrArg, out Int32 arraySize)
+ {
+ arrArg = Helper.GetExpChangeArray<string>(20);
+ arraySize = 20;
+ return true;
+ }
+
+ #endregion
+
+ public static void RunTestByOut()
+ {
+ Console.WriteLine("ReversePInvoke C-Style Array marshaled by out with SizeParamIndex attribute(by out Array size).");
+
+ //Common value type
+ Console.WriteLine("\tScenario 1 : byte ==> BYTE, Array_Size = byte.MinValue, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalByteArray_AsParam_AsByOut(new DelByteArrByOutAsCdeclCaller(TestMethodForByteArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalByteArray_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 2 : sbyte ==> CHAR, Array_Size = 1, Return_Array_Size = sbyte.Max");
+ Assert.IsTrue(DoCallBack_MarshalSbyteArray_AsParam_AsByOut(new DelSbyteArrByOutAsCdeclCaller(TestMethodForSbyteArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalSbyteArray_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 3 : short ==> SHORT, Array_Size = -1, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalShortArray_AsParam_AsByOut(new DelShortArrByOutAsCdeclCaller(TestMethodForShortArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalShortArray_AsReversePInvokeByOut_AsCdecl Failed!");
+
+ Console.WriteLine("\tScenario 4 : short ==> SHORT, Array_Size = 10, Return_Array_Size = -1");
+ Assert.IsTrue(DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByOut(new DelShortArrByOutAsCdeclCaller(TestMethodForShortArrayReturnNegativeSize_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalShortArray_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 5 : ushort ==> USHORT, Array_Size = ushort.MaxValue, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalUshortArray_AsParam_AsByOut(new DelUshortArrByOutAsCdeclCaller(TestMethodForUshortArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalUshortArray_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 6 : Int32 ==> LONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalInt32Array_AsParam_AsByOut(new DelInt32ArrByOutAsCdeclCaller(TestMethodForInt32Array_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalInt32Array_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 7 : UInt32 ==> ULONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalUint32Array_AsParam_AsByOut(new DelUint32ArrByOutAsCdeclCaller(TestMethodForUint32Array_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalUint32Array_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 8 : long ==> LONGLONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalLongArray_AsParam_AsByOut(new DelLongArrByOutAsCdeclCaller(TestMethodForLongArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalLongArray_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 9 : ulong ==> ULONGLONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalUlongArray_AsParam_AsByOut(new DelUlongArrByOutAsCdeclCaller(TestMethodForUlongArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalUlongArray_AsReversePInvokeByOut_AsCdecl Passed!");
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ Console.WriteLine("\tScenario 10 : string ==> BSTR, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalStringArray_AsParam_AsByOut(new DelStringArrByOutAsCdeclCaller(TestMethodForStringArray_AsReversePInvokeByOut_AsCdecl)));
+ Console.WriteLine("\t\tMarshalStringArray_AsReversePInvokeByOut_AsCdecl Passed!");
+ }
+ }
+
+ public static int Main()
+ {
+ try{
+ RunTestByOut();
+ return 100;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+ }
+}
--- /dev/null
+<?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" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>PassingByOutTest</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>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </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="PassingByOutTest.cs" />
+ <Compile Include="..\helper.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="../../../../Interop.settings.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+// 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.
+
+// ReversePInvokePassingByOutNative.cpp : Defines the entry point for the DLL application.
+//
+#include <xplatform.h>
+#include <limits.h>
+#include "platformdefines.h"
+#include "helper.h"
+
+//Func Pointer
+typedef BOOL (__cdecl *DelByteArrByOutAsCdeclCaller)(BYTE** arrByte, BYTE* arraySize);
+typedef BOOL (__cdecl *DelSbyteArrByOutAsCdeclCaller)(CHAR* arraySize, CHAR** arrSbyte);
+typedef BOOL (__cdecl *DelShortArrByOutAsCdeclCaller)(SHORT** arrShort, SHORT* arraySize);
+typedef BOOL (__cdecl *DelUshortArrByOutAsCdeclCaller)(USHORT** arrUshort, USHORT* arraySize);
+typedef BOOL (__cdecl *DelInt32ArrByOutAsCdeclCaller)(LONG** arrInt32, LONG* arraySize);
+typedef BOOL (__cdecl *DelUint32ArrByOutAsCdeclCaller)(ULONG** arrUint32, ULONG* arraySize);
+typedef BOOL (__cdecl *DelLongArrByOutAsCdeclCaller)(LONGLONG** arrLong, LONGLONG* arraySize);
+typedef BOOL (__cdecl *DelUlongArrByOutAsCdeclCaller)(ULONGLONG** arrUlong, ULONGLONG* arraySize);
+typedef BOOL (__cdecl *DelStringArrByOutAsCdeclCaller)(BSTR** arrString, LONG* arraySize);
+
+//#######################################################
+//Test Method
+//#######################################################
+
+//BYTE 0 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalByteArray_AsParam_AsByOut(DelByteArrByOutAsCdeclCaller caller)
+{
+ BYTE arrSize = 0;
+ BYTE* arrByte = InitArray<BYTE>(arrSize);
+
+ if(!caller(&arrByte, &arrSize))
+ {
+ printf("DoCallBack_MarshalByteArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrByte);
+ return FALSE;
+ }
+
+ return CheckArray(arrByte, arrSize, (BYTE)20);
+}
+
+//CHAR 1 ==> CHAR.Max size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalSbyteArray_AsParam_AsByOut(DelSbyteArrByOutAsCdeclCaller caller)
+{
+ CHAR arrSize = 1;
+ CHAR* arrSbyte = InitArray<CHAR>((size_t)arrSize);
+
+ if(!caller(&arrSize, &arrSbyte))
+ {
+ printf("DoCallBack_MarshalSbyteArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrSbyte);
+ return FALSE;
+ }
+
+ return CheckArray(arrSbyte, (size_t)arrSize, (CHAR)127);
+}
+
+//SHORT -1 ==> 20 size Array(Actual: 10 ==> 20)
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalShortArray_AsParam_AsByOut(DelShortArrByOutAsCdeclCaller caller)
+{
+ SHORT arrSize = -1;
+ SHORT* arrShort = InitArray<SHORT>(SHORT(10));
+
+ if(!caller(&arrShort, &arrSize))
+ {
+ printf("DoCallBack_MarshalShortArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrShort);
+ return FALSE;
+ }
+
+ return CheckArray(arrShort, (size_t)arrSize, (SHORT)20);
+}
+
+//SHORT 10 ==> -1 size Array(Actual: 10 ==> 20)
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByOut(DelShortArrByOutAsCdeclCaller caller)
+{
+ SHORT arrSize = 10;
+ SHORT* arrShort = InitArray<SHORT>((size_t)arrSize);
+
+ if(!caller(&arrShort, &arrSize))
+ {
+ printf("DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrShort);
+ return FALSE;
+ }
+
+ if(arrSize == -1)
+ return CheckArray(arrShort, (SHORT)20, (SHORT)20);
+ else
+ return FALSE;
+}
+
+//USHORT ushort.Max ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalUshortArray_AsParam_AsByOut(DelUshortArrByOutAsCdeclCaller caller)
+{
+ USHORT arrSize = 65535;
+ USHORT* arrUshort = InitArray<USHORT>(arrSize);
+
+ if(!caller(&arrUshort, &arrSize))
+ {
+ printf("DoCallBack_MarshalUshortArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrUshort);
+ return FALSE;
+ }
+
+ return CheckArray(arrUshort, arrSize, (USHORT)20);
+}
+
+//Int32 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalInt32Array_AsParam_AsByOut(DelInt32ArrByOutAsCdeclCaller caller)
+{
+ LONG arrSize = 10;
+ LONG* arrInt32 = InitArray<LONG>((size_t)arrSize);
+
+ if(!caller(&arrInt32, &arrSize))
+ {
+ printf("DoCallBack_MarshalInt32Array_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrInt32);
+ return FALSE;
+ }
+
+ return CheckArray(arrInt32, (size_t)arrSize, (LONG)20);
+}
+
+//UInt32 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalUint32Array_AsParam_AsByOut(DelUint32ArrByOutAsCdeclCaller caller)
+{
+ ULONG arrSize = 10;
+ ULONG* arrUint32 = InitArray<ULONG>(arrSize);
+
+ if(!caller(&arrUint32, &arrSize))
+ {
+ printf("DoCallBack_MarshalUint32Array_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrUint32);
+ return FALSE;
+ }
+
+ return CheckArray(arrUint32, arrSize, (ULONG)20);
+}
+
+//LONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalLongArray_AsParam_AsByOut(DelLongArrByOutAsCdeclCaller caller)
+{
+ LONGLONG arrSize = 10;
+ LONGLONG* arrLong = InitArray<LONGLONG>((SIZE_T)arrSize);
+
+ if(!caller(&arrLong, &arrSize))
+ {
+ printf("DoCallBack_MarshalLongArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrLong);
+ return FALSE;
+ }
+
+ return CheckArray(arrLong, (SIZE_T)arrSize, 20);
+}
+
+//ULONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalUlongArray_AsParam_AsByOut(DelUlongArrByOutAsCdeclCaller caller)
+{
+ ULONGLONG arrSize = 10;
+ ULONGLONG* arrUlong = InitArray<ULONGLONG>((SIZE_T)arrSize);
+
+ if(!caller(&arrUlong, &arrSize))
+ {
+ printf("DoCallBack_MarshalUlongArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrUlong);
+ return FALSE;
+ }
+
+ return CheckArray(arrUlong, (SIZE_T)arrSize, 20);
+}
+
+#ifdef _WIN32
+//BSTR 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalStringArray_AsParam_AsByOut(DelStringArrByOutAsCdeclCaller caller)
+{
+ LONG arrSize = 10;
+ BSTR* arrString = InitArrayBSTR(arrSize);
+
+ if(!caller(&arrString, &arrSize))
+ {
+ printf("DoCallBack_MarshalStringArray_AsParam_AsByOut:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrString);
+ return FALSE;
+ }
+
+ LONG ExpectedArraySize = 20;
+ BSTR* pExpectedArr = (BSTR*)CoreClrAlloc(sizeof(BSTR)*ExpectedArraySize);
+ for(LONG i = 0; i < ExpectedArraySize; ++i)
+ {
+ pExpectedArr[i] = ToBSTR(ExpectedArraySize - 1 - i);
+ }
+
+ if(!EqualArrayBSTR(arrString, arrSize, pExpectedArr, ExpectedArraySize))
+ {
+ printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(arrString);
+ CoreClrFree(pExpectedArr);
+ return TRUE;
+}
+#endif
--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+project (ReversePInvokePassingByRefNative)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+include_directories("..")
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES
+ ReversePInvokePassingByRefNative.cpp
+)
+# Additional files to reference:
+# add the executable
+add_library (ReversePInvokePassingByRefNative SHARED ${SOURCES})
+target_link_libraries(ReversePInvokePassingByRefNative ${LINK_LIBRARIES_ADDITIONAL})
+# add the install targets
+install (TARGETS ReversePInvokePassingByRefNative DESTINATION bin)
--- /dev/null
+// 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;
+
+public class ReversePInvoke_MashalArrayByRef_AsManagedTest
+{
+ public static int arrSize = 10;
+
+ public static int failures = 0;
+
+ #region Func Sig
+
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalByteArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelByteArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalSbyteArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelSbyteArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalShortArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelShortArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelShortArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalUshortArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelUshortArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalInt32Array_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelInt32ArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalUint32Array_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelUint32ArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalLongArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelLongArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalUlongArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelUlongArrByRefAsCdeclCaller caller);
+ [DllImport("ReversePInvokePassingByRefNative", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool DoCallBack_MarshalStringArray_AsParam_AsByRef([MarshalAs(UnmanagedType.FunctionPtr)]DelStringArrByRefAsCdeclCaller caller);
+
+ #endregion
+
+ #region Delegate Method
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelByteArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref byte[] arrArg, ref byte arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelSbyteArrByRefAsCdeclCaller(ref sbyte arraySize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref sbyte[] arrArg);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelShortArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref short[] arrArg, ref short arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelUshortArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref ushort[] arrArg, ref ushort arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelInt32ArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref Int32[] arrArg, ref Int32 arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelUint32ArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref UInt32[] arrArg, ref UInt32 arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelLongArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref long[] arrArg, ref long arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelUlongArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref ulong[] arrArg, ref ulong arraySize);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate bool DelStringArrByRefAsCdeclCaller([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1, ArraySubType = UnmanagedType.BStr)] ref string[] arrArg, ref Int32 arraySize);
+
+ #endregion
+
+ #region Test Method
+
+ //Type: byte ==> BYTE Array Size: byte.MinValue ==> 20
+ public static bool TestMethodForByteArray_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref byte[] arrArg, ref byte arraySize)
+ {
+ if (arraySize == byte.MinValue)
+ return Helper.CheckAndChangeArray<byte>(ref arrArg, ref arraySize, (Int32)byte.MinValue, 20);
+ return false;
+ }
+
+ //Type: sbyte ==> CHAR Array Size: 1 ==> sbyte.MaxValue
+ public static bool TestMethodForSbyteArray_AsReversePInvokeByRef_AsCdecl(ref sbyte arraySize, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] ref sbyte[] arrArg)
+ {
+ if (arraySize == 1)
+ return Helper.CheckAndChangeArray<sbyte>(ref arrArg, ref arraySize, 1, (Int32)sbyte.MaxValue);
+ return false;
+ }
+
+ //Type: short ==> SHORT Array Size: -1 ==> 20(Actual 10 ==> 20)
+ public static bool TestMethodForShortArray_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref short[] arrArg, ref short arraySize)
+ {
+ if (arraySize == -1)
+ return Helper.CheckAndChangeArray<short>(ref arrArg, ref arraySize, 10, 20);
+ return false;
+ }
+
+ //Type: short ==> SHORT Array Size: 10 ==> -1(Actual 10 ==> 20)
+ public static bool TestMethodForShortArrayReturnNegativeSize_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref short[] arrArg, ref short arraySize)
+ {
+ if (arraySize == 10)
+ {
+ Helper.CheckAndChangeArray<short>(ref arrArg, ref arraySize, 10, 20);
+ arraySize = -1;
+ return true;
+ }
+ return false;
+ }
+
+ //Type: ushort ==> USHORT Array Size: ushort.MaxValue ==> 20
+ public static bool TestMethodForUshortArray_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref ushort[] arrArg, ref ushort arraySize)
+ {
+ if (arraySize == ushort.MaxValue)
+ return Helper.CheckAndChangeArray<ushort>(ref arrArg, ref arraySize, (Int32)ushort.MaxValue, 20);
+ return false;
+ }
+
+ //Type: Int32 ==> LONG Array Size: 10 ==> 20
+ public static bool TestMethodForInt32Array_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref Int32[] arrArg, ref Int32 arraySize)
+ {
+ if (arraySize == 10)
+ return Helper.CheckAndChangeArray<Int32>(ref arrArg, ref arraySize, 10, 20);
+ return false;
+ }
+
+ //Type: UInt32 ==> ULONG Array Size: 10 ==> 20
+ public static bool TestMethodForUint32Array_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref UInt32[] arrArg, ref UInt32 arraySize)
+ {
+ if (arraySize == 10)
+ return Helper.CheckAndChangeArray<UInt32>(ref arrArg, ref arraySize, 10, 20);
+ return false;
+ }
+
+ //Type: long ==> LONGLONG Array Size: 10 ==> 20
+ public static bool TestMethodForLongArray_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref long[] arrArg, ref long arraySize)
+ {
+ if (arraySize == 10)
+ return Helper.CheckAndChangeArray<long>(ref arrArg, ref arraySize, 10, 20);
+ return false;
+ }
+
+ //Type: ulong ==> ULONGLONG Array Size: 10 ==> 20
+ public static bool TestMethodForUlongArray_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ref ulong[] arrArg, ref ulong arraySize)
+ {
+ if (arraySize == 10)
+ return Helper.CheckAndChangeArray<ulong>(ref arrArg, ref arraySize, 10, 20);
+ return false;
+ }
+
+ //Type: string ==> BSTR Array Size: 10 ==> 20
+ public static bool TestMethodForStringArray_AsReversePInvokeByRef_AsCdecl([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1, ArraySubType = UnmanagedType.BStr)] ref string[] arrArg, ref Int32 arraySize)
+ {
+ string[] actualArr = Helper.InitArray<string>(10);
+ if (!Helper.EqualArray<string>(arrArg, arraySize, actualArr, 10))
+ {
+ return false;
+ }
+
+ arraySize = 20;
+ arrArg = Helper.GetExpChangeArray<string>(20);
+ return true;
+ }
+
+ #endregion
+
+ public static void RunTestByRef()
+ {
+ Console.WriteLine("ReversePInvoke C-Style Array marshaled by ref with SizeParamIndex attribute(by ref Array size).");
+
+ //Common value type
+ Console.WriteLine("\tScenario 1 : byte ==> BYTE, Array_Size = byte.MinValue, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalByteArray_AsParam_AsByRef(new DelByteArrByRefAsCdeclCaller(TestMethodForByteArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalByteArray_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 2 : sbyte ==> CHAR, Array_Size = 1, Return_Array_Size = sbyte.Max");
+ Assert.IsTrue(DoCallBack_MarshalSbyteArray_AsParam_AsByRef(new DelSbyteArrByRefAsCdeclCaller(TestMethodForSbyteArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalSbyteArray_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ // We don't support exception interop in .NET Core off-Windows.
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ Console.WriteLine("\tScenario 3 : short ==> SHORT, Array_Size = -1, Return_Array_Size = 20");
+ Assert.Throws<OverflowException>(() => DoCallBack_MarshalShortArray_AsParam_AsByRef(new DelShortArrByRefAsCdeclCaller(TestMethodForShortArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalShortArray_AsReversePInvokeByRef_AsCdecl Passed!");
+ }
+
+
+ Console.WriteLine("\tScenario 4 : short ==> SHORT, Array_Size = 10, Return_Array_Size = -1");
+ Assert.IsTrue(DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByRef(new DelShortArrByRefAsCdeclCaller(TestMethodForShortArrayReturnNegativeSize_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalShortArray_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 5 : ushort ==> USHORT, Array_Size = ushort.MaxValue, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalUshortArray_AsParam_AsByRef(new DelUshortArrByRefAsCdeclCaller(TestMethodForUshortArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalUshortArray_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 6 : Int32 ==> LONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalInt32Array_AsParam_AsByRef(new DelInt32ArrByRefAsCdeclCaller(TestMethodForInt32Array_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalInt32Array_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 7 : UInt32 ==> ULONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalUint32Array_AsParam_AsByRef(new DelUint32ArrByRefAsCdeclCaller(TestMethodForUint32Array_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalUint32Array_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 8 : long ==> LONGLONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalLongArray_AsParam_AsByRef(new DelLongArrByRefAsCdeclCaller(TestMethodForLongArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalLongArray_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ Console.WriteLine("\tScenario 9 : ulong ==> ULONGLONG, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalUlongArray_AsParam_AsByRef(new DelUlongArrByRefAsCdeclCaller(TestMethodForUlongArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalUlongArray_AsReversePInvokeByRef_AsCdecl Passed!");
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ Console.WriteLine("\tScenario 10 : string ==> BSTR, Array_Size = 10, Return_Array_Size = 20");
+ Assert.IsTrue(DoCallBack_MarshalStringArray_AsParam_AsByRef(new DelStringArrByRefAsCdeclCaller(TestMethodForStringArray_AsReversePInvokeByRef_AsCdecl)));
+ Console.WriteLine("\t\tMarshalStringArray_AsReversePInvokeByRef_AsCdecl Passed!");
+ }
+ }
+
+ public static int Main()
+ {
+ try{
+ RunTestByRef();
+ return 100;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+ }
+}
--- /dev/null
+<?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" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>PassingByRefTest</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>
+ <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+ </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="PassingByRefTest.cs" />
+ <Compile Include="..\helper.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="../../../../Interop.settings.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+// 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.
+
+// ReversePInvokePassingByRefNative.cpp : Defines the entry point for the DLL application.
+#include <xplatform.h>
+#include <limits.h>
+#include "platformdefines.h"
+#include "helper.h"
+
+//Func Pointer
+typedef BOOL (__cdecl *DelByteArrByRefAsCdeclCaller)(BYTE** arrByte, BYTE* arraySize);
+typedef BOOL (__cdecl *DelSbyteArrByRefAsCdeclCaller)(CHAR* arraySize, CHAR** arrSbyte);
+typedef BOOL (__cdecl *DelShortArrByRefAsCdeclCaller)(SHORT** arrShort, SHORT* arraySize);
+typedef BOOL (__cdecl *DelUshortArrByRefAsCdeclCaller)(USHORT** arrUshort, USHORT* arraySize);
+typedef BOOL (__cdecl *DelInt32ArrByRefAsCdeclCaller)(LONG** arrInt32, LONG* arraySize);
+typedef BOOL (__cdecl *DelUint32ArrByRefAsCdeclCaller)(ULONG** arrUint32, ULONG* arraySize);
+typedef BOOL (__cdecl *DelLongArrByRefAsCdeclCaller)(LONGLONG** arrLong, LONGLONG* arraySize);
+typedef BOOL (__cdecl *DelUlongArrByRefAsCdeclCaller)(ULONGLONG** arrUlong, ULONGLONG* arraySize);
+typedef BOOL (__cdecl *DelStringArrByRefAsCdeclCaller)(BSTR** arrString, LONG* arraySize);
+
+//#######################################################
+//Test Method
+//#######################################################
+
+//BYTE 0 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalByteArray_AsParam_AsByRef(DelByteArrByRefAsCdeclCaller caller)
+{
+ BYTE arrSize = 0;
+ BYTE* arrByte = InitArray<BYTE>(arrSize);
+
+ if(!caller(&arrByte, &arrSize))
+ {
+ printf("DoCallBack_MarshalByteArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrByte);
+ return FALSE;
+ }
+
+ return CheckArray(arrByte, arrSize, (BYTE)20);
+}
+
+//CHAR 1 ==> CHAR.Max size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalSbyteArray_AsParam_AsByRef(DelSbyteArrByRefAsCdeclCaller caller)
+{
+ CHAR arrSize = 1;
+ CHAR* arrSbyte = InitArray<CHAR>((size_t)arrSize);
+
+ if(!caller(&arrSize, &arrSbyte))
+ {
+ printf("DoCallBack_MarshalSbyteArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrSbyte);
+ return FALSE;
+ }
+
+ return CheckArray(arrSbyte, (size_t)arrSize, (CHAR)127);
+}
+
+//SHORT -1 ==> 20 size Array(Actual: 10 ==> 20)
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalShortArray_AsParam_AsByRef(DelShortArrByRefAsCdeclCaller caller)
+{
+ SHORT arrSize = -1;
+ SHORT* arrShort = InitArray<SHORT>(SHORT(10));
+
+ if(!caller(&arrShort, &arrSize))
+ {
+ printf("DoCallBack_MarshalShortArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrShort);
+ return FALSE;
+ }
+
+ return CheckArray(arrShort, (size_t)arrSize, (SHORT)20);
+}
+
+//SHORT 10 ==> -1 size Array(Actual: 10 ==> 20)
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByRef(DelShortArrByRefAsCdeclCaller caller)
+{
+ SHORT arrSize = 10;
+ SHORT* arrShort = InitArray<SHORT>((size_t)arrSize);
+
+ if(!caller(&arrShort, &arrSize))
+ {
+ printf("DoCallBack_MarshalShortArrayReturnNegativeSize_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrShort);
+ return FALSE;
+ }
+
+ if(arrSize == -1)
+ return CheckArray(arrShort, (SHORT)20, (SHORT)20);
+ else
+ return FALSE;
+}
+
+//USHORT ushort.Max ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalUshortArray_AsParam_AsByRef(DelUshortArrByRefAsCdeclCaller caller)
+{
+ USHORT arrSize = 65535;
+ USHORT* arrUshort = InitArray<USHORT>(arrSize);
+
+ if(!caller(&arrUshort, &arrSize))
+ {
+ printf("DoCallBack_MarshalUshortArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrUshort);
+ return FALSE;
+ }
+
+ return CheckArray(arrUshort, arrSize, (USHORT)20);
+}
+
+//Int32 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalInt32Array_AsParam_AsByRef(DelInt32ArrByRefAsCdeclCaller caller)
+{
+ LONG arrSize = 10;
+ LONG* arrInt32 = InitArray<LONG>((size_t)arrSize);
+
+ if(!caller(&arrInt32, &arrSize))
+ {
+ printf("DoCallBack_MarshalInt32Array_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrInt32);
+ return FALSE;
+ }
+
+ return CheckArray(arrInt32, (size_t)arrSize, (LONG)20);
+}
+
+//UInt32 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalUint32Array_AsParam_AsByRef(DelUint32ArrByRefAsCdeclCaller caller)
+{
+ ULONG arrSize = 10;
+ ULONG* arrUint32 = InitArray<ULONG>(arrSize);
+
+ if(!caller(&arrUint32, &arrSize))
+ {
+ printf("DoCallBack_MarshalUint32Array_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrUint32);
+ return FALSE;
+ }
+
+ return CheckArray(arrUint32, arrSize, (ULONG)20);
+}
+
+//LONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalLongArray_AsParam_AsByRef(DelLongArrByRefAsCdeclCaller caller)
+{
+ LONGLONG arrSize = 10;
+ LONGLONG* arrLong = InitArray<LONGLONG>(SIZE_T(arrSize));
+
+ if(!caller(&arrLong, &arrSize))
+ {
+ printf("DoCallBack_MarshalLongArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrLong);
+ return FALSE;
+ }
+
+ return CheckArray(arrLong, (SIZE_T)arrSize, 20);
+}
+
+//ULONGLONG 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalUlongArray_AsParam_AsByRef(DelUlongArrByRefAsCdeclCaller caller)
+{
+ ULONGLONG arrSize = 10;
+ ULONGLONG* arrUlong = InitArray<ULONGLONG>(SIZE_T(arrSize));
+
+ if(!caller(&arrUlong, &arrSize))
+ {
+ printf("DoCallBack_MarshalUlongArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrUlong);
+ return FALSE;
+ }
+
+ return CheckArray(arrUlong, (SIZE_T)arrSize, 20);
+}
+#ifdef _WIN32
+//BSTR 10 ==> 20 size Array
+extern "C" DLL_EXPORT BOOL __cdecl DoCallBack_MarshalStringArray_AsParam_AsByRef(DelStringArrByRefAsCdeclCaller caller)
+{
+ LONG arrSize = 10;
+ BSTR* arrString = InitArrayBSTR(arrSize);
+
+ if(!caller(&arrString, &arrSize))
+ {
+ printf("DoCallBack_MarshalStringArray_AsParam_AsByRef:\n\tThe Caller returns wrong value\n");
+ CoreClrFree(arrString);
+ return FALSE;
+ }
+
+ LONG ExpectedArraySize = 20;
+ BSTR* pExpectedArr = (BSTR*)CoreClrAlloc(sizeof(BSTR)*ExpectedArraySize);
+ for(LONG i = 0; i < ExpectedArraySize; ++i)
+ {
+ pExpectedArr[i] = ToBSTR(ExpectedArraySize - 1 - i);
+ }
+
+ if(!EqualArrayBSTR(arrString, arrSize, pExpectedArr, ExpectedArraySize))
+ {
+ printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(arrString);
+ CoreClrFree(pExpectedArr);
+ return TRUE;
+}
+#endif
--- /dev/null
+// 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;
+
+public class Helper
+{
+ #region General method
+
+ public static T[] InitArray<T>(int arrSize)
+ {
+ T[] array = new T[arrSize];
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = (T)Convert.ChangeType(i, typeof(T));
+ }
+ return array;
+ }
+
+ public static bool EqualArray<T>(T[] actualArray, int actualSize, T[] expArr, int arrSize2)
+ {
+ int failures = 0;
+ if (actualArray == null && expArr == null)
+ {
+ Console.WriteLine("\tTwo array are equal.Both of them null");
+ return true;
+ }
+ else if (actualArray == null && expArr != null)
+ {
+ Console.WriteLine("\tTwo array are not equal.The sourcArr is null,but the expArr is not null");
+ return false;
+ }
+ else if (actualArray != null && expArr == null)
+ {
+ Console.WriteLine("\tTwo array are not equal.The sourcArr is not null but the expArr is null");
+ return false;
+ }
+ else if (!actualSize.Equals(arrSize2))
+ {
+ Console.WriteLine("\tTwo array are not equal.The sizes are not equal");
+ return false;
+ }
+ for (int i = 0; i < arrSize2; ++i)
+ {
+ if (!actualArray[i].Equals(expArr[i]))
+ {
+ Console.WriteLine("\tTwo array are not equal.The values of index {0} are not equal!", i);
+ Console.WriteLine("\t\tThe actualArray is {0},the expArr is {1}", actualArray[i].ToString(), expArr[i].ToString());
+ failures++;
+ }
+ }
+ if (failures > 0)
+ return false;
+ return true;
+ }
+
+ public static T[] GetExpChangeArray<T>(int cSize)
+ {
+ T[] array = new T[cSize];
+
+ for (int i = array.Length - 1; i >= 0; --i)
+ array[i] = (T)Convert.ChangeType(array.Length - 1 - i, typeof(T));
+
+ return array;
+ }
+
+ public static bool CheckAndChangeArray<T>(ref T[] arrArg, ref T arrSize, int actualArrSize, int expectedArrSize)
+ {
+ T[] actualArr = InitArray<T>(actualArrSize);
+ if (!EqualArray<T>(arrArg, actualArrSize, actualArr, actualArrSize))
+ {
+ return false;
+ }
+
+ arrSize = (T)Convert.ChangeType(expectedArrSize, typeof(T));
+ arrArg = GetExpChangeArray<T>(expectedArrSize);
+ return true;
+ }
+
+ #endregion
+}
\ No newline at end of file
--- /dev/null
+// 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.
+
+// helper.h : Defines helper functions
+#include <xplatform.h>
+
+const LONG Array_Size = 10;
+const LONG CArray_Size = 20;
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify helper methods
+//////////////////////////////////////////////////////////////////////////////
+template<typename T>
+BOOL IsObjectEquals(T o1, T o2)
+{
+ // T::operator== required.
+ return o1 == o2;
+}
+
+//Int32 helper
+template<typename T>
+T* InitArray(SIZE_T arrSize)
+{
+ T* pExpectArr = (T*)CoreClrAlloc(sizeof(T)*arrSize);
+ for(SIZE_T i = 0;i<arrSize;++i)
+ {
+ pExpectArr[i] = (T)i;
+ }
+ return pExpectArr;
+}
+
+template<typename T>
+T* InitExpectedArray(SIZE_T arrSize)
+{
+ T* pExpectArr = (T*)CoreClrAlloc(sizeof(T)*arrSize);
+ for(SIZE_T i = 0;i<arrSize;++i)
+ {
+ pExpectArr[i] = (T)(arrSize - 1 - i);
+ }
+ return pExpectArr;
+}
+
+template<typename T>
+BOOL EqualArray(T* actualArray, SIZE_T actualSize, T* expectedArray, SIZE_T expectedSize)
+{
+ int failures = 0;
+
+ if(actualArray == NULL && expectedArray == NULL)
+ {
+ printf("Two arrays are equal. Both of them NULL\n");
+ return TRUE;
+ }
+ else if(actualArray == NULL && expectedArray != NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is NULL,but the Compared is not NULL!\n");
+ return FALSE;
+ }
+ else if(actualArray != NULL && expectedArray == NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is not NULL,but the Compared is NULL!\n");
+ return FALSE;
+ }
+ else if(actualSize != expectedSize)
+ {
+ printf("Two arrays aren't equal. The arrays size are not equal!\n");
+ return FALSE;
+ }
+ for(SIZE_T i = 0;i < actualSize; ++i)
+ {
+ if(actualArray[i] != expectedArray[i])
+ {
+ printf("Two arrays aren't equal.The value of index of %d isn't equal!\n",(int)i);
+ printf("\tThe value in actual rray is %d\n",(int)actualArray[i]);
+ printf("\tThe value in expected array is %d\n",(int)expectedArray[i]);
+ failures++;
+ }
+ }
+ if( failures > 0 )
+ return FALSE;
+ return TRUE;
+}
+
+template<typename T>
+BOOL CheckAndChangeArrayByRef(T ** ppActual, T* Actual_Array_Size, SIZE_T Expected_Array_Size, SIZE_T Return_Array_Size)
+{
+ T* pExpectedArr = InitArray<T>(Expected_Array_Size);
+ if(!EqualArray(*ppActual, *Actual_Array_Size, pExpectedArr, Expected_Array_Size))
+ {
+ printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+ return FALSE;
+ }
+
+ CoreClrFree(pExpectedArr);
+ CoreClrFree(*ppActual);
+ *ppActual = (T*)CoreClrAlloc(sizeof(T)*Return_Array_Size);
+
+ *Actual_Array_Size = ((T)Return_Array_Size);
+ for(SIZE_T i = 0; i < Return_Array_Size; ++i)
+ {
+ (*ppActual)[i] = Return_Array_Size - 1 - i;
+ }
+ return TRUE;
+}
+
+template<typename T>
+BOOL CheckAndChangeArrayByOut(T ** ppActual, T* Actual_Array_Size, SIZE_T Return_Array_Size)
+{
+ if(*ppActual != NULL )
+ {
+ printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+ printf("Array is not NULL");
+ return FALSE;
+ }
+
+ CoreClrFree(*ppActual);
+ *ppActual = (T*)CoreClrAlloc(sizeof(T)*Return_Array_Size);
+
+ *Actual_Array_Size = ((T)Return_Array_Size);
+ for(SIZE_T i = 0; i < Return_Array_Size; ++i)
+ {
+ (*ppActual)[i] = Return_Array_Size - 1 - i;
+ }
+ return TRUE;
+}
+
+template<typename T>
+BOOL CheckArray(T* pReturnArr, SIZE_T actualArraySize, SIZE_T expectedArraySize)
+{
+ T* pExpectedArr = InitExpectedArray<T>(expectedArraySize);
+
+ if(!EqualArray(pReturnArr, actualArraySize, pExpectedArr, expectedArraySize))
+ {
+ printf("ManagedtoNative Error in Method: %s!\n",__FUNCTION__);
+ CoreClrFree(pExpectedArr);
+ return FALSE;
+ }
+ else
+ {
+ CoreClrFree(pExpectedArr);
+ return TRUE;
+ }
+}
+
+//BSTR helper
+#ifdef _WIN32
+template<>
+BOOL IsObjectEquals(BSTR o1, BSTR o2)
+{
+ if ( o1 == NULL && o2 == NULL )
+ return TRUE;
+ else if ( o1 == NULL && o2 != NULL )
+ return FALSE;
+ else if ( o1 != NULL && o2 == NULL )
+ return FALSE;
+
+ UINT uLen1 = SysStringLen(o1);
+ UINT uLen2 = SysStringLen(o2);
+
+ if (uLen1 != uLen2 )
+ return FALSE;
+
+ return memcmp(o1, o2, uLen1) == 0;
+}
+
+BSTR ToBSTR(int i)
+{
+ BSTR bstrRet = NULL;
+ VarBstrFromI4(i, 0, 0, &bstrRet);
+
+ return bstrRet;
+}
+BOOL CmpBSTR(BSTR bstr1, BSTR bstr2)
+{
+ UINT uLen1 = SysStringLen(bstr1);
+ UINT uLen2 = SysStringLen(bstr2);
+
+ if (uLen1 != uLen2 )
+ return FALSE;
+ return memcmp(bstr1, bstr2, uLen1) == 0;
+}
+BSTR* InitArrayBSTR(LONG arrSize)
+{
+ BSTR* pExpectArr = (BSTR*)CoreClrAlloc(sizeof(BSTR)*arrSize);
+ for(LONG i = 0;i<arrSize;++i)
+ {
+ pExpectArr[i] = ToBSTR(i);
+ }
+ return pExpectArr;
+}
+BOOL EqualArrayBSTR(BSTR* actualBSTRArray, LONG actualSize, BSTR* expectedBSTRArray, LONG expectedSize)
+{
+ int failures = 0;
+
+ if(actualBSTRArray == NULL && expectedBSTRArray == NULL)
+ {
+ printf("Two arrays are equal. Both of them NULL\n");
+ return TRUE;
+ }
+ else if(actualBSTRArray == NULL && expectedBSTRArray != NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is NULL,but the Compared is not NULL!\n");
+ return FALSE;
+ }
+ else if(actualBSTRArray != NULL && expectedBSTRArray == NULL)
+ {
+ printf("Two arrays aren't equal. Array from Managed to Native is not NULL,but the Compared is NULL!\n");
+ return FALSE;
+ }
+ else if(actualSize != expectedSize)
+ {
+ printf("Two arrays aren't equal. The arrays size are not equal!\n");
+ return FALSE;
+ }
+ for(int i = 0;i < actualSize; ++i)
+ {
+ if(!CmpBSTR(actualBSTRArray[i],expectedBSTRArray[i]))
+ {
+ printf("Two arrays aren't equal.The value of index of %d isn't equal!\n",i);
+ printf("\tThe value in array from managed to native is %S\n",actualBSTRArray[i]);
+ printf("\tThe value in expected array is %S\n",expectedBSTRArray[i]);
+ failures++;
+ }
+ }
+ if(failures>0)
+ return FALSE;
+ return TRUE;
+}
+#endif
typedef unsigned short USHORT;
typedef signed short SHORT;
typedef unsigned short WORD, *PWORD, *LPWORD;
+typedef int LONG;
+
+typedef size_t SIZE_T;
#ifndef TRUE
#define TRUE 1