SET(CLR_INTEROP_TEST_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(common)
+add_subdirectory(PInvoke/Decimal/PInvoke)
+add_subdirectory(PInvoke/Decimal/ReversePInvoke)
add_subdirectory(PInvoke/ArrayWithOffset)
add_subdirectory(PInvoke/DllImportPath)
add_subdirectory(PInvoke/BestFitMapping/Char)
--- /dev/null
+#VCXPROJ
+cmake_minimum_required (VERSION 2.6)
+project (DecNative)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES
+ DecNative.cpp
+)
+# Additional files to reference:
+# add the executable
+add_library (DecNative SHARED ${SOURCES})
+target_link_libraries(DecNative ${LINK_LIBRARIES_ADDITIONAL})
+# add the install targets
+install (TARGETS DecNative 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.
+
+#include <iostream>
+#include <xplatform.h>
+#include "platformdefines.h"
+
+DECIMAL g_DECIMAL_MaxValue = { 0, {{ 0, 0 }}, 0xffffffff, {{0xffffffff, 0xffffffff}} };
+DECIMAL g_DECIMAL_MinValue = { 0, {{ 0, DECIMAL_NEG }}, 0xffffffff, {{0xffffffff, 0xffffffff}} };
+DECIMAL g_DECIMAL_Zero = { 0 };
+
+CY g_CY_MaxValue = { { 0xffffffff, 0x7fffffff } };
+CY g_CY_MinValue = { { (LONG)0x00000000, (LONG)0x80000000 } };
+CY g_CY_Zero = { { 0 } };
+
+typedef struct _Stru_Exp_DecAsCYAsFld
+{
+ WCHAR wc;
+ CY cy;
+} Stru_Exp_DecAsCYAsFld;
+
+typedef struct _Stru_Seq_DecAsLPStructAsFld
+{
+ DOUBLE dblVal;
+ WCHAR cVal;
+ DECIMAL* lpDec;
+} Stru_Seq_DecAsLPStructAsFld;
+
+void DecDisplay(const DECIMAL& dec)
+{
+ std::cout << "\twReserved" << "\t\t" << dec.wReserved << "\n"
+ << "\tscale" << "\t\t" << dec.scale << "\n"
+ << "\tsign" << "\t\t" << dec.sign << "\n"
+ << "\tsignscale" << "\t\t" << dec.signscale << "\n"
+ << "\tHi32" << "\t\t" << dec.Hi32 << "\n"
+ << "\tLo32" << "\t\t" << dec.Lo32 << "\n"
+ << "\tMid32" << "\t\t" << dec.Mid32 << "\n"
+ << "\tLo64" << "\t\t" << dec.Lo64 << std::endl;
+}
+
+template<typename T>
+bool operator==(const T& t1, const T& t2)
+{
+ return 0 == memcmp((void*)&t1, (void*)&t2, sizeof(T));
+}
+
+template<typename T>
+bool Equals(LPCSTR err_id, T expected, T actual)
+{
+ if(expected == actual)
+ return true;
+ else
+ {
+ std::cout << "\t#Native Side Err# -- " << err_id
+ << "\n\tExpected = " << expected << std::endl;
+ std::wcout << "\tActual is = " << actual << std::endl;
+
+ return false;
+ }
+}
+
+bool DecEqualsToExpected(LPCSTR err_id, const DECIMAL& expected, const DECIMAL& actual)
+{
+ if(expected == actual)
+ return true;
+ else
+ {
+ std::cout << "\t#Native Side Err # -- " << err_id
+ << "DECIMAL Expected is :" << std::endl;
+ DecDisplay(expected);
+
+ std::cout << "\t" << "____________________________________" << std::endl;
+
+ std::cout << "\tDECIMAL Actual is :" << std::endl;
+ DecDisplay(actual);
+
+ return false;
+ }
+}
+
+bool CYEqualsToExpected(LPCSTR err_id, const CY& expected, const CY& actual)
+{
+ if(expected == actual)
+ return true;
+ else
+ {
+ std::cout << "\t#Native Side Err# -- " << err_id
+ << "\n\tCY Expected is :" << "Hi = " << expected.Hi
+ << "Lo = " << expected.Lo << std::endl;
+
+ std::cout << "\tCY Actual is :" << "Hi = " << actual.Hi
+ << "Lo = " << actual.Lo << std::endl;
+
+ return false;
+ }
+}
+
+// DECIMAL
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeDecAsInOutParamAsLPStructByRef(DECIMAL** lppDec)
+{
+ if(DecEqualsToExpected("001.01", g_DECIMAL_MaxValue, **lppDec))
+ {
+ **lppDec = g_DECIMAL_MinValue;
+ return true;
+ }
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeDecAsOutParamAsLPStructByRef(DECIMAL** lppDec)
+{
+ if(*lppDec)
+ {
+ std::cout << "\t#Native Side Err# -- 001.02 DECIMAL* is not NULL" << std::endl;
+ return false;
+ }
+ else
+ {
+ *lppDec = (DECIMAL*)CoreClrAlloc(sizeof(DECIMAL));
+ **lppDec = g_DECIMAL_MinValue;
+
+ return true;
+ }
+}
+
+extern "C" DLL_EXPORT DECIMAL STDMETHODCALLTYPE RetDec()
+{
+ return g_DECIMAL_MaxValue;
+}
+
+// CY
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeCYAsInOutParamAsLPStructByRef(CY* lpCy)
+{
+ if(CYEqualsToExpected("002.01", g_CY_MaxValue, *lpCy))
+ {
+ *lpCy = g_CY_MinValue;
+ return true;
+ }
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeCYAsOutParamAsLPStructByRef(CY* lpCy)
+{
+ if(g_CY_Zero == *lpCy)
+ {
+ *lpCy = g_CY_MinValue;
+
+ return true;
+ }
+ else
+ {
+ std::cout << "\t#Native Side Err# -- 002.02 CY is not clear up." << std::endl;
+ return false;
+ }
+}
+
+extern "C" DLL_EXPORT CY STDMETHODCALLTYPE RetCY()
+{
+ return g_CY_MinValue;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeStru_Exp_DecAsCYAsFldByInOutRef(Stru_Exp_DecAsCYAsFld* s)
+{
+ if(CYEqualsToExpected("001.04.01", g_CY_Zero, s->cy) && Equals("001.04.02", W('\0'), s->wc))
+ {
+ s->cy = g_CY_MaxValue;
+ s->wc = W('C');
+
+ return true;
+ }
+ else
+ {
+ std::cout << "\t#Native Side Err# -- 002.02 Stru_Exp_DecAsCYAsFld is not clear up." << std::endl;
+ return false;
+ }
+}
--- /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;
+
+#pragma warning disable 618
+#region Struct Def
+[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
+public struct Stru_Exp_DecAsCYAsFld
+{
+ [FieldOffset(0)]
+ public char wc;
+
+ [FieldOffset(8)]
+ [MarshalAs(UnmanagedType.Currency)]
+ public decimal cy;
+}
+
+[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+public struct Stru_Seq_DecAsLPStructAsFld
+{
+ public double dblVal;
+
+ public char cVal;
+
+ [MarshalAs(UnmanagedType.LPStruct)]
+ public decimal dec;
+}
+#endregion
+
+public class CMain
+{
+ //DECIMAL
+ [DllImport("DecNative")]
+ static extern bool TakeDecAsInOutParamAsLPStructByRef([MarshalAs(UnmanagedType.LPStruct), In, Out] ref decimal dec);
+ [DllImport("DecNative")]
+ static extern bool TakeDecAsOutParamAsLPStructByRef([MarshalAs(UnmanagedType.LPStruct), Out] out decimal dec);
+ [DllImport("DecNative")]
+ [return: MarshalAs(UnmanagedType.LPStruct)]
+ static extern decimal RetDec();
+
+ //CY
+ [DllImport("DecNative")]
+ static extern bool TakeCYAsInOutParamAsLPStructByRef([MarshalAs(UnmanagedType.Currency), In, Out] ref decimal cy);
+ [DllImport("DecNative")]
+ static extern bool TakeCYAsOutParamAsLPStructByRef([MarshalAs(UnmanagedType.Currency), Out] out decimal cy);
+ [DllImport("DecNative")]
+ [return: MarshalAs(UnmanagedType.Currency)]
+ static extern decimal RetCY();
+ [DllImport("DecNative")]
+ static extern bool TakeStru_Exp_DecAsCYAsFldByInOutRef([Out] out Stru_Exp_DecAsCYAsFld s);
+
+ static int fails = 0;
+ static decimal CY_MAX_VALUE = 922337203685477.5807M;
+ static decimal CY_MIN_VALUE = -922337203685477.5808M;
+
+ static bool MarshalAsLPStruct()
+ {
+ Console.WriteLine("MarshalAsLPStruct started.");
+ // DECIMAL
+ decimal dec = decimal.MaxValue;
+ if (!TakeDecAsInOutParamAsLPStructByRef(ref dec))
+ {
+ Console.WriteLine("Test Failed: TakeDecAsInOutParamAsLPStructByRef : Returned false");
+ return false;
+ }
+ if (decimal.MinValue != dec)
+ {
+ Console.WriteLine($"Test Failed: Expected 'decimal.MinValue'. Got {dec}.");
+ return false;
+ }
+
+ dec = decimal.Zero;
+ if (!TakeDecAsOutParamAsLPStructByRef(out dec))
+ {
+ Console.WriteLine("Test Failed: TakeDecAsOutParamAsLPStructByRef : Returned false");
+ return false;
+ }
+ if (decimal.MinValue != dec)
+ {
+ Console.WriteLine($"Test Failed: Expected 'decimal.MinValue'. Got {dec}.");
+ return false;
+ }
+
+ bool exceptionThrown = false;
+ try
+ {
+ RetDec();
+ }
+ catch (MarshalDirectiveException)
+ {
+ exceptionThrown = true;
+ }
+
+ if (!exceptionThrown)
+ {
+ Console.WriteLine("Expected MarshalDirectiveException is not thrown");
+ return false;
+ }
+
+ Console.WriteLine("MarshalAsLPStruct end.");
+ return true;
+ }
+
+ static bool MarshalAsCurrencyScenario()
+ {
+ Console.WriteLine("MarshalAsCurrencyScenario started.");
+ //CY
+ decimal cy = CY_MAX_VALUE;
+ if (!TakeCYAsInOutParamAsLPStructByRef(ref cy))
+ {
+ Console.WriteLine("Test Failed: TakeCYAsInOutParamAsLPStructByRef : Returned false");
+ return false;
+ }
+ if (CY_MIN_VALUE != cy)
+ {
+ Console.WriteLine($"Test Failed: Expected 'CY_MIN_VALUE'. Got {cy}.");
+ return false;
+ }
+
+ cy = decimal.MaxValue;
+ if (!TakeCYAsOutParamAsLPStructByRef(out cy))
+ {
+ Console.WriteLine("Test Failed: TakeCYAsOutParamAsLPStructByRef : Returned false");
+ return false;
+ }
+ if (CY_MIN_VALUE != cy)
+ {
+ Console.WriteLine($"Test Failed: Expected 'CY_MIN_VALUE'. Got {cy}.");
+ return false;
+ }
+
+
+ bool exceptionThrown = false;
+ try
+ {
+ RetCY();
+ }
+ catch (MarshalDirectiveException)
+ {
+ exceptionThrown = true;
+ }
+
+ if (!exceptionThrown)
+ {
+ Console.WriteLine("Expected MarshalDirectiveException is not thrown");
+ return false;
+ }
+
+ Stru_Exp_DecAsCYAsFld s = new Stru_Exp_DecAsCYAsFld();
+ s.cy = CY_MAX_VALUE;
+ s.wc = 'I';
+ if (!TakeStru_Exp_DecAsCYAsFldByInOutRef(out s))
+ {
+ Console.WriteLine("Test Failed: TakeStru_Exp_DecAsCYAsFldByInOutRef : Returned false");
+ return false;
+ }
+ if (!TakeStru_Exp_DecAsCYAsFldByInOutRef(out s))
+ if (CY_MAX_VALUE != s.cy)
+ {
+ Console.WriteLine($"Test Failed: Expected 'CY_MAX_VALUE'. Got {s.cy}.");
+ return false;
+ }
+ if ('C' != s.wc)
+ {
+ Console.WriteLine($"Test Failed: Expected 'C'. Got {s.wc}.");
+ return false;
+ }
+
+ Console.WriteLine("MarshalAsCurrencyScenario end.");
+ return true;
+ }
+
+ static int Main()
+ {
+ bool success = true;
+ success = success && MarshalAsLPStruct();
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ success = success && MarshalAsCurrencyScenario();
+ }
+
+ return success ? 100 : 101;
+ }
+}
+#pragma warning restore 618
--- /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>DecimalTest</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="DecimalTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
--- /dev/null
+#VCXPROJ
+cmake_minimum_required (VERSION 2.6)
+project (RevNative)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES
+ RevNative.cpp
+)
+# add the executable
+add_library (RevNative SHARED ${SOURCES})
+target_link_libraries(RevNative ${LINK_LIBRARIES_ADDITIONAL})
+# add the install targets
+install (TARGETS RevNative 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;
+
+#pragma warning disable 618
+[StructLayout(LayoutKind.Sequential)]
+public struct Stru_Seq_DecAsStructAsFld
+{
+ public int number;
+
+ [MarshalAs(UnmanagedType.Struct)]
+ public decimal dec;
+}
+
+[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
+public struct Stru_Exp_DecAsCYAsFld
+{
+ [FieldOffset(0)]
+ public char wc;
+
+ [FieldOffset(8)]
+ [MarshalAs(UnmanagedType.Currency)]
+ public decimal dec;
+}
+
+public class CMain
+{
+ #region Func Sig
+
+ // Dec As Struct
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeDecByInOutRef([MarshalAs(UnmanagedType.FunctionPtr)] Dele_DecInOutRef dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeDecByOutRef([MarshalAs(UnmanagedType.FunctionPtr)] Dele_DecOutRef dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_DecRet([MarshalAs(UnmanagedType.FunctionPtr)] Dele_DecRet dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeStru_Seq_DecAsStructAsFldByInOutRef([MarshalAs(UnmanagedType.FunctionPtr)] Dele_Stru_Seq_DecAsStructAsFldInOutRef dele);
+
+ // Dec As CY
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeCYByInOutRef([MarshalAs(UnmanagedType.FunctionPtr)] Dele_CYInOutRef dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeCYByOutRef([MarshalAs(UnmanagedType.FunctionPtr)] Dele_CYOutRef dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_CYRet([MarshalAs(UnmanagedType.FunctionPtr)] Dele_CYRet dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef([MarshalAs(UnmanagedType.FunctionPtr)] Dele_Stru_Exp_DecAsCYAsFldOutRef dele);
+
+ // Dec As LPStruct
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeDecByInOutRefAsLPStruct([MarshalAs(UnmanagedType.FunctionPtr)] Dele_DecInOutRefAsLPStruct dele);
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_TakeDecByOutRefAsLPStruct([MarshalAs(UnmanagedType.FunctionPtr)] Dele_DecOutRefAsLPStruct dele);
+ //************** ReverseCall Return Int From Net **************//
+ [DllImport("RevNative")]
+ static extern bool ReverseCall_IntRet([MarshalAs(UnmanagedType.FunctionPtr)] Dele_IntRet dele);
+
+ #endregion
+
+ #region Delegate Set
+
+ // Dec As Struct
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_DecInOutRef([MarshalAs(UnmanagedType.Struct), In, Out]ref decimal dec);
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_DecOutRef([MarshalAs(UnmanagedType.Struct), Out]out decimal dec);
+ [return: MarshalAs(UnmanagedType.Struct)]
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate decimal Dele_DecRet();
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_Stru_Seq_DecAsStructAsFldInOutRef([In, Out]ref Stru_Seq_DecAsStructAsFld s);
+
+ // Dec As CY
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_CYInOutRef([MarshalAs(UnmanagedType.Currency), In, Out]ref decimal dec);
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_CYOutRef([MarshalAs(UnmanagedType.Currency), Out]out decimal dec);
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.Currency)]
+ delegate decimal Dele_CYRet();
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_Stru_Exp_DecAsCYAsFldOutRef([Out]out Stru_Exp_DecAsCYAsFld s);
+
+ // Dec As LPStruct
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_DecInOutRefAsLPStruct([MarshalAs(UnmanagedType.LPStruct), In, Out]ref decimal dec);
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate bool Dele_DecOutRefAsLPStruct([MarshalAs(UnmanagedType.LPStruct), Out]out decimal dec);
+
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ [return: MarshalAs(UnmanagedType.LPStruct)]
+ delegate decimal Dele_DecAsLPStructRet();
+
+ //************** ReverseCall Return Int From Net **************//
+ [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+ delegate int Dele_IntRet();
+
+ #endregion
+
+ #region AUX For Testing
+ const decimal CY_MAX_VALUE = 922337203685477.5807M;
+ const decimal CY_MIN_VALUE = -922337203685477.5808M;
+
+ static bool Equals<T>(T expected, T actual)
+ {
+ if (expected.Equals(actual))
+ return true;
+ else
+ return false;
+ }
+
+ #endregion
+
+ #region Method For Testing
+
+ //Dec As Struct
+ static bool TakeDecByInOutRef([MarshalAs(UnmanagedType.Struct), In, Out] ref decimal dec)
+ {
+ if (Equals(decimal.MaxValue, dec))
+ {
+ dec = decimal.MinValue;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ static bool TakeDecByOutRef([MarshalAs(UnmanagedType.Struct), Out] out decimal dec)
+ {
+ dec = decimal.Zero;
+
+ return true;
+ }
+
+ [return: MarshalAs(UnmanagedType.Struct)]
+ static decimal DecRet()
+ {
+ return decimal.MinValue;
+ }
+
+ static bool TakeStru_Seq_DecAsStructAsFldByInOutRef([In, Out] ref Stru_Seq_DecAsStructAsFld s)
+ {
+ if (Equals(decimal.MaxValue, s.dec) && Equals(1, s.number))
+ {
+ s.dec = decimal.MinValue;
+ s.number = 2;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // Dec As CY
+ static bool TakeCYByInOutRef([MarshalAs(UnmanagedType.Currency), In, Out] ref decimal cy)
+ {
+ if (Equals(CY_MAX_VALUE, cy))
+ {
+ cy = CY_MIN_VALUE;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ [return: MarshalAs(UnmanagedType.Currency)]
+ static decimal CYRet()
+ {
+ return CY_MIN_VALUE;
+ }
+
+ static bool TakeCYByOutRef([MarshalAs(UnmanagedType.Currency), Out] out decimal dec)
+ {
+ dec = decimal.Zero;
+
+ return true;
+ }
+
+ static bool ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef([Out] out Stru_Exp_DecAsCYAsFld s)
+ {
+ s.dec = CY_MAX_VALUE;
+ s.wc = 'C';
+
+ return true;
+ }
+
+ //Dec As LPStruct
+ static bool TakeDecByInOutRefAsLPStruct([MarshalAs(UnmanagedType.LPStruct), In, Out] ref decimal dec)
+ {
+ if (Equals(decimal.MaxValue, dec))
+ {
+ dec = decimal.MinValue;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ static bool TakeDecByOutRefAsLPStruct([MarshalAs(UnmanagedType.LPStruct), Out] out decimal dec)
+ {
+ dec = decimal.Zero;
+
+ return true;
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStruct)]
+ static decimal DecAsLPStructRet()
+ {
+ return decimal.MinValue;
+ }
+
+ //************** ReverseCall Return Int From Net **************//
+ [return: MarshalAs(UnmanagedType.I4)]
+ static int IntRet()
+ {
+ return 0x12345678;
+ }
+
+ #endregion
+
+ static bool AsStruct()
+ {
+ Console.WriteLine("AsStruct started.");
+ // Dec As Struct
+ if (!ReverseCall_TakeDecByInOutRef(new Dele_DecInOutRef(TakeDecByInOutRef)))
+ {
+ Console.WriteLine("Test Failed: Decimal <-> DECIMAL, Marshal As Struct/Param, Passed By In / Out / Ref .");
+ return false;
+ }
+ if (!ReverseCall_TakeDecByOutRef(new Dele_DecOutRef(TakeDecByOutRef)))
+ {
+ Console.WriteLine("Test Failed: Decimal <-> DECIMAL, Marshal As Struct/Param, Passed By Out / Ref .");
+ return false;
+ }
+ if (!ReverseCall_DecRet(new Dele_DecRet(DecRet)))
+ {
+ Console.WriteLine("Test Failed: Decimal <-> DECIMAL, Marshal As Struct/RetVal .");
+ return false;
+ }
+ if (!ReverseCall_TakeStru_Seq_DecAsStructAsFldByInOutRef(new Dele_Stru_Seq_DecAsStructAsFldInOutRef(TakeStru_Seq_DecAsStructAsFldByInOutRef)))
+ {
+ Console.WriteLine("Test Failed: Decimal <-> DECIMAL, Marshal As Struct/Field, Passed By In / Out / Ref .");
+ return false;
+ }
+
+ Console.WriteLine("AsStruct end.");
+ return true;
+ }
+
+ static bool AsCY()
+ {
+ Console.WriteLine("AsCY started.");
+ // Dec As CY
+ if (!(ReverseCall_TakeCYByInOutRef(new Dele_CYInOutRef(TakeCYByInOutRef))))
+ {
+ Console.WriteLine("Test Failed: (ReverseCall_TakeCYByInOutRef(new Dele_CYInOutRef(TakeCYByInOutRef)))");
+ return false;
+ }
+ if (!(ReverseCall_TakeCYByOutRef(new Dele_CYOutRef(TakeCYByOutRef))))
+ {
+ Console.WriteLine("Test Failed: (ReverseCall_TakeCYByOutRef(new Dele_CYOutRef(TakeCYByOutRef)))");
+ return false;
+ }
+
+ bool exceptionThrown = false;
+
+ try
+ {
+ ReverseCall_CYRet(new Dele_CYRet(CYRet));
+ }
+ catch (MarshalDirectiveException)
+ {
+ exceptionThrown = true;
+ }
+ if (!exceptionThrown)
+ {
+ Console.WriteLine("Expected MarshalDirectiveException from TakeDecAsInOutParamAsLPStructByRef(ref dec) not thrown");
+ return false;
+ }
+
+ if (!(ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef(new Dele_Stru_Exp_DecAsCYAsFldOutRef(ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef))))
+ {
+ Console.WriteLine("Test Failed: (ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef(new Dele_Stru_Exp_DecAsCYAsFldOutRef(ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef)))");
+ return false;
+ }
+
+ Console.WriteLine("AsCY end.");
+ return true;
+ }
+
+ static bool AsLPStruct()
+ {
+ Console.WriteLine("AsLPStruct started.");
+
+ if (!ReverseCall_TakeDecByInOutRefAsLPStruct(new Dele_DecInOutRefAsLPStruct(TakeDecByInOutRefAsLPStruct)))
+ {
+ Console.WriteLine("Test Failed: Decimal <-> DECIMAL, Marshal As LPStruct/Param, Passed By In / Out / Ref");
+ return false;
+ }
+ if (!ReverseCall_TakeDecByOutRefAsLPStruct(new Dele_DecOutRefAsLPStruct(TakeDecByOutRefAsLPStruct)))
+ {
+ Console.WriteLine("Test Failed: Decimal <-> DECIMAL, Marshal As LPStruct/Param, Passed By Out / Ref");
+ return false;
+ }
+
+
+ Console.WriteLine("AsLPStruct end.");
+ return true;
+ }
+
+ static bool AsInt()
+ {
+ if (!ReverseCall_IntRet(new Dele_IntRet(IntRet)))
+ {
+ Console.WriteLine("Test Failed: RET INT");
+ return false;
+ }
+
+ return true;
+ }
+
+ static int Main()
+ {
+ bool success = true;
+ success = success && AsStruct();
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ success = success && AsCY();
+ }
+ success = success && AsLPStruct();
+ success = success && AsInt();
+
+ return success ? 100 : 101;
+ }
+}
+#pragma warning restore 618
--- /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>DecimalTest</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="DecimalTest.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ </ItemGroup>
+ <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.
+
+#include <iostream>
+#include <xplatform.h>
+#include "platformdefines.h"
+
+DECIMAL g_DECIMAL_MaxValue = { 0, {{ 0, 0 }}, 0xffffffff, {{0xffffffff, 0xffffffff}} };
+DECIMAL g_DECIMAL_MinValue = { 0, {{ 0, DECIMAL_NEG }}, 0xffffffff, {{0xffffffff, 0xffffffff }}};
+DECIMAL g_DECIMAL_Zero = { 0 };
+
+CY g_CY_MaxValue = { {0xffffffff, 0x7fffffff} };
+CY g_CY_MinValue = { {(LONG)0x00000000, (LONG)0x80000000} };
+CY g_CY_Zero = { {0} };
+
+typedef struct _Stru_Seq_DecAsStructAsFld
+{
+ int number;
+ DECIMAL dec;
+} Stru_Seq_DecAsStructAsFld;
+
+typedef struct _Stru_Exp_DecAsCYAsFld
+{
+ WCHAR wc;
+ CY cy;
+} Stru_Exp_DecAsCYAsFld;
+
+typedef struct _Stru_Seq_DecAsLPStructAsFld
+{
+ DOUBLE dblVal;
+ CHAR cVal;
+ DECIMAL* dec;
+} Stru_Seq_DecAsLPStructAsFld;
+
+// As Struct
+typedef BOOL (STDMETHODCALLTYPE *Fp_Dec)(DECIMAL*);
+typedef DECIMAL (STDMETHODCALLTYPE *Fp_RetDec)();
+typedef BOOL (STDMETHODCALLTYPE *Fp_Stru_Seq_DecAsStructAsFld)(Stru_Seq_DecAsStructAsFld*);
+// As CY
+typedef BOOL (STDMETHODCALLTYPE *Fp_CY)(CY*);
+typedef CY (STDMETHODCALLTYPE *Fp_RetCY)();
+typedef BOOL (STDMETHODCALLTYPE *Fp_Stru_Exp_DecAsCYAsFld)(Stru_Exp_DecAsCYAsFld*);
+// As LPStruct
+typedef BOOL (STDMETHODCALLTYPE *Fp_DecAsLPStruct)(DECIMAL**);
+typedef DECIMAL* (STDMETHODCALLTYPE *Fp_RetDecAsLPStruct)();
+typedef BOOL (STDMETHODCALLTYPE *Fp_Stru_Seq_DecAsLPStructAsFld)(Stru_Seq_DecAsLPStructAsFld*);
+
+void DecDisplay(const DECIMAL& dec)
+{
+ std::cout << "\twReserved" << "\t\t" << dec.wReserved << "\n"
+ << "\tscale" << "\t\t" << dec.scale << "\n"
+ << "\tsign" << "\t\t" << dec.sign << "\n"
+ << "\tsignscale" << "\t\t" << dec.signscale << "\n"
+ << "\tHi32" << "\t\t" << dec.Hi32 << "\n"
+ << "\tLo32" << "\t\t" << dec.Lo32 << "\n"
+ << "\tMid32" << "\t\t" << dec.Mid32 << "\n"
+ << "\tLo64" << "\t\t" << dec.Lo64 << std::endl;
+}
+
+template<typename T>
+bool operator==(const T& t1, const T& t2)
+{
+ return 0 == memcmp((void*)&t1, (void*)&t2, sizeof(T));
+}
+
+template<typename T>
+bool Equals(LPCSTR err_id, T expected, T actual)
+{
+ if(expected == actual)
+ return true;
+ else
+ {
+ std::cout << "\t#Native Side Err# -- " << err_id
+ << "\n\tExpected = " << expected << std::endl;
+ std::wcout << "\tActual is = " << actual << std::endl;
+
+ return false;
+ }
+}
+
+bool IntEqualsToExpected(LPCSTR err_id, int number, int expected)
+{
+
+ if(number == expected)
+ {
+ return true;
+ }
+ else
+ {
+ std::wcout << "\t#Native Side Err# -- " << err_id
+ << "\n\tnumber Expected = " << expected << std::endl;
+
+ std::wcout << "\tnumber Actual is = " << number << std::endl;
+
+ return false;
+ }
+}
+bool DecEqualsToExpected(LPCSTR err_id, const DECIMAL& expected, const DECIMAL& actual)
+{
+ if(expected == actual)
+ return true;
+ else
+ {
+ std::cout << "\t#Native Side Err # -- " << err_id
+ << "DECIMAL Expected is :" << std::endl;
+ DecDisplay(expected);
+
+ std::cout << "\t" << "____________________________________" << std::endl;
+
+ std::cout << "\tDECIMAL Actual is :" << std::endl;
+ DecDisplay(actual);
+
+ return false;
+ }
+}
+
+bool CYEqualsToExpected(LPCSTR err_id, const CY& expected, const CY& actual)
+{
+ if(expected == actual)
+ return true;
+ else
+ {
+ std::cout << "\t#Native Side Err# -- " << err_id
+ << "\n\tCY Expected is :" << "Hi = " << expected.Hi
+ << "Lo = " << expected.Lo << std::endl;
+
+ std::cout << "\tCY Actual is :" << "Hi = " << actual.Hi
+ << "Lo = " << actual.Lo << std::endl;
+
+ return false;
+ }
+}
+
+template<typename T>
+T* RetSpecificTypeInstancePtr(T tVal)
+{
+ T* lpT = (T*)CoreClrAlloc(sizeof(T));
+ *lpT = tVal;
+ return lpT;
+}
+
+// As Struct
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeDecByInOutRef(Fp_Dec fp)
+{
+ DECIMAL* lpDec = RetSpecificTypeInstancePtr(g_DECIMAL_MaxValue);
+
+ if((*fp)(lpDec))
+ return DecEqualsToExpected("001.01", g_DECIMAL_MinValue, *lpDec);
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeDecByOutRef(Fp_Dec fp)
+{
+ DECIMAL* lpDec = RetSpecificTypeInstancePtr(g_DECIMAL_MaxValue);
+
+ if((*fp)(lpDec))
+ return DecEqualsToExpected("001.02", g_DECIMAL_Zero, *lpDec);
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_DecRet(Fp_RetDec fp)
+{
+ return DecEqualsToExpected("001.03", g_DECIMAL_MinValue, (*fp)());
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeStru_Seq_DecAsStructAsFldByInOutRef(Fp_Stru_Seq_DecAsStructAsFld fp)
+{
+ Stru_Seq_DecAsStructAsFld s = { 1, g_DECIMAL_MaxValue };
+
+ if((*fp)(&s))
+ return DecEqualsToExpected("001.04", g_DECIMAL_MinValue, s.dec) && IntEqualsToExpected("001.05", s.number, 2);
+ else
+ return false;
+}
+
+// As CY
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeCYByInOutRef(Fp_CY fp)
+{
+ CY* lpCy = RetSpecificTypeInstancePtr(g_CY_MaxValue);
+
+ if((*fp)(lpCy))
+ return CYEqualsToExpected("002.01", g_CY_MinValue, *lpCy);
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeCYByOutRef(Fp_CY fp)
+{
+ CY* lpCy = RetSpecificTypeInstancePtr(g_CY_MaxValue);
+
+ if((*fp)(lpCy))
+ return CYEqualsToExpected("002.02", g_CY_Zero, *lpCy);
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_CYRet(Fp_RetCY fp)
+{
+ return CYEqualsToExpected("002.03", g_CY_MinValue, (*fp)());
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeStru_Exp_DecAsCYAsFldByOutRef(Fp_Stru_Exp_DecAsCYAsFld fp)
+{
+ Stru_Exp_DecAsCYAsFld s = { 0 };
+
+ if((*fp)(&s))
+ return CYEqualsToExpected("002.04", g_CY_MaxValue, s.cy) && Equals("002.05", W('C'), s.wc);
+ else
+ return false;
+}
+
+// As LPStrcut
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeDecByInOutRefAsLPStruct(Fp_DecAsLPStruct fp)
+{
+ DECIMAL* lpDec = RetSpecificTypeInstancePtr(g_DECIMAL_MaxValue);
+ DECIMAL** lppDec = &lpDec;
+
+ if((*fp)(lppDec))
+ return DecEqualsToExpected("003.01", g_DECIMAL_MinValue, **lppDec);
+ else
+ return false;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_TakeDecByOutRefAsLPStruct(Fp_DecAsLPStruct fp)
+{
+ DECIMAL* lpDecAsLPStruct = RetSpecificTypeInstancePtr(g_DECIMAL_MaxValue);
+ DECIMAL** lppDecAsLPStruct = &lpDecAsLPStruct;
+
+ if((*fp)(lppDecAsLPStruct))
+ return DecEqualsToExpected("003.02", g_DECIMAL_Zero, **lppDecAsLPStruct);
+ else
+ return false;
+}
+
+//************** ReverseCall Return Int From Net **************//
+typedef int (*Fp_RetInt)();
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE ReverseCall_IntRet(Fp_RetInt fp)
+{
+ return 0x12345678 == (*fp)();
+}
typedef size_t UINT_PTR;
typedef unsigned long long ULONG64;
+typedef unsigned long long LONG64;
typedef double DOUBLE;
typedef float FLOAT;
-typedef signed long long LONG64, *PLONG64;
typedef int INT, *LPINT;
typedef unsigned int UINT;
+typedef int LONG;
typedef char CHAR, *PCHAR;
typedef unsigned short USHORT;
typedef signed short SHORT;
typedef size_t SIZE_T;
+typedef union tagCY {
+ struct {
+#if BIGENDIAN
+ LONG Hi;
+ LONG Lo;
+#else
+ LONG Lo;
+ LONG Hi;
+#endif
+ };
+ LONG64 int64;
+} CY, *LPCY;
+
+typedef CY CURRENCY;
+
+typedef struct tagDEC {
+ // Decimal.cs treats the first two shorts as one long
+ // And they seriable the data so we need to little endian
+ // seriliazation
+ // The wReserved overlaps with Variant's vt member
+#if BIGENDIAN
+ union {
+ struct {
+ BYTE sign;
+ BYTE scale;
+ };
+ USHORT signscale;
+ };
+ USHORT wReserved;
+#else
+ USHORT wReserved;
+ union {
+ struct {
+ BYTE scale;
+ BYTE sign;
+ };
+ USHORT signscale;
+ };
+#endif
+ LONG Hi32;
+ union {
+ struct {
+ LONG Lo32;
+ LONG Mid32;
+ };
+ ULONG64 Lo64;
+ };
+} DECIMAL, *LPDECIMAL;
+
+
#ifndef TRUE
#define TRUE 1
#endif
return wcsncmp(str1, str2, len);
}
+#define DECIMAL_NEG ((BYTE)0x80)
+#define DECIMAL_SCALE(dec) ((dec).u.u.scale)
+#define DECIMAL_SIGN(dec) ((dec).u.u.sign)
+#define DECIMAL_SIGNSCALE(dec) ((dec).u.signscale)
+#define DECIMAL_LO32(dec) ((dec).v.v.Lo32)
+#define DECIMAL_MID32(dec) ((dec).v.v.Mid32)
+#define DECIMAL_HI32(dec) ((dec).Hi32)
+#define DECIMAL_LO64_GET(dec) ((dec).v.Lo64)
+#define DECIMAL_LO64_SET(dec,value) {(dec).v.Lo64 = value; }
+
+#define DECIMAL_SETZERO(dec) {DECIMAL_LO32(dec) = 0; DECIMAL_MID32(dec) = 0; DECIMAL_HI32(dec) = 0; DECIMAL_SIGNSCALE(dec) = 0;}
+
#endif //!_Win32
#endif // __XPLAT_H__