From 9b3ace68d678b52ccff163fdcf1332be20ecd17f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 9 Jan 2019 15:03:43 -0800 Subject: [PATCH] Add tests for our layout-class marshalling (#20867) * Add simple test for the LayoutClassMarshaler (most of the code is already covered by the struct marshalling tests). * Add test for blittable layout class. * Apparently layout classes are passed by value when passed as struct fields instead of byref. --- tests/src/Interop/CMakeLists.txt | 1 + tests/src/Interop/LayoutClass/CMakeLists.txt | 11 + .../src/Interop/LayoutClass/LayoutClassNative.cpp | 74 +++++++ tests/src/Interop/LayoutClass/LayoutClassTest.cs | 227 +++++++++++++++++++++ .../src/Interop/LayoutClass/LayoutClassTest.csproj | 38 ++++ 5 files changed, 351 insertions(+) create mode 100644 tests/src/Interop/LayoutClass/CMakeLists.txt create mode 100644 tests/src/Interop/LayoutClass/LayoutClassNative.cpp create mode 100644 tests/src/Interop/LayoutClass/LayoutClassTest.cs create mode 100644 tests/src/Interop/LayoutClass/LayoutClassTest.csproj diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 9e0bf85..9784ea1 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -61,6 +61,7 @@ add_subdirectory(DllImportAttribute/ExeFile) add_subdirectory(DllImportAttribute/FileNameContainDot) add_subdirectory(DllImportAttribute/Simple) add_subdirectory(ExecInDefAppDom) +add_subdirectory(LayoutClass) if(WIN32) add_subdirectory(PInvoke/Attributes/LCID) diff --git a/tests/src/Interop/LayoutClass/CMakeLists.txt b/tests/src/Interop/LayoutClass/CMakeLists.txt new file mode 100644 index 0000000..5626d66 --- /dev/null +++ b/tests/src/Interop/LayoutClass/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required (VERSION 2.6) +project (LayoutClassNative) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES LayoutClassNative.cpp ) + +# add the executable +add_library (LayoutClassNative SHARED ${SOURCES}) +target_link_libraries(LayoutClassNative ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS LayoutClassNative DESTINATION bin) diff --git a/tests/src/Interop/LayoutClass/LayoutClassNative.cpp b/tests/src/Interop/LayoutClass/LayoutClassNative.cpp new file mode 100644 index 0000000..3185040 --- /dev/null +++ b/tests/src/Interop/LayoutClass/LayoutClassNative.cpp @@ -0,0 +1,74 @@ +#include "platformdefines.h" + +#include +#include +#include + +typedef void *voidPtr; + +struct SeqClass +{ + int a; + bool b; + char* str; +}; + +struct ExpClass +{ + int a; + int extra; //padding needs to be added here as we have added 8 byte offset. + union + { + int i; + BOOL b; + double d; + } udata; +}; + +struct BlittableClass +{ + int a; +}; + +struct NestedLayoutClass +{ + SeqClass str; +}; + +extern "C" +DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleSeqLayoutClassByRef(SeqClass *p) +{ + if((p->a != 0) || (p->b) || strcmp(p->str, "before") != 0) + { + printf("\np->a=%d, p->b=%s, p->str=%s", p->a, p->b ? "true" : "false", p->str); + return FALSE; + } + return TRUE; +} + +extern "C" +DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleBlittableSeqLayoutClassByRef(BlittableClass *p) +{ + if(p->a != 10) + { + printf("\np->a=%d", p->a); + return FALSE; + } + return TRUE; +} + +extern "C" +DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleExpLayoutClassByRef(ExpClass *p) +{ + if((p->a != 0) || (p->udata.i != 10)) + { + printf("\np->a=%d, p->udata.i=%d\n",p->a,p->udata.i); + return FALSE; + } + return TRUE; +} + +extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleNestedLayoutClassByValue(NestedLayoutClass v) +{ + return SimpleSeqLayoutClassByRef(&v.str); +} diff --git a/tests/src/Interop/LayoutClass/LayoutClassTest.cs b/tests/src/Interop/LayoutClass/LayoutClassTest.cs new file mode 100644 index 0000000..49984d5 --- /dev/null +++ b/tests/src/Interop/LayoutClass/LayoutClassTest.cs @@ -0,0 +1,227 @@ +using System; +using System.Security; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using TestLibrary; + +namespace PInvokeTests +{ + [StructLayout(LayoutKind.Sequential)] + public class SeqClass + { + public int a; + public bool b; + public string str; + + public SeqClass(int _a, bool _b, string _str) + { + a = _a; + b = _b; + str = String.Concat(_str, ""); + } + } + + [StructLayout(LayoutKind.Explicit)] + public class ExpClass + { + [FieldOffset(0)] + public DialogResult type; + + [FieldOffset(8)] + public int i; + + [FieldOffset(8)] + public bool b; + + [FieldOffset(8)] + public double c; + + public ExpClass(DialogResult t, int num) + { + type = t; + b = false; + c = num; + i = num; + } + public ExpClass(DialogResult t, double dnum) + { + type = t; + b = false; + i = 0; + c = dnum; + } + public ExpClass(DialogResult t, bool bnum) + { + type = t; + i = 0; + c = 0; + b = bnum; + } + } + + public enum DialogResult + { + None = 0, + OK = 1, + Cancel = 2 + } + + + [StructLayout(LayoutKind.Sequential)] + public class Blittable + { + public int a; + + public Blittable(int _a) + { + a = _a; + } + } + + public struct NestedLayout + { + public SeqClass value; + } + + class StructureTests + { + [DllImport("LayoutClassNative")] + private static extern bool SimpleSeqLayoutClassByRef(SeqClass p); + + [DllImport("LayoutClassNative")] + private static extern bool SimpleExpLayoutClassByRef(ExpClass p); + + [DllImport("LayoutClassNative")] + private static extern bool SimpleNestedLayoutClassByValue(NestedLayout p); + + [DllImport("LayoutClassNative")] + private static extern bool SimpleBlittableSeqLayoutClassByRef(Blittable p); + + public static bool SequentialClass() + { + string s = "before"; + bool retval = true; + SeqClass p = new SeqClass(0, false, s); + + TestFramework.BeginScenario("Test #1 Pass a sequential layout class."); + + try + { + retval = SimpleSeqLayoutClassByRef(p); + + if (retval == false) + { + TestFramework.LogError("01", "PInvokeTests->SequentialClass : Unexpected error occured on unmanaged side"); + return false; + } + } + catch (Exception e) + { + TestFramework.LogError("04", "Unexpected exception: " + e.ToString()); + retval = false; + } + + return retval; + } + + public static bool ExplicitClass() + { + ExpClass p; + bool retval = false; + + TestFramework.BeginScenario("Test #2 Pass an explicit layout class."); + + try + { + p = new ExpClass(DialogResult.None, 10); + retval = SimpleExpLayoutClassByRef(p); + + if (retval == false) + { + TestFramework.LogError("01", "PInvokeTests->ExplicitClass : Unexpected error occured on unmanaged side"); + return false; + } + + } + catch (Exception e) + { + TestFramework.LogError("03", "Unexpected exception: " + e.ToString()); + retval = false; + } + + return retval; + } + + public static bool BlittableClass() + { + bool retval = true; + Blittable p = new Blittable(10); + + TestFramework.BeginScenario("Test #3 Pass a blittable sequential layout class."); + + try + { + retval = SimpleBlittableSeqLayoutClassByRef(p); + + if (retval == false) + { + TestFramework.LogError("01", "PInvokeTests->Blittable : Unexpected error occured on unmanaged side"); + return false; + } + } + catch (Exception e) + { + TestFramework.LogError("04", "Unexpected exception: " + e.ToString()); + retval = false; + } + + return retval; + } + + public static bool NestedLayoutClass() + { + string s = "before"; + bool retval = true; + SeqClass p = new SeqClass(0, false, s); + NestedLayout target = new NestedLayout + { + value = p + }; + + TestFramework.BeginScenario("Test #4 Nested sequential layout class in a structure."); + + try + { + retval = SimpleNestedLayoutClassByValue(target); + + if (retval == false) + { + TestFramework.LogError("01", "PInvokeTests->NestedLayoutClass : Unexpected error occured on unmanaged side"); + return false; + } + } + catch (Exception e) + { + TestFramework.LogError("04", "Unexpected exception: " + e.ToString()); + retval = false; + } + + return retval; + } + + public static int Main(string[] argv) + { + bool retVal = true; + + retVal = retVal && SequentialClass(); + retVal = retVal && ExplicitClass(); + retVal = retVal && BlittableClass(); + retVal = retVal && NestedLayoutClass(); + + return (retVal ? 100 : 101); + } + + + } +} diff --git a/tests/src/Interop/LayoutClass/LayoutClassTest.csproj b/tests/src/Interop/LayoutClass/LayoutClassTest.csproj new file mode 100644 index 0000000..caf67cf --- /dev/null +++ b/tests/src/Interop/LayoutClass/LayoutClassTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + LayoutClassTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + {c8c0dc74-fac4-45b1-81fe-70c4808366e0} + CoreCLRTestLibrary + + + + + -- 2.7.4