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..6b24cd79eab7 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 @@ -117,7 +135,6 @@ public static bool TryLoad(string libraryName, Assembly assembly, DllImportSearc /// No action if the input handle is null. /// /// The native library handle to be freed - /// If the operation fails public static void Free(IntPtr handle) { FreeLib(handle); @@ -161,6 +178,74 @@ public static bool TryGetExport(IntPtr handle, string name, out IntPtr address) return address != IntPtr.Zero; } + /// + /// Map from assembly to native-library resolver. + /// Interop specific fields and properties are generally not added to Assembly class. + /// 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 resolver is the first attempt to resolve native library loads + /// initiated by this assembly. + /// + /// Only one resolver can be registered per assembly. + /// Trying to register a second resolver fails with InvalidOperationException. + /// + /// The assembly for which the resolver is registered + /// The resolver callback to register + /// If assembly or resolver is null + /// If a resolver 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); + + if (s_nativeDllResolveMap == null) + { + s_nativeDllResolveMap = new ConditionalWeakTable(); + } + + try + { + s_nativeDllResolveMap.Add(assembly, resolver); + } + catch (ArgumentException e) + { + // ConditionalWealTable throws ArgumentException if the Key already exists + throw new InvalidOperationException("Resolver is alerady Set for the Assembly"); + } + } + + /// + /// 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 845ebf990753..a6670b385f9c 100644 --- a/src/vm/dllimport.cpp +++ b/src/vm/dllimport.cpp @@ -51,11 +51,6 @@ #include "clr/fs/path.h" using namespace clr::fs; -// The Bit 0x2 has different semantics in DllImportSearchPath and LoadLibraryExA flags. -// In DllImportSearchPath enum, bit 0x2 represents SearchAssemblyDirectory -- which is performed by CLR. -// Unlike other bits in this enum, this bit shouldn't be directly passed on to LoadLibrary() -#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2 - // remove when we get an updated SDK #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000 @@ -6127,6 +6122,57 @@ bool NDirect::s_fSecureLoadLibrarySupported = false; #define PLATFORM_SHARED_LIB_PREFIX_W W("") #endif // !FEATURE_PAL +// The Bit 0x2 has different semantics in DllImportSearchPath and LoadLibraryExA flags. +// In DllImportSearchPath enum, bit 0x2 represents SearchAssemblyDirectory -- which is performed by CLR. +// Unlike other bits in this enum, this bit shouldn't be directly passed on to LoadLibrary() +#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2 + +// DllImportSearchPathFlags is a special enumeration, whose values are tied closely with LoadLibrary flags. +// There is no "default" value DllImportSearchPathFlags. In the absence of DllImportSearchPath attribute, +// CoreCLR's LoadLibrary implementation uses the following defaults. +// Other implementations of LoadLibrary callbacks/events are free to use other default conventions. +void GetDefaultDllImportSearchPathFlags(DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) +{ + STANDARD_VM_CONTRACT; + + *searchAssemblyDirectory = TRUE; + *dllImportSearchPathFlags = 0; +} + +// If a module has the DllImportSearchPathAttribute, get DllImportSearchPathFlags from it, and return true. +// Otherwise, get the default value for the flags, and return false. +BOOL GetDllImportSearchPathFlags(Module *pModule, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) +{ + STANDARD_VM_CONTRACT; + + if (pModule->HasDefaultDllImportSearchPathsAttribute()) + { + *dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); + *searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); + return true; + } + + GetDefaultDllImportSearchPathFlags(dllImportSearchPathFlags, searchAssemblyDirectory); + return false; +} + +// If a pInvoke has DllImportSearchPathAttribute, get DllImportSearchPathFlags from it, and returns true. +// Otherwise, if the containing assembly has the DllImportSearchPathAttribute, get DllImportSearchPathFlags from it, and returns true. +// Otherwise, return false (out parameters are untouched). +BOOL GetDllImportSearchPathFlags(NDirectMethodDesc * pMD, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory) +{ + STANDARD_VM_CONTRACT; + + if (pMD->HasDefaultDllImportSearchPathsAttribute()) + { + *dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); + *searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory(); + return true; + } + + return GetDllImportSearchPathFlags(pMD->GetModule(), dllImportSearchPathFlags, searchAssemblyDirectory); +} + // static NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError) { @@ -6165,9 +6211,10 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly * LoadLibErrorTracker errorTracker; // 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 dllImportSearchPathFlags = 0; + // Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute. + // If so, use that value. + BOOL searchAssemblyDirectory; + DWORD dllImportSearchPathFlags; if (hasDllImportSearchFlags) { @@ -6175,15 +6222,10 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly * searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; } - else + else { - Module * pModule = callingAssembly->GetManifestModule(); - - if (pModule->HasDefaultDllImportSearchPathsAttribute()) - { - dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); - searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); - } + GetDllImportSearchPathFlags(callingAssembly->GetManifestModule(), + &dllImportSearchPathFlags, &searchAssemblyDirectory); } NATIVE_LIBRARY_HANDLE hmod = @@ -6203,26 +6245,10 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD { STANDARD_VM_CONTRACT; - // 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 dllImportSearchPathFlags = 0; + BOOL searchAssemblyDirectory; + DWORD dllImportSearchPathFlags; - if (pMD->HasDefaultDllImportSearchPathsAttribute()) - { - dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); - searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory(); - } - else - { - Module * pModule = pMD->GetModule(); - - if (pModule->HasDefaultDllImportSearchPathsAttribute()) - { - dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue(); - searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory(); - } - } + GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory); Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName); @@ -6452,18 +6478,20 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallback(NDirectMethodDesc * { STANDARD_VM_CONTRACT; - NATIVE_LIBRARY_HANDLE handle = NULL; - - DWORD dllImportSearchPathFlags = 0; - BOOL hasDllImportSearchPathFlags = pMD->HasDefaultDllImportSearchPathsAttribute(); - if (hasDllImportSearchPathFlags) + if (pMD->GetModule()->IsSystem()) { - dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue(); - if (pMD->DllImportSearchAssemblyDirectory()) - dllImportSearchPathFlags |= DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; + // Don't attempt to callback on Corelib itself. + // The LoadLibrary callback stub is managed code that requires CoreLib + return NULL; } + DWORD dllImportSearchPathFlags; + BOOL searchAssemblyDirectory; + BOOL hasDllImportSearchPathFlags = GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory); + dllImportSearchPathFlags |= searchAssemblyDirectory ? DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY : 0; + Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); + NATIVE_LIBRARY_HANDLE handle = NULL; GCX_COOP(); @@ -6491,87 +6519,6 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallback(NDirectMethodDesc * return handle; } -// Return the AssemblyLoadContext for an assembly -INT_PTR GetManagedAssemblyLoadContext(Assembly* pAssembly) -{ - STANDARD_VM_CONTRACT; - - PTR_ICLRPrivBinder pBindingContext = pAssembly->GetManifestFile()->GetBindingContext(); - if (pBindingContext == NULL) - { - // GetBindingContext() returns NULL for System.Private.CoreLib - return NULL; - } - - UINT_PTR assemblyBinderID = 0; - IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); - - AppDomain *pDomain = GetAppDomain(); - ICLRPrivBinder *pCurrentBinder = reinterpret_cast(assemblyBinderID); - -#ifdef FEATURE_COMINTEROP - if (AreSameBinderInstance(pCurrentBinder, pDomain->GetWinRtBinder())) - { - // No ALC associated handle with WinRT Binders. - return NULL; - } -#endif // FEATURE_COMINTEROP - - // The code here deals with two implementations of ICLRPrivBinder interface: - // - CLRPrivBinderCoreCLR for the TPA binder in the default ALC, and - // - CLRPrivBinderAssemblyLoadContext for custom ALCs. - // in order obtain the associated ALC handle. - INT_PTR ptrManagedAssemblyLoadContext = AreSameBinderInstance(pCurrentBinder, pDomain->GetTPABinderContext()) - ? ((CLRPrivBinderCoreCLR *)pCurrentBinder)->GetManagedAssemblyLoadContext() - : ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext(); - - return ptrManagedAssemblyLoadContext; -} - -// static -NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaEvent(NDirectMethodDesc * pMD, PCWSTR wszLibName) -{ - STANDARD_VM_CONTRACT; - - NATIVE_LIBRARY_HANDLE hmod = NULL; - Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); - INT_PTR ptrManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(pAssembly); - - if (ptrManagedAssemblyLoadContext == NULL) - { - return NULL; - } - - GCX_COOP(); - - struct { - STRINGREF DllName; - OBJECTREF AssemblyRef; - } gc = { NULL, NULL }; - - GCPROTECT_BEGIN(gc); - - gc.DllName = StringObject::NewString(wszLibName); - gc.AssemblyRef = pAssembly->GetExposedObject(); - - // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDllUsingEvent method - // While ResolveUnmanagedDllUsingEvent() could compute the AssemblyLoadContext using the AssemblyRef - // argument, it will involve another pInvoke to the runtime. So AssemblyLoadContext is passed in - // as an additional argument. - PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLLUSINGEVENT); - DECLARE_ARGHOLDER_ARRAY(args, 3); - args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.DllName); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.AssemblyRef); - args[ARGNUM_2] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext); - - // Make the call - CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args); - - GCPROTECT_END(); - - return hmod; -} - // 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) { @@ -6842,7 +6789,7 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke if ( !name || !*name ) return NULL; - PREFIX_ASSUME( name != NULL ); + PREFIX_ASSUME( name != NULL ); MAKE_WIDEPTR_FROMUTF8( wszLibName, name ); ModuleHandleHolder hmod = LoadLibraryModuleViaCallback(pMD, wszLibName); diff --git a/src/vm/dllimport.h b/src/vm/dllimport.h index 1203803b9afd..f4943ff8a0a8 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,12 +122,13 @@ 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, LPCWSTR wszLibName); static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaEvent(NDirectMethodDesc * pMD, LPCWSTR wszLibName); + static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaCallback(NDirectMethodDesc * pMD, LPCWSTR 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 cfa844012eea..cbac116bd3d3 100644 --- a/src/vm/metasig.h +++ b/src/vm/metasig.h @@ -552,6 +552,7 @@ DEFINE_METASIG_T(IM(RefGuid_OutIntPtr_RetCustomQueryInterfaceResult, r(g(GUID)) DEFINE_METASIG_T(SM(IntPtr_AssemblyName_RetAssemblyBase, I C(ASSEMBLY_NAME), C(ASSEMBLYBASE))) DEFINE_METASIG_T(SM(Str_AssemblyBase_IntPtr_RetIntPtr, s C(ASSEMBLYBASE) I, I)) +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 a1341dd70f68..730355f4354f 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -487,6 +487,8 @@ DEFINE_METHOD(MARSHAL, GET_DELEGATE_FOR_FUNCTION_POINTER, GetDelega DEFINE_METHOD(MARSHAL, ALLOC_CO_TASK_MEM, AllocCoTaskMem, SM_Int_RetIntPtr) DEFINE_FIELD(MARSHAL, SYSTEM_MAX_DBCS_CHAR_SIZE, SystemMaxDBCSCharSize) +DEFINE_CLASS(NATIVELIBRARY, Interop, NativeLibrary) +DEFINE_METHOD(NATIVELIBRARY, 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 e46e78a8ff47..1af7157f0761 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -57,6 +57,7 @@ add_subdirectory(MarshalAPI/FunctionPointer) add_subdirectory(MarshalAPI/IUnknown) add_subdirectory(NativeLibrary) add_subdirectory(NativeLibraryResolveEvent) +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..4eb8accb34fb --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveCallBack/CallBackTests.cs @@ -0,0 +1,86 @@ +// 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; + +[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] +public class CallBackTests +{ + public static int Main() + { + try + { + Assembly assembly = Assembly.GetExecutingAssembly(); + + DllImportResolver resolver = + (string libraryName, Assembly asm, DllImportSearchPath? dllImportSearchPath) => + { + if (!dllImportSearchPath.HasValue || dllImportSearchPath.Value != DllImportSearchPath.System32) + { + Console.WriteLine($"Unexpected dllImportSearchPath: {dllImportSearchPath.ToString()}"); + throw new ArgumentException(); + } + + return NativeLibrary.Load("ResolveLib", asm, dllImportSearchPath); + }; + + DllImportResolver anotherResolver = + (string libraryName, Assembly asm, DllImportSearchPath? dllImportSearchPath) => + IntPtr.Zero; + + try + { + NativeLibrary.SetDllImportResolver(null, resolver); + + Console.WriteLine("Expected exception not thrown"); + return 101; + } + catch (ArgumentNullException e) { } + + try + { + NativeLibrary.SetDllImportResolver(assembly, null); + + Console.WriteLine("Expected exception not thrown"); + return 102; + } + catch (ArgumentNullException e) { } + + // Set a resolver callback + 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.ToString()} {e.Message}"); + return 105; + } + + return 100; + } + + [DllImport("NativeLib")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + 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..d899e8ded7c9 --- /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..597b549a9976 --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveCallBack/ResolveLib.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 +#include + +extern "C" DLL_EXPORT int NativeSum(int a, int b) +{ + return a + b; +}