From 39b81b985530a3692946a8879a653be5f2c31747 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 --- .../Runtime/InteropServices/NativeLibrary.cs | 86 +++++++++++++ src/vm/callhelpers.h | 1 + src/vm/dllimport.cpp | 119 +++++++++++++----- 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 +- tests/src/Interop/CMakeLists.txt | 1 + .../CMakeLists.txt | 13 ++ .../CallBackTests.cs | 81 ++++++++++++ .../CallBackTests.csproj | 39 ++++++ .../ResolveLib.cpp | 11 ++ 13 files changed, 334 insertions(+), 37 deletions(-) create mode 100644 tests/src/Interop/NativeLibraryResolveCallBack/CMakeLists.txt create mode 100644 tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.cs create mode 100644 tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.csproj create mode 100644 tests/src/Interop/NativeLibraryResolveCallBack/ResolveLib.cpp diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs index 38712ac1b724..fa30af6d297f 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs @@ -12,6 +12,22 @@ namespace System.Runtime.InteropServices { + + /// + /// A delegate used to resolve native libraries via callback. + /// + /// The native library to resolve + /// The assembly requesting the resolution + /// + /// The DllImportSearchPathsAttribute on the PInvoke, if any. + /// Otherwise, the DllImportSearchPathsAttribute on the assembly, if any. + /// Otherwise null. + /// + /// The handle for the loaded native library on success, null on failure + public delegate IntPtr DllImportResolver(string libraryName, + Assembly assembly, + DllImportSearchPath? searchPath); + /// /// APIs for managing Native Libraries /// @@ -58,7 +74,9 @@ public static bool TryLoad(string libraryPath, out IntPtr handle) /// Otherwise, the flags specified by the DefaultDllImportSearchPaths attribute on the /// calling assembly (if any) are used. /// This LoadLibrary() method does not invoke the managed call-backs for native library resolution: + /// * The per-assembly registered callback /// * AssemblyLoadContext.LoadUnmanagedDll() + /// * AssemblyLoadContext.ResolvingUnmanagedDllEvent /// /// The name of the native library to be loaded /// The assembly loading the native library @@ -161,6 +179,74 @@ public static bool TryGetExport(IntPtr handle, string name, out IntPtr address) return address != IntPtr.Zero; } + /// + /// Map from assembly to native-library-resolution-callback. + /// Generally interop specific fields and properties are not added to assembly. + /// Therefore, this table uses weak assembly pointers to indirectly achieve + /// similar behavior. + /// + public static ConditionalWeakTable s_nativeDllResolveMap = null; + + /// + /// Set a callback for resolving native library imports from an assembly. + /// This per-assembly callback is the first attempt to resolve native library loads + /// initiated by this assembly. + /// + /// Only one resolver callback can be registered per assembly. + /// Trying to register a second callback fails with InvalidOperationException. + /// + /// The assembly for which the callback is registered + /// The callback to register + /// If assembly or resolver is null + /// If a callback is already set for this assembly + public static void SetDllImportResolver(Assembly assembly, DllImportResolver resolver) + { + if (assembly == null) + throw new ArgumentNullException(nameof(assembly)); + if (resolver == null) + throw new ArgumentNullException(nameof(resolver)); + if (!(assembly is RuntimeAssembly)) + throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); + + DllImportResolver existingResolver = null; + + if (s_nativeDllResolveMap == null) + { + s_nativeDllResolveMap = new ConditionalWeakTable(); + } + else if (s_nativeDllResolveMap.TryGetValue(assembly, out existingResolver)) + { + if (existingResolver != resolver) + throw new InvalidOperationException(); + return; + } + + s_nativeDllResolveMap.Add(assembly, resolver); + } + + /// + /// The helper function that calls the per-assembly native-library resolver + /// if one is registered for this assembly. + /// + /// The native library to load + /// The assembly trying load the native library + /// If the pInvoke has DefaultDllImportSearchPathAttribute + /// If hasdllImportSearchPathFlags is true, the flags in + /// DefaultDllImportSearchPathAttribute; meaningless otherwise + /// The handle for the loaded library on success. Null on failure. + internal static IntPtr LoadLibraryCallbackStub(string libraryName, Assembly assembly, + bool hasDllImportSearchPathFlags, uint dllImportSearchPathFlags) + { + DllImportResolver resolver; + + if (!s_nativeDllResolveMap.TryGetValue(assembly, out resolver)) + { + return IntPtr.Zero; + } + + return resolver(libraryName, assembly, hasDllImportSearchPathFlags ? (DllImportSearchPath?)dllImportSearchPathFlags : null); + } + /// External functions that implement the NativeLibrary interface [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/vm/callhelpers.h b/src/vm/callhelpers.h index bcd553dcc898..032cec43ced7 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..d7228e198304 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,34 @@ INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR sy return address; } +#ifndef PLATFORM_UNIX +BOOL IsWindowsAPISet(PCWSTR wszLibName) +{ + STANDARD_VM_CONTRACT; + + // 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 (IsWindowsAPISet(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 +6360,49 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, return (NATIVE_LIBRARY_HANDLE)hmod; } +NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallback(NDirectMethodDesc * pMD, LPCWSTR wszLibName) +{ + STANDARD_VM_CONTRACT; + + NATIVE_LIBRARY_HANDLE handle = NULL; + + DWORD dllImportSearchPathFlags = 0; + BOOL hasDllImportSearchPathFlags = pMD->HasDefaultDllImportSearchPathsAttribute(); + if (hasDllImportSearchPathFlags) + { + dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); + if (pMD->DllImportSearchAssemblyDirectory()) + dllImportSearchPathFlags |= DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + } + + Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); + + GCX_COOP(); + + struct { + STRINGREF libNameRef; + OBJECTREF assemblyRef; + } gc = { NULL, NULL }; + + GCPROTECT_BEGIN(gc); + + gc.libNameRef = StringObject::NewString(wszLibName); + gc.assemblyRef = pAssembly->GetExposedObject(); + + PREPARE_NONVIRTUAL_CALLSITE(METHOD__MARSHAL__LOADLIBRARYCALLBACKSTUB); + DECLARE_ARGHOLDER_ARRAY(args, 4); + args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.libNameRef); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.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 +6426,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 +6553,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 +6563,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 (IsWindowsAPISet(wszLibName)) { hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker); if (hmod != NULL) @@ -6536,7 +6591,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 +6600,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 +6615,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 +6652,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 +6673,19 @@ 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 + 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 +6693,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..d0dc71f9256d 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/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 9784ea1c95ab..baf57c294262 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory(StringMarshalling/VBByRefStr) add_subdirectory(MarshalAPI/FunctionPointer) add_subdirectory(MarshalAPI/IUnknown) add_subdirectory(NativeLibrary) +add_subdirectory(NativeLibraryResolveCallBack) add_subdirectory(SizeConst) add_subdirectory(DllImportAttribute/ExeFile) add_subdirectory(DllImportAttribute/FileNameContainDot) diff --git a/tests/src/Interop/NativeLibraryResolveCallBack/CMakeLists.txt b/tests/src/Interop/NativeLibraryResolveCallBack/CMakeLists.txt new file mode 100644 index 000000000000..b3f3409e3e0f --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveCallBack/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 2.6) +project (ResolveLib) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES ResolveLib.cpp) + +# add the executable +add_library (ResolveLib SHARED ${SOURCES}) +target_link_libraries(ResolveLib ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS ResolveLib DESTINATION bin) + + diff --git a/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.cs b/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.cs new file mode 100644 index 000000000000..22df7cfb9b38 --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.cs @@ -0,0 +1,81 @@ +// 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 CallBackTests +{ + public static int Main() + { + try + { + Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); + string testBinDir = Path.GetDirectoryName(assembly.Location); + + DllImportResolver resolver = + (string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath) => + NativeLibrary.LoadLibrary("ResolveLib", assembly, dllImportSearchPath); + + DllImportResolver anotherResolver = + (string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath) => + IntPtr.Zero; + + try + { + NativeLibrary.SetDllImportResolver(null, resolver); + + Console.WriteLine("Expected exception not thrown"); + return 101; + } + catch (ArgumentNullException e){} + + try + { + NativeLibrary.SetDllImportResolver(resolver, null); + + Console.WriteLine("Expected exception not thrown"); + return 102; + } + catch (ArgumentNullException e){} + + // Set a resolver callback + NativeLibrary.SetDllImportResolver(assembly, resolver); + + // Set the same resolver again. + NativeLibrary.SetDllImportResolver(assembly, resolver); + + try + { + // Try to set another resolver on the same assembly. + NativeLibrary.SetDllImportResolver(assembly, anotherResolver); + + Console.WriteLine("Expected Exception not thrown"); + return 103; + } + catch (InvalidOperationException e){} + + if (NativeSum(10, 10) != 20) + { + Console.WriteLine("Unexpected ReturnValue from NativeSum()"); + return 104; + } + } + catch (Exception e) + { + Console.WriteLine($"Unexpected exception: {e.Message}"); + return 105; + } + + return 100; + } + + [DllImport("NativeLib")] + static extern int NativeSum(int arg1, int arg2); +} diff --git a/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.csproj b/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.csproj new file mode 100644 index 000000000000..de2de5a9b85a --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.csproj @@ -0,0 +1,39 @@ + + + + + Debug + AnyCPU + CallBackTests + 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 + + + + diff --git a/tests/src/Interop/NativeLibraryResolveCallBack/ResolveLib.cpp b/tests/src/Interop/NativeLibraryResolveCallBack/ResolveLib.cpp new file mode 100644 index 000000000000..bdf5beb4247a --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveCallBack/ResolveLib.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; +} +