From cd0a465caf1b0063e73dfe0b0cd8b193266f11e7 Mon Sep 17 00:00:00 2001 From: Zeng Jiang Date: Fri, 16 Nov 2018 02:10:25 +0800 Subject: [PATCH] Add PInvoke/Miscellaneous tests (#19326) * Add PInvoke/Miscellaneous tests * Clean up HandleRef test. --- tests/src/Interop/CMakeLists.txt | 2 + .../PInvoke/Miscellaneous/HandleRef/CMakeLists.txt | 14 +++ .../Miscellaneous/HandleRef/HandleRefNative.cpp | 85 +++++++++++++++++ .../Miscellaneous/HandleRef/HandleRefTest.cs | 106 +++++++++++++++++++++ .../Miscellaneous/HandleRef/HandleRefTest.csproj | 35 +++++++ .../CMakeLists.txt | 14 +++ .../MAWSPINative.cpp | 10 ++ .../MAWSPITest.cs | 27 ++++++ .../MAWSPITest.csproj | 36 +++++++ .../ManagedDll1/ManagedDll1.cs | 20 ++++ .../ManagedDll1/ManagedDll1.csproj | 33 +++++++ .../ManagedDll2/ManagedDll2.cs | 20 ++++ .../ManagedDll2/ManagedDll2.csproj | 33 +++++++ 13 files changed, 435 insertions(+) create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/HandleRef/CMakeLists.txt create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.csproj create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/CMakeLists.txt create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPINative.cpp create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.cs create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.csproj create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.cs create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.csproj create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.cs create mode 100644 tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.csproj diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index fdddcde..de43fca 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -17,6 +17,8 @@ add_subdirectory(PInvoke/BestFitMapping/LPStr) add_subdirectory(PInvoke/Delegate/MarshalDelegateAsField) add_subdirectory(PInvoke/Delegate/MarshalDelegateAsParam) add_subdirectory(PInvoke/Primitives/Int) +add_subdirectory(PInvoke/Miscellaneous/HandleRef) +add_subdirectory(PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke) add_subdirectory(PInvoke/ExactSpelling) add_subdirectory(PInvoke/AsAny) add_subdirectory(NativeCallable) diff --git a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/CMakeLists.txt b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/CMakeLists.txt new file mode 100644 index 0000000..c5f031a --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/CMakeLists.txt @@ -0,0 +1,14 @@ +#VCXPROJ +cmake_minimum_required (VERSION 2.6) +project (HandleRefNative) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + HandleRefNative.cpp +) +# Additional files to reference: +# HandleRefNative.def +# add the executable +add_library (HandleRefNative SHARED ${SOURCES}) +# add the install targets +install (TARGETS HandleRefNative DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp new file mode 100644 index 0000000..bc5d61e --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include + +const int intManaged = 1000; +const int intNative = 2000; +const int intReturn = 3000; +const int intErrReturn = 4000; +const int expectedStackGuard = 5000; + +extern "C" DLL_EXPORT int STDMETHODCALLTYPE MarshalPointer_In(/*[in]*/int *pintValue, int stackGuard) +{ + if (*pintValue != intManaged) + { + printf("Error in Function MarshalPointer_In(Native Client)\n"); + printf("Expected:%u\n", intManaged); + printf("Actual:%u\n",*pintValue); + + // Return the error value instead if verification failed + return intErrReturn; + } + if (stackGuard != expectedStackGuard) + { + printf("Stack error in Function MarshalPointer_In(Native Client)\n"); + return intErrReturn; + } + + return intReturn; +} + +extern "C" DLL_EXPORT int STDMETHODCALLTYPE MarshalPointer_InOut(/*[in,out]*/int *pintValue, int stackGuard) +{ + if(*pintValue != intManaged) + { + printf("Error in Function MarshalPointer_InOut(Native Client)\n"); + printf("Expected:%u\n", intManaged); + printf("Actual:%u\n",*pintValue); + + // Return the error value instead if verification failed + return intErrReturn; + } + if (stackGuard != expectedStackGuard) + { + printf("Stack error in Function MarshalPointer_In(Native Client)\n"); + return intErrReturn; + } + + // In-Place Change + *pintValue = intNative; + + return intReturn; +} + +extern "C" DLL_EXPORT int STDMETHODCALLTYPE MarshalPointer_Out(/*[out]*/ int *pintValue, int stackGuard) +{ + *pintValue = intNative; + if (stackGuard != expectedStackGuard) + { + printf("Stack error in Function MarshalPointer_In(Native Client)\n"); + return intErrReturn; + } + + return intReturn; +} + +typedef void (*GCCallback)(void); +extern "C" DLL_EXPORT int STDMETHODCALLTYPE TestNoGC(int *pintValue, GCCallback gcCallback) +{ + int origValue = *pintValue; + gcCallback(); + int afterGCValue = *pintValue; + if (origValue != afterGCValue) + { + printf("Error in Function TestNoGC(Native Client)\n"); + printf("Expected:%u\n", origValue); + printf("Actual:%u\n", afterGCValue); + return intErrReturn; + } + + return intReturn; +} + diff --git a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs new file mode 100644 index 0000000..6f6ed52 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System; +using System.Reflection; +using System.Text; +using TestLibrary; + +class BoxedInt +{ + public int MyInt; +} + +class HandleRefTest +{ + [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)] + private static extern int MarshalPointer_In(HandleRef pintValue, int stackGuard); + + [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)] + private static extern int MarshalPointer_InOut(HandleRef pintValue, int stackGuard); + + [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)] + private static extern int MarshalPointer_Out(HandleRef pintValue, int stackGuard); + + [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)] + private static extern int TestNoGC(HandleRef pintValue, Action gcCallback); + + public unsafe static int Main(string[] args) + { + try{ + const int intManaged = 1000; + const int intNative = 2000; + const int intReturn = 3000; + const int stackGuard = 5000; + + Console.WriteLine("MarshalPointer_In"); + int int1 = intManaged; + int* int1Ptr = &int1; + HandleRef hr1 = new HandleRef(new Object(), (IntPtr)int1Ptr); + Assert.AreEqual(intReturn, MarshalPointer_In(hr1, stackGuard), "The return value is wrong"); + Assert.AreEqual(intManaged, int1, "The parameter value is changed"); + + Console.WriteLine("MarshalPointer_InOut"); + int int2 = intManaged; + int* int2Ptr = &int2; + HandleRef hr2 = new HandleRef(new Object(), (IntPtr)int2Ptr); + Assert.AreEqual(intReturn, MarshalPointer_InOut(hr2, stackGuard), "The return value is wrong"); + Assert.AreEqual(intNative, int2, "The passed value is wrong"); + + Console.WriteLine("MarshalPointer_Out"); + int int3 = intManaged; + int* int3Ptr = &int3; + HandleRef hr3 = new HandleRef(new Object(), (IntPtr)int3Ptr); + Assert.AreEqual(intReturn, MarshalPointer_Out(hr3, stackGuard), "The return value is wrong"); + Assert.AreEqual(intNative, int3, "The passed value is wrong"); + + // Note that this scenario will always pass in a debug build because all values + // stay rooted until the end of the method. + Console.WriteLine("TestNoGC"); + + // Keep the int boxed and pinned to prevent it from getting collected. + // That way, we can safely reference it from finalizers that run on shutdown. + BoxedInt boxedInt = new BoxedInt(); + GCHandle.Alloc(boxedInt, GCHandleType.Normal); + int* int4Ptr; + fixed (int* tempIntPtr = &boxedInt.MyInt) + { + // Smuggle the pointer out of the fixed scope + int4Ptr = tempIntPtr; + } + Console.WriteLine("2"); + *int4Ptr = intManaged; + CollectableClass collectableClass = new CollectableClass(int4Ptr); + HandleRef hr4 = new HandleRef(collectableClass, (IntPtr)int4Ptr); + Action gcCallback = () => { Console.WriteLine("GC callback now"); GC.Collect(2, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); GC.Collect(2, GCCollectionMode.Forced); }; + Assert.AreEqual(intReturn, TestNoGC(hr4, gcCallback), "The return value is wrong"); + Console.WriteLine("Native code finished"); + + return 100; + } catch (Exception e){ + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } + + /// + /// Class that will change a pointer passed to native code when this class gets finalized. + /// Native code can check whether the pointer changed during a P/Invoke + /// + unsafe class CollectableClass + { + int* PtrToChange; + public CollectableClass(int* ptrToChange) + { + PtrToChange = ptrToChange; + } + + ~CollectableClass() + { + Console.WriteLine("CollectableClass collected"); + *PtrToChange = Int32.MaxValue; + } + } +} diff --git a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.csproj b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.csproj new file mode 100644 index 0000000..2094f59 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.csproj @@ -0,0 +1,35 @@ + + + + + Debug + AnyCPU + HandleRefTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + true + + + + + + + False + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/CMakeLists.txt b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/CMakeLists.txt new file mode 100644 index 0000000..b7a9790 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/CMakeLists.txt @@ -0,0 +1,14 @@ +#VCXPROJ +cmake_minimum_required (VERSION 2.6) +project (MAWSPINative) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + MAWSPINative.cpp +) +# Additional files to reference: +# MAWSPINative.def +# add the executable +add_library (MAWSPINative SHARED ${SOURCES}) +# add the install targets +install (TARGETS MAWSPINative DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPINative.cpp b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPINative.cpp new file mode 100644 index 0000000..721a486 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPINative.cpp @@ -0,0 +1,10 @@ +// 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 + +extern "C" DLL_EXPORT int STDMETHODCALLTYPE GetInt() +{ + return 24; +} diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.cs b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.cs new file mode 100644 index 0000000..38beec9 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using TestLibrary; + +class MultipleAssembliesWithSamePInvokeTest +{ + [DllImport(@"MAWSPINative", CallingConvention = CallingConvention.StdCall)] + private static extern int GetInt(); + + public static int Main(string[] args) + { + try{ + Assert.AreEqual(24, GetInt(), "MultipleAssembliesWithSamePInvoke.GetInt() failed."); + Assert.AreEqual(24, ManagedDll1.Class1.GetInt(), "ManagedDll.Class1.GetInt() failed."); + Assert.AreEqual(24, ManagedDll2.Class2.GetInt(), "ManagedDll.Class2.GetInt() failed."); + + return 100; + } catch (Exception e){ + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.csproj b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.csproj new file mode 100644 index 0000000..4884d9c --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/MAWSPITest.csproj @@ -0,0 +1,36 @@ + + + + + Debug + AnyCPU + MAWSPITest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.cs b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.cs new file mode 100644 index 0000000..5bd3b6e --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.cs @@ -0,0 +1,20 @@ +// 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; + +namespace ManagedDll1 +{ + public class Class1 + { + [DllImport(@"MAWSPINative", EntryPoint="GetInt", CallingConvention = CallingConvention.StdCall)] + private static extern int GetIntNative(); + + public static int GetInt() + { + return GetIntNative(); + } + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.csproj b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.csproj new file mode 100644 index 0000000..34a8116 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll1/ManagedDll1.csproj @@ -0,0 +1,33 @@ + + + + + Debug + AnyCPU + ManagedDll1 + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Library + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.cs b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.cs new file mode 100644 index 0000000..6684f18 --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.cs @@ -0,0 +1,20 @@ +// 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; + +namespace ManagedDll2 +{ + public class Class2 + { + [DllImport(@"MAWSPINative", EntryPoint="GetInt", CallingConvention = CallingConvention.StdCall)] + private static extern int GetIntNative(); + + public static int GetInt() + { + return GetIntNative(); + } + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.csproj b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.csproj new file mode 100644 index 0000000..825e62e --- /dev/null +++ b/tests/src/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/ManagedDll2/ManagedDll2.csproj @@ -0,0 +1,33 @@ + + + + + Debug + AnyCPU + ManagedDll2 + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Library + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + \ No newline at end of file -- 2.7.4