From 09b0e78e6ad06d1c089f3d59ec154f658eef667c Mon Sep 17 00:00:00 2001 From: swaroop-sridhar Date: Wed, 21 Nov 2018 12:22:19 -0800 Subject: [PATCH] Add Per-assembly Load Native Library callbacks This Change implements the Native Library resolution Call-backs proposed in https://github.com/dotnet/corefx/issues/32015 public static bool RegisterDllImportResolver( Assembly assembly, Func callback ); This API is not yet approved, and the API contracts in CoreFX will not be added until the API approval is complete. In the meantime, we want to have the code reviewed, tested, and avaiable in CoreCLR. --- .../System/Runtime/InteropServices/Marshal.cs | 5 + src/vm/callhelpers.h | 1 + src/vm/dllimport.cpp | 124 ++++++++++++++---- src/vm/dllimport.h | 9 +- src/vm/interoputil.cpp | 6 +- src/vm/interoputil.h | 2 +- src/vm/metasig.h | 1 + src/vm/mscorlib.h | 2 +- .../MarshalAPI/DllImportUtil/CMakeLists.txt | 13 ++ .../MarshalAPI/DllImportUtil/DllImportUtil.cs | 110 ++++++++++++++++ .../DllImportUtil/DllImportUtil.csproj | 47 +++++++ .../DllImportUtil/NativeLibrary.cpp | 11 ++ .../MarshalAPI/DllResolve/DllResolveTests.cs | 56 ++++++++ .../DllResolve/DllResolveTests.csproj | 42 ++++++ .../NativeLibrary/NativeLibraryTests.csproj | 3 + 15 files changed, 395 insertions(+), 37 deletions(-) create mode 100644 tests/src/Interop/MarshalAPI/DllImportUtil/CMakeLists.txt create mode 100644 tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.cs create mode 100644 tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.csproj create mode 100644 tests/src/Interop/MarshalAPI/DllImportUtil/NativeLibrary.cpp create mode 100644 tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.cs create mode 100644 tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.csproj diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index 5e9fd3108109..5173415d8a4d 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -29,6 +29,11 @@ public static partial class Marshal internal static Guid IID_IUnknown = new Guid(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); #endif //FEATURE_COMINTEROP + static Marshal() + { + nativeDllResolveMap = new ConditionalWeakTable>(); + } + private const int LMEM_FIXED = 0; private const int LMEM_MOVEABLE = 2; #if !FEATURE_PAL diff --git a/src/vm/callhelpers.h b/src/vm/callhelpers.h index bcd553dcc898..6cd2e44bd6b2 100644 --- a/src/vm/callhelpers.h +++ b/src/vm/callhelpers.h @@ -566,6 +566,7 @@ enum DispatchCallSimpleFlags #define STRINGREF_TO_ARGHOLDER(x) (LPVOID)STRINGREFToObject(x) #define PTR_TO_ARGHOLDER(x) (LPVOID)x #define DWORD_TO_ARGHOLDER(x) (LPVOID)(SIZE_T)x +#define BOOL_TO_ARGHOLDER(x) DWORD_TO_ARGHOLDER(x) #define INIT_VARIABLES(count) \ DWORD __numArgs = count; \ diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp index 2ce100b4b93a..4b7c97736162 100644 --- a/src/vm/dllimport.cpp +++ b/src/vm/dllimport.cpp @@ -6144,7 +6144,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL thr // static NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly, - BOOL hasDllImportSearchFlag, DWORD dllImportSearchFlag, + BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags, BOOL throwOnError) { CONTRACTL @@ -6157,15 +6157,15 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly * LoadLibErrorTracker errorTracker; - // First checks if a default DllImportSearchPathFlag was passed in, if so, use that value. + // First checks if a default dllImportSearchPathFlags was passed in, if so, use that value. // Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute. If so, use that value. BOOL searchAssemblyDirectory = TRUE; - DWORD dllImportSearchPathFlag = 0; + DWORD dllImportSearchPathFlags = 0; - if (hasDllImportSearchFlag) + if (hasDllImportSearchFlags) { - dllImportSearchPathFlag = dllImportSearchFlag & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; - searchAssemblyDirectory = dllImportSearchFlag & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; } else @@ -6174,13 +6174,13 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly * if (pModule->HasDefaultDllImportSearchPathsAttribute()) { - dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); + dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); } } NATIVE_LIBRARY_HANDLE hmod = - LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlag, &errorTracker, libraryName); + LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName); if (throwOnError && (hmod == nullptr)) { @@ -6199,11 +6199,11 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD // First checks if the method has DefaultDllImportSearchPathsAttribute. If so, use that value. // Otherwise checks if the assembly has the attribute. If so, use that value. BOOL searchAssemblyDirectory = TRUE; - DWORD dllImportSearchPathFlag = 0; + DWORD dllImportSearchPathFlags = 0; if (pMD->HasDefaultDllImportSearchPathsAttribute()) { - dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); + dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory(); } else @@ -6212,13 +6212,13 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD if (pModule->HasDefaultDllImportSearchPathsAttribute()) { - dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); + dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); } } Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); - return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlag, pErrorTracker, wszLibName); + return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName); } // static @@ -6267,23 +6267,32 @@ INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR sy return address; } +#ifndef PLATFORM_UNIX +BOOL IsWindowsAPI(PCWSTR wszLibName) +{ + // This is replicating quick check from the OS implementation of api sets. + return SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || + SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0; +} +#endif // !PLATFORM_UNIX + // static -NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, PCWSTR wszLibName) +NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, PCWSTR wszLibName) { STANDARD_VM_CONTRACT; //Dynamic Pinvoke Support: //Check if we need to provide the host a chance to provide the unmanaged dll #ifndef PLATFORM_UNIX - // Prevent Overriding of Windows API sets. - // This is replicating quick check from the OS implementation of api sets. - if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0) + if (IsWindowsAPI(wszLibName)) { + // Prevent Overriding of Windows API sets. return NULL; } -#endif +#endif // !PLATFORM_UNIX LPVOID hmod = NULL; + AppDomain* pDomain = GetAppDomain(); CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext(); Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); @@ -6349,6 +6358,55 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, return (NATIVE_LIBRARY_HANDLE)hmod; } +NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallBack(NDirectMethodDesc * pMD, LPCWSTR wszLibName) +{ +#ifndef PLATFORM_UNIX + if (IsWindowsAPI(wszLibName)) + { + // Prevent Overriding of Windows API sets. + return NULL; + } +#endif // !PLATFORM_UNIX + + DWORD dllImportSearchPathFlags = 0; + BOOL hasDllImportSearchPathFlags = pMD->HasDefaultDllImportSearchPathsAttribute(); + if (hasDllImportSearchPathFlags) + { + dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); + if (pMD->DllImportSearchAssemblyDirectory()) + dllImportSearchPathFlags |= DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + } + + GCX_COOP(); + + struct { + STRINGREF libNameRef; + OBJECTREF assemblyRef; + } protect; + + + Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); + protect.libNameRef = StringObject::NewString(wszLibName); + protect.assemblyRef = pAssembly->GetExposedObject(); + + NATIVE_LIBRARY_HANDLE handle = NULL; + + GCPROTECT_BEGIN(protect); + + PREPARE_NONVIRTUAL_CALLSITE(METHOD__MARSHAL__LOADLIBRARYCALLBACKSTUB); + DECLARE_ARGHOLDER_ARRAY(args, 4); + args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(protect.libNameRef); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(protect.assemblyRef); + args[ARGNUM_2] = BOOL_TO_ARGHOLDER(hasDllImportSearchPathFlags); + args[ARGNUM_3] = DWORD_TO_ARGHOLDER(dllImportSearchPathFlags); + + // Make the call + CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args); + GCPROTECT_END(); + + return handle; +} + // Try to load the module alongside the assembly where the PInvoke was declared. NATIVE_LIBRARY_HANDLE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) { @@ -6372,11 +6430,12 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssem } // Try to load the module from the native DLL search directories -NATIVE_LIBRARY_HANDLE NDirect::LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) +NATIVE_LIBRARY_HANDLE NDirect::LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker) { STANDARD_VM_CONTRACT; NATIVE_LIBRARY_HANDLE hmod = NULL; + AppDomain* pDomain = GetAppDomain(); if (pDomain->HasNativeDllSearchDirectories()) { @@ -6498,7 +6557,7 @@ static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* num // Search for the library and variants of its name in probing directories. //static NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssembly, - BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag, + BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags, LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName) { STANDARD_VM_CONTRACT; @@ -6508,7 +6567,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb #if defined(FEATURE_CORESYSTEM) && !defined(PLATFORM_UNIX) // Try to go straight to System32 for Windows API sets. This is replicating quick check from // the OS implementation of api sets. - if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0) + if (IsWindowsAPI(wszLibName)) { hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker); if (hmod != NULL) @@ -6536,7 +6595,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb currLibNameVariation.Printf(prefixSuffixCombinations[i], PLATFORM_SHARED_LIB_PREFIX_W, wszLibName, PLATFORM_SHARED_LIB_SUFFIX_W); // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path - hmod = LoadFromNativeDllSearchDirectories(pDomain, currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker); + hmod = LoadFromNativeDllSearchDirectories(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker); if (hmod != NULL) { return hmod; @@ -6545,11 +6604,11 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb if (!libNameIsRelativePath) { DWORD flags = loadWithAlteredPathFlags; - if ((dllImportSearchPathFlag & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0) + if ((dllImportSearchPathFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0) { // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH. - flags |= dllImportSearchPathFlag; + flags |= dllImportSearchPathFlags; } hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker); @@ -6560,14 +6619,14 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb } else if ((callingAssembly != nullptr) && searchAssemblyDirectory) { - hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker); + hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker); if (hmod != NULL) { return hmod; } } - hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlag, pErrorTracker); + hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker); if (hmod != NULL) { return hmod; @@ -6597,7 +6656,7 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssemb Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED); Module *pModule = pAssembly->FindModuleByName(szLibName); - hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker); + hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker); } } @@ -6618,11 +6677,20 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke if ( !name || !*name ) return NULL; - ModuleHandleHolder hmod; PREFIX_ASSUME( name != NULL ); MAKE_WIDEPTR_FROMUTF8( wszLibName, name ); + ModuleHandleHolder hmod = LoadLibraryModuleViaCallBack(pMD, wszLibName); + if (hmod != NULL) + { +#ifdef FEATURE_PAL + // Register the system library handle with PAL and get a PAL library handle + hmod = PAL_RegisterLibraryDirect(hmod, wszLibName); +#endif // FEATURE_PAL + return hmod.Extract(); + } + AppDomain* pDomain = GetAppDomain(); // AssemblyLoadContext is not supported in AppX mode and thus, @@ -6630,7 +6698,7 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke // AppX mode. if (!AppX::IsAppXProcess()) { - hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName); + hmod = LoadLibraryModuleViaHost(pMD, wszLibName); if (hmod != NULL) { #ifdef FEATURE_PAL diff --git a/src/vm/dllimport.h b/src/vm/dllimport.h index 2f25e59570e1..93c42a78a3b5 100644 --- a/src/vm/dllimport.h +++ b/src/vm/dllimport.h @@ -76,7 +76,7 @@ class NDirect static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod); static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError); static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly, - BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, + BOOL hasDllImportSearchPathFlags, DWORD dllImportSearchPathFlags, BOOL throwOnError); static HINSTANCE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker); static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle); @@ -122,11 +122,12 @@ class NDirect private: NDirect() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class - static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); + static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); static NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); - static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName); + static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, const wchar_t* wszLibName); + static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaCallBack(NDirectMethodDesc * pMD, const wchar_t* wszLibName); static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName); - static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName); + static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName); #if !defined(FEATURE_PAL) // Indicates if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623 diff --git a/src/vm/interoputil.cpp b/src/vm/interoputil.cpp index a21e68b27095..6854edd15773 100644 --- a/src/vm/interoputil.cpp +++ b/src/vm/interoputil.cpp @@ -898,8 +898,8 @@ void FillExceptionData( //--------------------------------------------------------------------------- //returns true if pImport has DefaultDllImportSearchPathsAttribute -//if true, also returns dllImportSearchPathFlag and searchAssemblyDirectory values. -BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDllImportSearchPathFlag) +//if true, also returns dllImportSearchPathFlags and searchAssemblyDirectory values. +BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDllImportSearchPathFlags) { CONTRACTL { @@ -929,7 +929,7 @@ BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, md args[0].InitEnum(SERIALIZATION_TYPE_U4, (ULONG)0); ParseKnownCaArgs(ca, args, lengthof(args)); - *pDllImportSearchPathFlag = args[0].val.u4; + *pDllImportSearchPathFlags = args[0].val.u4; return TRUE; } diff --git a/src/vm/interoputil.h b/src/vm/interoputil.h index 91f6828c4950..770568a93671 100644 --- a/src/vm/interoputil.h +++ b/src/vm/interoputil.h @@ -137,7 +137,7 @@ void FillExceptionData( //--------------------------------------------------------------------------- //returns true if pImport has DefaultDllImportSearchPathsAttribute -//if true, also returns dllImportSearchPathFlag and searchAssemblyDirectory values. +//if true, also returns dllImportSearchPathFlags and searchAssemblyDirectory values. BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDlImportSearchPathFlag); //--------------------------------------------------------------------------- diff --git a/src/vm/metasig.h b/src/vm/metasig.h index 154c91570cc2..6fd136d3ecf4 100644 --- a/src/vm/metasig.h +++ b/src/vm/metasig.h @@ -551,6 +551,7 @@ DEFINE_METASIG_T(IM(RefGuid_OutIntPtr_RetCustomQueryInterfaceResult, r(g(GUID)) #endif //FEATURE_COMINTEROP DEFINE_METASIG_T(SM(IntPtr_AssemblyName_RetAssemblyBase, I C(ASSEMBLY_NAME), C(ASSEMBLYBASE))) +DEFINE_METASIG_T(SM(Str_AssemblyBase_Bool_UInt_RetIntPtr, s C(ASSEMBLYBASE) F K, I)) // ThreadPool DEFINE_METASIG(SM(Obj_Bool_RetVoid, j F, v)) diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 62205d39bc88..cd1b5ef210a1 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -486,7 +486,7 @@ DEFINE_METHOD(MARSHAL, GET_FUNCTION_POINTER_FOR_DELEGATE, GetFuncti DEFINE_METHOD(MARSHAL, GET_DELEGATE_FOR_FUNCTION_POINTER, GetDelegateForFunctionPointer, SM_IntPtr_Type_RetDelegate) DEFINE_METHOD(MARSHAL, ALLOC_CO_TASK_MEM, AllocCoTaskMem, SM_Int_RetIntPtr) DEFINE_FIELD(MARSHAL, SYSTEM_MAX_DBCS_CHAR_SIZE, SystemMaxDBCSCharSize) - +DEFINE_METHOD(MARSHAL, LOADLIBRARYCALLBACKSTUB, LoadLibraryCallbackStub, SM_Str_AssemblyBase_Bool_UInt_RetIntPtr) DEFINE_CLASS(MEMBER, Reflection, MemberInfo) diff --git a/tests/src/Interop/MarshalAPI/DllImportUtil/CMakeLists.txt b/tests/src/Interop/MarshalAPI/DllImportUtil/CMakeLists.txt new file mode 100644 index 000000000000..93b6277e579f --- /dev/null +++ b/tests/src/Interop/MarshalAPI/DllImportUtil/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 2.6) +project (NativeLib) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES NativeLibrary.cpp) + +# add the executable +add_library (NativeLib SHARED ${SOURCES}) +target_link_libraries(NativeLib ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS NativeLib DESTINATION bin) + + diff --git a/tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.cs b/tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.cs new file mode 100644 index 000000000000..08bfc4ca4b77 --- /dev/null +++ b/tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.cs @@ -0,0 +1,110 @@ +// 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.Reflection; +using System.Runtime.InteropServices; +using TestLibrary; + +using Console = Internal.Console; + +namespace DllImportUtil +{ + public enum TestResult { + Success, + ReturnFailure, + ReturnNull, + IncorrectEvaluation, + ArgumentNull, + ArgumentBad, + + DllNotFound, + BadImage, + InvalidOperation, + EntryPointNotFound, + GenericException + }; + + public class Test + { + public bool EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success) + { + if (actualValue == expectedValue) + { + if (Verbose) + Console.WriteLine(String.Format("{0} : {1} : [OK]", CurrentTest, actualValue)); + return true; + } + else + { + Console.WriteLine(String.Format(" {0} : {1} : [FAIL]", CurrentTest, actualValue)); + return false; + } + } + public TestResult Run (Func test) + { + TestResult result; + + try + { + result = test(); + } + catch (ArgumentNullException e) + { + return TestResult.ArgumentNull; + } + catch (ArgumentException e) + { + return TestResult.ArgumentBad; + } + catch (DllNotFoundException e) + { + return TestResult.DllNotFound; + } + catch (BadImageFormatException e) + { + return TestResult.BadImage; + } + catch (InvalidOperationException e) + { + return TestResult.InvalidOperation; + } + catch (EntryPointNotFoundException e) + { + return TestResult.EntryPointNotFound; + } + catch (Exception e) + { + return TestResult.GenericException; + } + + return result; + } + + public static string GetDecoratedName(string baseName) + { + if (TestLibrary.Utilities.IsWindows) + { + return baseName + ".dll"; + } + if (TestLibrary.Utilities.IsLinux) + { + return "lib" + baseName + ".so"; + } + if (TestLibrary.Utilities.IsMacOSX) + { + return "lib" + baseName + ".dylib"; + } + + return "ERROR"; + } + public bool Verbose; + public string CurrentTest; + public string LocalLibPlainName; + public string LocalLibName => GetDecoratedName(LocalLibPlainName); + public string Win32LibName => "msi.dll"; + public static string CommonLibPlainName => "NativeLib"; + public string CommonLibName => GetDecoratedName(CommonLibPlainName); + } +} \ No newline at end of file diff --git a/tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.csproj b/tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.csproj new file mode 100644 index 000000000000..65632b71c8b5 --- /dev/null +++ b/tests/src/Interop/MarshalAPI/DllImportUtil/DllImportUtil.csproj @@ -0,0 +1,47 @@ + + + + + Debug + AnyCPU + DllImportUtil + 2.0 + {C8C0DC74-FAC4-45B1-81FE-70C4808366E1} + Library + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + true + true + false + + + + + + + + + False + + + + + + + + + + + PreserveNewest + + + + + {c8c0dc74-fac4-45b1-81fe-70c4808366e0} + CoreCLRTestLibrary + + + + + diff --git a/tests/src/Interop/MarshalAPI/DllImportUtil/NativeLibrary.cpp b/tests/src/Interop/MarshalAPI/DllImportUtil/NativeLibrary.cpp new file mode 100644 index 000000000000..bdf5beb4247a --- /dev/null +++ b/tests/src/Interop/MarshalAPI/DllImportUtil/NativeLibrary.cpp @@ -0,0 +1,11 @@ +// 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 + +extern "C" DLL_EXPORT int NativeSum(int a, int b) +{ + return a + b; +} + diff --git a/tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.cs b/tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.cs new file mode 100644 index 000000000000..bb6cef094738 --- /dev/null +++ b/tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.cs @@ -0,0 +1,56 @@ +// 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.Reflection; +using System.Runtime.InteropServices; +using TestLibrary; +using DllImportUtil; + +using Console = Internal.Console; + +public class NativeLibraryTest +{ + static Test test; + + public static int Main() + { + bool success = true; + + Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); + string testBinDir = Path.GetDirectoryName(assembly.Location); + + success &= test.EXPECT(RegisterResolver(null, LoadLibraryCallBack), TestResult.ArgumentNull); + success &= test.EXPECT(RegisterResolver(assembly, null), TestResult.ArgumentNull); + success &= test.EXPECT(RegisterResolver(assembly, LoadLibraryCallBack)); + success &= test.EXPECT(RegisterResolver(assembly, LoadLibraryCallBack), TestResult.ReturnFailure); + + success &= NativeSum(10, 10) == 20; + + return (success) ? 100 : -100; + } + public static IntPtr LoadLibraryCallBack(string libraryName, Assembly assembly, + DllImportSearchPath? dllImportSearchPath) + { + return Marshal.LoadLibrary(libraryName, assembly, dllImportSearchPath); + } + + static TestResult RegisterResolver(Assembly assembly, Func callBack) + { + test.CurrentTest = String.Format("RegisterDllImportResolver({0}, {1})", assembly.FullName, callBack); + + TestResult result = test.Run(() => { + bool success = Marshal.RegisterDllImportResolver(assembly, callBack); + if (!success) + return TestResult.ReturnFailure; + return TestResult.Success; + }); + + return result; + } + + + [DllImport("NativeLib")] + static extern int NativeSum(int arg1, int arg2); +} diff --git a/tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.csproj b/tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.csproj new file mode 100644 index 000000000000..edc20c0f6faf --- /dev/null +++ b/tests/src/Interop/MarshalAPI/DllResolve/DllResolveTests.csproj @@ -0,0 +1,42 @@ + + + + + Debug + AnyCPU + DllResolveTests + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + true + + + + + + + + + False + + + + + + + + + + + {c8c0dc74-fac4-45b1-81fe-70c4808366e0} + CoreCLRTestLibrary + + + DllImportUtil + + + + diff --git a/tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj b/tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj index 9f01b9f70c4a..5ce5e65f8df8 100644 --- a/tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj +++ b/tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj @@ -39,6 +39,9 @@ {c8c0dc74-fac4-45b1-81fe-70c4808366e0} CoreCLRTestLibrary + + DllImportUtil +