From 9d2f9c4b4eebcac13247fa414bc8ca1c3a1d5b03 Mon Sep 17 00:00:00 2001 From: Zeng Jiang Date: Fri, 16 Nov 2018 06:51:02 +0800 Subject: [PATCH] Add PInvoke/DllImportpath tests (#19270) * Add PInvoke/DllImportpath tests * Refactor test to current toolset and remove Windows-only Path API searching. * Remove explicit calling convention from managed and add correct convention to test. * Get environment test passing on Unix. * Update test to pass off-Windows. * Include feature/platform defines in tests. * Fix environment test (again). * Remove zero-width character that's breaking CI * Fix zero-width character I missed. * Remove invalid parens around LD_LIBRARY_PATH * Ensure the path added to the LD_LIBRARY_PATH exists before the test starts. * Combine all DllImportPath CMakeLists.txt files into one file. * Include clr.coreclr.props when also including clr.defines.targets so we get the feature defines correctly as well. * Disable unicode test for our OSX 10.12 CI builds. --- tests/src/Interop/CMakeLists.txt | 1 + .../Interop/PInvoke/DllImportPath/CMakeLists.txt | 25 ++ .../PInvoke/DllImportPath/DllImportPathNative.cpp | 46 ++++ .../PInvoke/DllImportPath/DllImportPathTest.cs | 272 +++++++++++++++++++++ .../PInvoke/DllImportPath/DllImportPathTest.csproj | 41 ++++ tests/src/dir.targets | 3 + 6 files changed, 388 insertions(+) create mode 100644 tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt create mode 100644 tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp create mode 100644 tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs create mode 100644 tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index cab63b7..9825873 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -12,6 +12,7 @@ list(APPEND LINK_LIBRARIES_ADDITIONAL platformdefines) SET(CLR_INTEROP_TEST_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(common) +add_subdirectory(PInvoke/DllImportPath) add_subdirectory(PInvoke/BestFitMapping/Char) add_subdirectory(PInvoke/BestFitMapping/LPStr) add_subdirectory(PInvoke/Delegate/MarshalDelegateAsField) diff --git a/tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt b/tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt new file mode 100644 index 0000000..a0d2992 --- /dev/null +++ b/tests/src/Interop/PInvoke/DllImportPath/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required (VERSION 2.6) +project (DllImportPath) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + DllImportPathNative.cpp +) +# Additional files to reference: +# add the executable +add_library (DllImportPath_Local SHARED ${SOURCES}) +add_library (DllImportPath.Local SHARED ${SOURCES}) +add_library (DllImportPath_PathEnv SHARED ${SOURCES}) +add_library (DllImportPath_Relative SHARED ${SOURCES}) +add_library (DllImportPath_U�n�i�c�o�d�e SHARED ${SOURCES}) +target_link_libraries(DllImportPath_Local ${LINK_LIBRARIES_ADDITIONAL}) +target_link_libraries(DllImportPath.Local ${LINK_LIBRARIES_ADDITIONAL}) +target_link_libraries(DllImportPath_PathEnv ${LINK_LIBRARIES_ADDITIONAL}) +target_link_libraries(DllImportPath_Relative ${LINK_LIBRARIES_ADDITIONAL}) +target_link_libraries(DllImportPath_U�n�i�c�o�d�e ${LINK_LIBRARIES_ADDITIONAL}) +# add the install targets +install (TARGETS DllImportPath_Local DESTINATION bin) +install (TARGETS DllImportPath.Local DESTINATION bin) +install (TARGETS DllImportPath_PathEnv DESTINATION bin) +install (TARGETS DllImportPath_Relative DESTINATION bin) +install (TARGETS DllImportPath_U�n�i�c�o�d�e DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp new file mode 100644 index 0000000..e3ad7cd --- /dev/null +++ b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathNative.cpp @@ -0,0 +1,46 @@ +// 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 + +LPCWSTR strManaged = W("Managed\0String\0"); +LPCWSTR strNative = W(" Native\0String\0"); + +size_t lenstrManaged = 7; // the length of strManaged +size_t lenstrNative = 7; //the len of strNative + +extern "C" DLL_EXPORT bool STDMETHODCALLTYPE MarshalStringPointer_InOut(/*[in,out]*/LPWSTR *s) +{ + //Check the Input + size_t len = wcslen(*s); + if((len != lenstrManaged)||(wcsncmp(*s,strManaged, lenstrManaged)!=0)) + { + printf("Error in Function MarshalStringPointer_InOut\n"); + + //Expected + printf("Expected:"); + wprintf(L"%ls",strManaged); + printf("\tThe length of Expected:%d\n",static_cast(lenstrManaged)); + + //Actual + printf("Actual:"); + wprintf(L"%ls",*s); + printf("\tThe length of Actual:%d\n",static_cast(len)); + + return false; + } + + //Allocate New + CoreClrFree(*s); + + //Alloc New + size_t length = lenstrNative + 1; + *s = (LPWSTR)CoreClrAlloc(length * sizeof(WCHAR)); + memset(*s,'\0',length * sizeof(WCHAR)); + wcsncpy_s(*s,length,strNative,lenstrNative); + + //Return + return true; +} diff --git a/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs new file mode 100644 index 0000000..03c7cbc --- /dev/null +++ b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.cs @@ -0,0 +1,272 @@ +// 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.IO; +using System.Linq; +using System.Runtime.InteropServices; + +class Test +{ + private const string RelativeSubdirectoryName = "RelativeNative"; + private const string PathEnvSubdirectoryName = "Subdirectory"; + private const string PathEnvFileName = "MovedNativeLib"; + +#if PLATFORM_WINDOWS + private const string RelativePath1 = @".\RelativeNative\..\DllImportPath_Relative"; + private const string RelativePath3 = @"..\DllImportPathTest\DllImportPath_Relative"; +#else + private const string RelativePath1 = @"./RelativeNative/../libDllImportPath_Relative"; + private const string RelativePath3 = @"../DllImportPathTest/libDllImportPath_Relative"; +#endif + + [DllImport(@"DllImportPath_Local", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Local1([In, Out]ref string strManaged); + + [DllImport(@".\DllImportPath_Local", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Local2([In, Out]ref string strManaged); + + [DllImport(@"DllImportPath.Local.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_LocalWithDot1([In, Out]ref string strManaged); + + [DllImport(@".\DllImportPath.Local.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_LocalWithDot2([In, Out]ref string strManaged); + + [DllImport(RelativePath1, CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Relative1([In, Out]ref string strManaged); + + [DllImport(@"..\DllImportPathTest\DllImportPath_Relative.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Relative2([In, Out]ref string strManaged); + + [DllImport(RelativePath3, CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Relative3([In, Out]ref string strManaged); + + [DllImport(@".\..\DllImportPathTest\DllImportPath_Relative.dll", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Relative4([In, Out]ref string strManaged); + + [DllImport(@"DllImportPath_U�n�i�c�o�d�e", CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_Unicode([In, Out]ref string strManaged); + + [DllImport(PathEnvFileName, CharSet = CharSet.Unicode, EntryPoint = "MarshalStringPointer_InOut")] + private static extern bool MarshalStringPointer_InOut_PathEnv([In, Out]ref string strManaged); + + static bool DllExistsOnLocalPath() + { + string strManaged = "Managed"; + string native = " Native"; + + Console.WriteLine("[Calling MarshalStringPointer_InOut_Local1]."); + string strPara1 = strManaged; + if (!MarshalStringPointer_InOut_Local1(ref strPara1)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara1) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Console.WriteLine("[Calling MarshalStringPointer_InOut_Local2]"); + string strPara2 = strManaged; + if (!MarshalStringPointer_InOut_Local2(ref strPara2)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara2) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + + Console.WriteLine("[Calling MarshalStringPointer_InOut_LocalWithDot1]"); + string strPara3 = strManaged; + if (!MarshalStringPointer_InOut_LocalWithDot1(ref strPara3)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara3) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + + Console.WriteLine("[Calling MarshalStringPointer_InOut_LocalWithDot2]"); + string strPara4 = strManaged; + if (!MarshalStringPointer_InOut_LocalWithDot2(ref strPara4)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara4) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + } + + return true; + } + + static bool DllExistsOnRelativePath() + { + string strManaged = "Managed"; + string native = " Native"; + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // We need to ensure that the subdirectory exists for off-Windows. + { + var currentDirectory = Directory.GetCurrentDirectory(); + var info = new DirectoryInfo(currentDirectory); + info.CreateSubdirectory(RelativeSubdirectoryName); + } + + Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative1]"); + string strPara5 = strManaged; + if (!MarshalStringPointer_InOut_Relative1(ref strPara5)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara5) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative2]"); + string strPara6 = strManaged; + if (!MarshalStringPointer_InOut_Relative2(ref strPara6)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara6) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + } + + Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative3]"); + string strPara7 = strManaged; + if (!MarshalStringPointer_InOut_Relative3(ref strPara7)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara7) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Console.WriteLine("[Calling MarshalStringPointer_InOut_Relative4]"); + string strPara8 = strManaged; + if (!MarshalStringPointer_InOut_Relative4(ref strPara8)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != strPara8) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + } + + return true; + } + + private static void SetupPathEnvTest() + { + var currentDirectory = Directory.GetCurrentDirectory(); + var info = new DirectoryInfo(currentDirectory); + var subDirectory = info.CreateSubdirectory(PathEnvSubdirectoryName); + + var file = info.EnumerateFiles("*DllImportPath_PathEnv*", SearchOption.TopDirectoryOnly).FirstOrDefault(); + + var newFileLocation = Path.Combine(subDirectory.FullName, file.Name); + + file.CopyTo(Path.Combine(subDirectory.FullName, PathEnvFileName + file.Extension), true); + + Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + $";{subDirectory.FullName}"); + } + + static bool DllExistsOnPathEnv() + { + SetupPathEnvTest(); + + string managed = "Managed"; + string native = " Native"; + + Console.WriteLine("[Calling MarshalStringPointer_InOut_PathEnv]"); + if (!MarshalStringPointer_InOut_PathEnv(ref managed)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != managed) + { + Console.WriteLine($"The passed string is wrong. Expected {native} got {managed}."); + return false; + } + + return true; + } + + static bool DllExistsUnicode() + { + string managed = "Managed"; + string native = " Native"; + + Console.WriteLine("[Calling MarshalStringPointer_InOut_Unicode]"); + if (!MarshalStringPointer_InOut_Unicode(ref managed)) + { + Console.WriteLine("Return value is wrong"); + return false; + } + + if (native != managed) + { + Console.WriteLine("The passed string is wrong"); + return false; + } + + return true; + } + + public static int Main(string[] args) + { + bool success = true; + + success = success && DllExistsOnLocalPath(); + success = success && DllExistsOnRelativePath(); + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) // This test fails due to a bug in OSX 10.12 combined with the weird way that HFS+ handles unicode file names + { + success = success && DllExistsUnicode(); + } + success = success && DllExistsOnPathEnv(); + + return success ? 100 : 101; + } +} diff --git a/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj new file mode 100644 index 0000000..57e08f1 --- /dev/null +++ b/tests/src/Interop/PInvoke/DllImportPath/DllImportPathTest.csproj @@ -0,0 +1,41 @@ + + + + + Debug + AnyCPU + DllImportPathTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + $(DefineConstants);STATIC + + + + + + + False + + + + + + + + + + + + + $(BashCLRTestPreCommands);$(PathEnvSetupCommands) + + + + + + diff --git a/tests/src/dir.targets b/tests/src/dir.targets index 3e3ce9b..ac803ee 100644 --- a/tests/src/dir.targets +++ b/tests/src/dir.targets @@ -236,4 +236,7 @@ + + + -- 2.7.4