diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index c12d6c854ac0c0..440163552ef3d4 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -222,7 +222,6 @@ - diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreCLR.cs deleted file mode 100644 index f407b366021f89..00000000000000 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreCLR.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace System.Runtime.InteropServices -{ - public static partial class NativeLibrary - { - internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError) - { - RuntimeAssembly rtAsm = (RuntimeAssembly)assembly; - return LoadByName(libraryName, - new QCallAssembly(ref rtAsm), - searchPath.HasValue, - (uint)searchPath.GetValueOrDefault(), - throwOnError); - } - - /// External functions that implement the NativeLibrary interface - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "NativeLibrary_LoadFromPath", StringMarshalling = StringMarshalling.Utf16)] - internal static partial IntPtr LoadFromPath(string libraryName, [MarshalAs(UnmanagedType.Bool)] bool throwOnError); - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "NativeLibrary_LoadByName", StringMarshalling = StringMarshalling.Utf16)] - internal static partial IntPtr LoadByName(string libraryName, QCallAssembly callingAssembly, - [MarshalAs(UnmanagedType.Bool)] bool hasDllImportSearchPathFlag, uint dllImportSearchPathFlag, - [MarshalAs(UnmanagedType.Bool)] bool throwOnError); - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "NativeLibrary_FreeLib")] - internal static partial void FreeLib(IntPtr handle); - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "NativeLibrary_GetSymbol", StringMarshalling = StringMarshalling.Utf16)] - internal static partial IntPtr GetSymbol(IntPtr handle, string symbolName, [MarshalAs(UnmanagedType.Bool)] bool throwOnError); - } -} diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index 0fed12722a1139..abd530f5836d37 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -164,8 +164,6 @@ BEGIN IDS_EE_NDIRECT_LOADLIB_MAC "Unable to load shared library '%1' or one of its dependencies. In order to help diagnose loading problems, consider setting the DYLD_PRINT_LIBRARIES environment variable: %2" IDS_EE_NDIRECT_GETPROCADDRESS_WIN "Unable to find an entry point named '%2' in DLL '%1'." IDS_EE_NDIRECT_GETPROCADDRESS_UNIX "Unable to find an entry point named '%2' in shared library '%1'." - IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL "Unable to find an entry point named '%1' in DLL." - IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO "Unable to find an entry point named '%1' in shared library." IDS_EE_NDIRECT_GETPROCADDRESS_NONAME "A library name must be specified in a DllImport attribute applied to non-IJW methods." IDS_EE_NDIRECT_DISABLEDMARSHAL_SETLASTERROR "Setting SetLastError to 'true' is not supported when runtime marshalling is disabled." IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID "The LCIDConversionAttribute is not supported when runtime marshalling is disabled." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index f7ae1dea4a6259..f3621378343c9a 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -514,8 +514,6 @@ #define IDS_EE_CANNOT_SET_INITONLY_STATIC_FIELD 0x2643 -#define IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL 0x2644 -#define IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO 0x2645 #define IDS_EE_BADMARSHAL_STRING_OUT 0x2646 #define IDS_EE_BADMARSHAL_COPYCTORRESTRICTION 0x2647 #define IDS_EE_BADMARSHAL_DELEGATE_TLB_INTERFACE 0x2649 diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 6dd8b1dbe9fa54..76d3de6266ab27 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -202,7 +202,6 @@ - @@ -252,7 +251,6 @@ - System\Runtime\InteropServices\BuiltInVariantExtensions.cs @@ -282,9 +280,6 @@ Interop\Windows\OleAut32\Interop.VariantClear.cs - - Interop\Windows\Kernel32\Interop.DynamicLoad.cs - @@ -293,7 +288,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.cs deleted file mode 100644 index db2174deef1dc2..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Reflection; - -using LibraryNameVariation = System.Runtime.Loader.LibraryNameVariation; - -namespace System.Runtime.InteropServices -{ - public static partial class NativeLibrary - { - // Not a public API. We expose this so that it's possible to bypass the codepath that tries to read search path - // from custom attributes. - internal static bool TryLoad(string libraryName, Assembly assembly, DllImportSearchPath searchPath, out IntPtr handle) - { - handle = LoadLibraryByName(libraryName, - assembly, - userSpecifiedSearchFlags: true, - searchPath, - throwOnError: false); - return handle != IntPtr.Zero; - } - - internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError) - { - // 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 userSpecifiedSearchFlags = searchPath.HasValue; - if (!userSpecifiedSearchFlags) - { - searchPath = GetDllImportSearchPath(assembly, out userSpecifiedSearchFlags); - } - return LoadLibraryByName(libraryName, assembly, userSpecifiedSearchFlags, searchPath!.Value, throwOnError); - } - - private static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, bool userSpecifiedSearchFlags, DllImportSearchPath searchPath, bool throwOnError) - { - int searchPathFlags = (int)(searchPath & ~DllImportSearchPath.AssemblyDirectory); - bool searchAssemblyDirectory = (searchPath & DllImportSearchPath.AssemblyDirectory) != 0; - - LoadLibErrorTracker errorTracker = default; - IntPtr ret = LoadBySearch(assembly, userSpecifiedSearchFlags, searchAssemblyDirectory, searchPathFlags, ref errorTracker, libraryName); - if (throwOnError && ret == IntPtr.Zero) - { - errorTracker.Throw(libraryName); - } - - return ret; - } - - private static DllImportSearchPath GetDllImportSearchPath(Assembly callingAssembly, out bool userSpecifiedSearchFlags) - { - foreach (CustomAttributeData cad in callingAssembly.CustomAttributes) - { - if (cad.AttributeType == typeof(DefaultDllImportSearchPathsAttribute)) - { - userSpecifiedSearchFlags = true; - return (DllImportSearchPath)cad.ConstructorArguments[0].Value!; - } - } - - userSpecifiedSearchFlags = false; - return DllImportSearchPath.AssemblyDirectory; - } - - internal static IntPtr LoadBySearch(Assembly callingAssembly, bool userSpecifiedSearchFlags, bool searchAssemblyDirectory, int dllImportSearchPathFlags, ref LoadLibErrorTracker errorTracker, string libraryName) - { - IntPtr ret; - - int loadWithAlteredPathFlags = LoadWithAlteredSearchPathFlag; - const int loadLibrarySearchFlags = (int)DllImportSearchPath.UseDllDirectoryForDependencies - | (int)DllImportSearchPath.ApplicationDirectory - | (int)DllImportSearchPath.UserDirectories - | (int)DllImportSearchPath.System32 - | (int)DllImportSearchPath.SafeDirectories; - bool libNameIsRelativePath = !Path.IsPathFullyQualified(libraryName); - - // P/Invokes are often declared with variations on the actual library name. - // For example, it's common to leave off the extension/suffix of the library - // even if it has one, or to leave off a prefix like "lib" even if it has one - // (both of these are typically done to smooth over cross-platform differences). - // We try to dlopen with such variations on the original. - foreach (LibraryNameVariation libraryNameVariation in LibraryNameVariation.DetermineLibraryNameVariations(libraryName, libNameIsRelativePath)) - { - string currLibNameVariation = libraryNameVariation.Prefix + libraryName + libraryNameVariation.Suffix; - - if (!libNameIsRelativePath) - { - // LOAD_WITH_ALTERED_SEARCH_PATH is incompatible with LOAD_LIBRARY_SEARCH flags. Remove those flags if they are set. - int flags = loadWithAlteredPathFlags | (dllImportSearchPathFlags & ~loadLibrarySearchFlags); - ret = LoadLibraryHelper(currLibNameVariation, flags, ref errorTracker); - if (ret != IntPtr.Zero) - { - return ret; - } - } - else if ((callingAssembly != null) && searchAssemblyDirectory) - { - // LOAD_WITH_ALTERED_SEARCH_PATH is incompatible with LOAD_LIBRARY_SEARCH flags. Remove those flags if they are set. - int flags = loadWithAlteredPathFlags | (dllImportSearchPathFlags & ~loadLibrarySearchFlags); - - // Try to load the module alongside the assembly where the PInvoke was declared. - // For PInvokes where the DllImportSearchPath.AssemblyDirectory is specified, look next to the application. - ret = LoadLibraryHelper(Path.Combine(AppContext.BaseDirectory, currLibNameVariation), flags, ref errorTracker); - if (ret != IntPtr.Zero) - { - return ret; - } - } - - // Internally, search path flags and whether or not to search the assembly directory are - // tracked separately. However, on the API level, DllImportSearchPath represents them both. - // When unspecified, the default is to search the assembly directory and all OS defaults, - // which maps to searchAssemblyDirectory being true and dllImportSearchPathFlags being 0. - // When a user specifies DllImportSearchPath.AssemblyDirectory, searchAssemblyDirectory is - // true, dllImportSearchPathFlags is 0, and the desired logic is to only search the assembly - // directory (handled above), so we avoid doing any additional load search in that case. - if (!userSpecifiedSearchFlags || !searchAssemblyDirectory || dllImportSearchPathFlags != 0) - { - ret = LoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, ref errorTracker); - if (ret != IntPtr.Zero) - { - return ret; - } - } - } - - return IntPtr.Zero; - } - - private static IntPtr LoadFromPath(string libraryName, bool throwOnError) - { - LoadLibErrorTracker errorTracker = default; - IntPtr ret = LoadLibraryHelper(libraryName, LoadWithAlteredSearchPathFlag, ref errorTracker); - if (throwOnError && ret == IntPtr.Zero) - { - errorTracker.Throw(libraryName); - } - - return ret; - } - - private static unsafe IntPtr GetSymbol(IntPtr handle, string symbolName, bool throwOnError) - { - IntPtr ret = GetSymbolOrNull(handle, symbolName); - if (throwOnError && ret == IntPtr.Zero) - throw new EntryPointNotFoundException(SR.Format(SR.Arg_EntryPointNotFoundExceptionParameterizedNoLibrary, symbolName)); - - return ret; - } - } -} diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index f574bb1f14eefc..5fbcb4ac6da73a 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -354,7 +354,6 @@ set(VM_SOURCES_WKS multicorejitplayer.cpp # Condition="'$(FeatureMulticoreJIT)' == 'true' nativeeventsource.cpp nativelibrary.cpp - nativelibrarynative.cpp olevariant.cpp pendingload.cpp pinvokeoverride.cpp diff --git a/src/coreclr/vm/corelib.cpp b/src/coreclr/vm/corelib.cpp index 9e89019b200780..676c266d3416a9 100644 --- a/src/coreclr/vm/corelib.cpp +++ b/src/coreclr/vm/corelib.cpp @@ -23,7 +23,6 @@ #include "clrconfignative.h" #include "commodule.h" #include "marshalnative.h" -#include "nativelibrarynative.h" #include "system.h" #include "comutilnative.h" #include "comsynchronizable.h" diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index 4f1c5afdd4bc1b..e625ae15369547 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -37,6 +37,9 @@ #endif // !TARGET_UNIX #include "nativelibrary.h" +#ifdef TARGET_UNIX +#include "dlfcn.h" +#endif #ifndef DACCESS_COMPILE @@ -644,7 +647,7 @@ HRESULT CorHost2::CreateAppDomainWithManager( // Preload the libSystem.Native.so/dylib to detect possible problems with loading it early EX_TRY { - NativeLibrary::LoadLibraryByName(W("libSystem.Native"), SystemDomain::SystemAssembly(), FALSE, 0, TRUE); + NativeLibrary::LoadFromAssemblyDirectory(W("libSystem.Native") PAL_SHLIB_SUFFIX_W, SystemDomain::SystemAssembly()); } EX_HOOK { diff --git a/src/coreclr/vm/nativelibrary.cpp b/src/coreclr/vm/nativelibrary.cpp index dec0e92964cd8f..3fe2b1f8c762d9 100644 --- a/src/coreclr/vm/nativelibrary.cpp +++ b/src/coreclr/vm/nativelibrary.cpp @@ -242,70 +242,6 @@ namespace } } -// static -NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(libraryPath)); - } - CONTRACTL_END; - - LoadLibErrorTracker errorTracker; - const NATIVE_LIBRARY_HANDLE hmod = - LocalLoadLibraryHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker); - - if (throwOnError && (hmod == nullptr)) - { - SString libraryPathSString(libraryPath); - errorTracker.Throw(libraryPathSString); - } - return hmod; -} - -// static -void NativeLibrary::FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle) -{ - STANDARD_VM_CONTRACT; - _ASSERTE(handle != NULL); - -#ifndef TARGET_UNIX - BOOL retVal = FreeLibrary(handle); -#else // !TARGET_UNIX - BOOL retVal = PAL_FreeLibraryDirect(handle); -#endif // !TARGET_UNIX - - if (retVal == 0) - COMPlusThrow(kInvalidOperationException, W("Arg_InvalidOperationException")); -} - -//static -INT_PTR NativeLibrary::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(handle)); - PRECONDITION(CheckPointer(symbolName)); - } - CONTRACTL_END; - - MAKE_UTF8PTR_FROMWIDE(lpstr, symbolName); - -#ifndef TARGET_UNIX - INT_PTR address = reinterpret_cast(GetProcAddress((HMODULE)handle, lpstr)); - if ((address == 0) && throwOnError) - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL, symbolName); -#else // !TARGET_UNIX - INT_PTR address = reinterpret_cast(PAL_GetProcAddressDirect(handle, lpstr)); - if ((address == 0) && throwOnError) - COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO, symbolName); -#endif // !TARGET_UNIX - - return address; -} - namespace { #ifndef TARGET_UNIX @@ -771,9 +707,7 @@ namespace } // static -NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly, - BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags, - BOOL throwOnError) +NATIVE_LIBRARY_HANDLE NativeLibrary::LoadFromAssemblyDirectory(LPCWSTR libraryName, Assembly *callingAssembly) { CONTRACTL { @@ -785,43 +719,13 @@ NATIVE_LIBRARY_HANDLE NativeLibrary::LoadLibraryByName(LPCWSTR libraryName, Asse NATIVE_LIBRARY_HANDLE hmod = nullptr; - // Resolve using the AssemblyLoadContext.LoadUnmanagedDll implementation - hmod = LoadNativeLibraryViaAssemblyLoadContext(callingAssembly, libraryName); - if (hmod != nullptr) - return hmod; - - // Check if a default dllImportSearchPathFlags was passed in. If so, use that value. - // Otherwise, check if the assembly has the DefaultDllImportSearchPathsAttribute attribute. - // If so, use that value. - BOOL searchAssemblyDirectory; - DWORD dllImportSearchPathFlags; - if (hasDllImportSearchFlags) - { - dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; - searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY; - - } - else - { - hasDllImportSearchFlags = GetDllImportSearchPathFlags(callingAssembly->GetModule(), - &dllImportSearchPathFlags, &searchAssemblyDirectory); - } - LoadLibErrorTracker errorTracker; - hmod = LoadNativeLibraryBySearch(callingAssembly, hasDllImportSearchFlags, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName); - if (hmod != nullptr) - return hmod; - - // Resolve using the AssemblyLoadContext.ResolvingUnmanagedDll event - hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(callingAssembly, libraryName); + hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, libraryName, 0, &errorTracker); if (hmod != nullptr) return hmod; - if (throwOnError) - { - SString libraryPathSString(libraryName); - errorTracker.Throw(libraryPathSString); - } + SString libraryPathSString(libraryName); + errorTracker.Throw(libraryPathSString); return hmod; } diff --git a/src/coreclr/vm/nativelibrary.h b/src/coreclr/vm/nativelibrary.h index 0745a5a3e41b03..61ea651daec9ce 100644 --- a/src/coreclr/vm/nativelibrary.h +++ b/src/coreclr/vm/nativelibrary.h @@ -9,13 +9,7 @@ class NativeLibrary { public: - static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError); - static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly, - BOOL hasDllImportSearchPathFlags, DWORD dllImportSearchPathFlags, - BOOL throwOnError); - static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle); - static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError); - + static NATIVE_LIBRARY_HANDLE LoadFromAssemblyDirectory(LPCWSTR libraryName, Assembly *callingAssembly); static NATIVE_LIBRARY_HANDLE LoadLibraryFromMethodDesc(PInvokeMethodDesc *pMD); }; diff --git a/src/coreclr/vm/nativelibrarynative.cpp b/src/coreclr/vm/nativelibrarynative.cpp deleted file mode 100644 index 780871eff3f725..00000000000000 --- a/src/coreclr/vm/nativelibrarynative.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// -// File: NativeLibraryNative.cpp -// - -#include "common.h" -#include "nativelibrary.h" -#include "nativelibrarynative.h" - -// static -extern "C" INT_PTR QCALLTYPE NativeLibrary_LoadFromPath(LPCWSTR path, BOOL throwOnError) -{ - QCALL_CONTRACT; - - NATIVE_LIBRARY_HANDLE handle = nullptr; - - BEGIN_QCALL; - - handle = NativeLibrary::LoadLibraryFromPath(path, throwOnError); - - END_QCALL; - - return reinterpret_cast(handle); -} - -// static -extern "C" INT_PTR QCALLTYPE NativeLibrary_LoadByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly, - BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, - BOOL throwOnError) -{ - QCALL_CONTRACT; - - NATIVE_LIBRARY_HANDLE handle = nullptr; - - BEGIN_QCALL; - - handle = NativeLibrary::LoadLibraryByName(name, callingAssembly, hasDllImportSearchPathFlag, dllImportSearchPathFlag, throwOnError); - - END_QCALL; - - return reinterpret_cast(handle); -} - -// static -extern "C" void QCALLTYPE NativeLibrary_FreeLib(INT_PTR handle) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - NativeLibrary::FreeNativeLibrary((NATIVE_LIBRARY_HANDLE) handle); - - END_QCALL; -} - -//static -extern "C" INT_PTR QCALLTYPE NativeLibrary_GetSymbol(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError) -{ - QCALL_CONTRACT; - - INT_PTR address = 0; - - BEGIN_QCALL; - - address = NativeLibrary::GetNativeLibraryExport((NATIVE_LIBRARY_HANDLE)handle, symbolName, throwOnError); - - END_QCALL; - - return address; -} diff --git a/src/coreclr/vm/nativelibrarynative.h b/src/coreclr/vm/nativelibrarynative.h deleted file mode 100644 index 6ace9ae0be58b3..00000000000000 --- a/src/coreclr/vm/nativelibrarynative.h +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// -// File: NativeLibraryNative.h -// -// -// QCall's for the NativeLibrary class -// - -#ifndef __NATIVELIBRARYNATIVE_H__ -#define __NATIVELIBRARYNATIVE_H__ - -extern "C" INT_PTR QCALLTYPE NativeLibrary_LoadFromPath(LPCWSTR path, BOOL throwOnError); -extern "C" INT_PTR QCALLTYPE NativeLibrary_LoadByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly, - BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, - BOOL throwOnError); -extern "C" void QCALLTYPE NativeLibrary_FreeLib(INT_PTR handle); -extern "C" INT_PTR QCALLTYPE NativeLibrary_GetSymbol(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError); - -#endif // __NATIVELIBRARYNATIVE_H__ diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 11e57f6663e15c..f801ab33053ef9 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -18,7 +18,6 @@ #include "clrconfignative.h" #include "commodule.h" #include "marshalnative.h" -#include "nativelibrarynative.h" #include "system.h" #include "comutilnative.h" #include "comsynchronizable.h" @@ -393,10 +392,6 @@ static const Entry s_QCall[] = DllImportEntry(MngdSafeArrayMarshaler_ClearNative) DllImportEntry(Variant_ConvertValueTypeToRecord) #endif // FEATURE_COMINTEROP - DllImportEntry(NativeLibrary_LoadFromPath) - DllImportEntry(NativeLibrary_LoadByName) - DllImportEntry(NativeLibrary_FreeLib) - DllImportEntry(NativeLibrary_GetSymbol) DllImportEntry(GetTypeLoadExceptionMessage) DllImportEntry(GetFileLoadExceptionMessage) DllImportEntry(FileLoadException_GetMessageForHR) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs index c27e92419943dd..416e7b84c4be2d 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetThreadErrorMode.cs @@ -15,6 +15,5 @@ internal static partial bool SetThreadErrorMode( out uint lpOldMode); internal const int SEM_FAILCRITICALERRORS = 0x00000001; - internal const int SEM_NOOPENFILEERRORBOX = 0x00008000; } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 3383f70a0b4e64..77248567b357b9 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1825,6 +1825,9 @@ Common\Interop\Windows\Kernel32\Interop.DeviceIoControl.cs + + Common\Interop\Windows\Kernel32\Interop.DynamicLoad.cs + Common\Interop\Windows\Kernel32\Interop.ExpandEnvironmentStrings.cs @@ -2274,6 +2277,7 @@ + @@ -2617,6 +2621,7 @@ + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Unix.cs similarity index 93% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs rename to src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Unix.cs index 6ef45a24750955..d9e460692dd316 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Unix.cs @@ -15,7 +15,7 @@ private static IntPtr LoadLibraryHelper(string libraryName, int _ /*flags*/, ref if (ret == IntPtr.Zero) { string? message = Marshal.PtrToStringUTF8(Interop.Sys.GetLoadLibraryError()); - errorTracker.TrackErrorMessage(message); + errorTracker.TrackErrorMessage(message ?? string.Empty); } return ret; @@ -46,7 +46,7 @@ public void Throw(string libraryName) #endif } - public void TrackErrorMessage(string? message) + public void TrackErrorMessage(string message) { _errorMessage ??= Environment.NewLine; if (!_errorMessage.Contains(message)) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Windows.cs similarity index 77% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Windows.cs rename to src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Windows.cs index bac99a01ed35df..73ab588fdd9128 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Windows.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.IO; namespace System.Runtime.InteropServices { @@ -13,37 +14,32 @@ private static IntPtr LoadLibraryHelper(string libraryName, int flags, ref LoadL { IntPtr hmod; - // Disable the OS dialogs when failing to load. This matches CoreCLR. - uint prev; - bool set = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS | Interop.Kernel32.SEM_NOOPENFILEERRORBOX, out prev); - if (((uint)flags & 0xFFFFFF00) != 0) + // Disable the OS dialogs when failing to load. + using (DisableMediaInsertionPrompt.Create()) { - hmod = Interop.Kernel32.LoadLibraryEx(libraryName, IntPtr.Zero, (int)((uint)flags & 0xFFFFFF00)); - if (hmod != IntPtr.Zero) + if (((uint)flags & 0xFFFFFF00) != 0) { - goto exit; + hmod = Interop.Kernel32.LoadLibraryEx(libraryName, IntPtr.Zero, (int)((uint)flags & 0xFFFFFF00)); + if (hmod != IntPtr.Zero) + { + return hmod; + } + + int lastError = Marshal.GetLastPInvokeError(); + if (lastError != Interop.Errors.ERROR_INVALID_PARAMETER) + { + errorTracker.TrackErrorCode(lastError); + return hmod; + } } - int lastError = Marshal.GetLastPInvokeError(); - if (lastError != Interop.Errors.ERROR_INVALID_PARAMETER) + hmod = Interop.Kernel32.LoadLibraryEx(libraryName, IntPtr.Zero, flags & 0xFF); + if (hmod == IntPtr.Zero) { - errorTracker.TrackErrorCode(lastError); - goto exit; + errorTracker.TrackErrorCode(Marshal.GetLastPInvokeError()); } } - hmod = Interop.Kernel32.LoadLibraryEx(libraryName, IntPtr.Zero, flags & 0xFF); - if (hmod == IntPtr.Zero) - { - errorTracker.TrackErrorCode(Marshal.GetLastPInvokeError()); - } - - exit: - if (set) - { - Interop.Kernel32.SetThreadErrorMode(prev, out _); - } - return hmod; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs index 41321edd86325c..d1e09384e0f0bd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; +using System.IO; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.Loader; using System.Threading; namespace System.Runtime.InteropServices @@ -131,6 +133,20 @@ public static bool TryLoad(string libraryName, Assembly assembly, DllImportSearc return handle != IntPtr.Zero; } +#if !MONO + // Not a public API. We expose this so that it's possible to bypass the codepath that tries to read search path + // from custom attributes. + internal static bool TryLoad(string libraryName, Assembly assembly, DllImportSearchPath searchPath, out IntPtr handle) + { + handle = LoadLibraryByName(libraryName, + assembly, + userSpecifiedSearchFlags: true, + searchPath, + throwOnError: false); + return handle != IntPtr.Zero; + } +#endif + /// /// Free a loaded library /// Given a library handle, free it. @@ -264,5 +280,181 @@ public static IntPtr GetMainProgramHandle() } return result; } + +#if !MONO + internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError) + { +#if !NATIVEAOT + // Resolve using the AssemblyLoadContext.LoadUnmanagedDll implementation + IntPtr mod = LoadNativeLibraryViaAssemblyLoadContext(assembly, libraryName); + if (mod != IntPtr.Zero) + return mod; +#endif + + // 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 userSpecifiedSearchFlags = searchPath.HasValue; + if (!userSpecifiedSearchFlags) + { + searchPath = GetDllImportSearchPath(assembly, out userSpecifiedSearchFlags); + } + return LoadLibraryByName(libraryName, assembly, userSpecifiedSearchFlags, searchPath!.Value, throwOnError); + } + + private static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, bool userSpecifiedSearchFlags, DllImportSearchPath searchPath, bool throwOnError) + { + int searchPathFlags = (int)(searchPath & ~DllImportSearchPath.AssemblyDirectory); + bool searchAssemblyDirectory = (searchPath & DllImportSearchPath.AssemblyDirectory) != 0; + + LoadLibErrorTracker errorTracker = default; + IntPtr ret = LoadBySearch(assembly, userSpecifiedSearchFlags, searchAssemblyDirectory, searchPathFlags, ref errorTracker, libraryName); + + // Resolve using the AssemblyLoadContext.ResolvingUnmanagedDll event + if (ret == IntPtr.Zero) + { + ret = LoadNativeLibraryViaAssemblyLoadContextEvent(assembly, libraryName); + } + + if (throwOnError && ret == IntPtr.Zero) + { + errorTracker.Throw(libraryName); + } + + return ret; + } + +#if !NATIVEAOT + private static IntPtr LoadNativeLibraryViaAssemblyLoadContext(Assembly callingAssembly, string libraryName) + { +#if TARGET_WINDOWS + // This is replicating quick check from the OS implementation of api sets. + if (libraryName.StartsWithOrdinalIgnoreCase("api-") || + libraryName.StartsWithOrdinalIgnoreCase("ext-")) + { + // Prevent Overriding of Windows API sets. + return IntPtr.Zero; + } +#endif + AssemblyLoadContext? alc = AssemblyLoadContext.GetLoadContext(callingAssembly); + if (alc is null || alc == AssemblyLoadContext.Default) + { + // For assemblies bound via default binder, we should use the standard mechanism to make the pinvoke call. + return IntPtr.Zero; + } + + // Call System.Runtime.Loader.AssemblyLoadContext.LoadUnmanagedDll to give + // The custom assembly context a chance to load the unmanaged dll. + return alc.InvokeLoadUnmanagedDll(libraryName); + } +#endif + + private static IntPtr LoadNativeLibraryViaAssemblyLoadContextEvent(Assembly callingAssembly, string libraryName) + { + AssemblyLoadContext? alc = AssemblyLoadContext.GetLoadContext(callingAssembly); + return alc?.GetResolvedUnmanagedDll(callingAssembly, libraryName) ?? IntPtr.Zero; + } + + private static DllImportSearchPath GetDllImportSearchPath(Assembly callingAssembly, out bool userSpecifiedSearchFlags) + { + foreach (CustomAttributeData cad in callingAssembly.CustomAttributes) + { + if (cad.AttributeType == typeof(DefaultDllImportSearchPathsAttribute)) + { + userSpecifiedSearchFlags = true; + return (DllImportSearchPath)cad.ConstructorArguments[0].Value!; + } + } + + userSpecifiedSearchFlags = false; + return DllImportSearchPath.AssemblyDirectory; + } + + internal static IntPtr LoadBySearch(Assembly callingAssembly, bool userSpecifiedSearchFlags, bool searchAssemblyDirectory, int dllImportSearchPathFlags, ref LoadLibErrorTracker errorTracker, string libraryName) + { + IntPtr ret; + + int loadWithAlteredPathFlags = LoadWithAlteredSearchPathFlag; + const int loadLibrarySearchFlags = (int)DllImportSearchPath.UseDllDirectoryForDependencies + | (int)DllImportSearchPath.ApplicationDirectory + | (int)DllImportSearchPath.UserDirectories + | (int)DllImportSearchPath.System32 + | (int)DllImportSearchPath.SafeDirectories; + bool libNameIsRelativePath = !Path.IsPathFullyQualified(libraryName); + + // P/Invokes are often declared with variations on the actual library name. + // For example, it's common to leave off the extension/suffix of the library + // even if it has one, or to leave off a prefix like "lib" even if it has one + // (both of these are typically done to smooth over cross-platform differences). + // We try to dlopen with such variations on the original. + foreach (LibraryNameVariation libraryNameVariation in LibraryNameVariation.DetermineLibraryNameVariations(libraryName, libNameIsRelativePath)) + { + string currLibNameVariation = libraryNameVariation.Prefix + libraryName + libraryNameVariation.Suffix; + + if (!libNameIsRelativePath) + { + // LOAD_WITH_ALTERED_SEARCH_PATH is incompatible with LOAD_LIBRARY_SEARCH flags. Remove those flags if they are set. + int flags = loadWithAlteredPathFlags | (dllImportSearchPathFlags & ~loadLibrarySearchFlags); + ret = LoadLibraryHelper(currLibNameVariation, flags, ref errorTracker); + if (ret != IntPtr.Zero) + { + return ret; + } + } + else if ((callingAssembly != null) && searchAssemblyDirectory) + { + // LOAD_WITH_ALTERED_SEARCH_PATH is incompatible with LOAD_LIBRARY_SEARCH flags. Remove those flags if they are set. + int flags = loadWithAlteredPathFlags | (dllImportSearchPathFlags & ~loadLibrarySearchFlags); + + // Try to load the module alongside the assembly where the PInvoke was declared. + // For PInvokes where the DllImportSearchPath.AssemblyDirectory is specified, look next to the application. + ret = LoadLibraryHelper(Path.Combine(AppContext.BaseDirectory, currLibNameVariation), flags, ref errorTracker); + if (ret != IntPtr.Zero) + { + return ret; + } + } + + // Internally, search path flags and whether or not to search the assembly directory are + // tracked separately. However, on the API level, DllImportSearchPath represents them both. + // When unspecified, the default is to search the assembly directory and all OS defaults, + // which maps to searchAssemblyDirectory being true and dllImportSearchPathFlags being 0. + // When a user specifies DllImportSearchPath.AssemblyDirectory, searchAssemblyDirectory is + // true, dllImportSearchPathFlags is 0, and the desired logic is to only search the assembly + // directory (handled above), so we avoid doing any additional load search in that case. + if (!userSpecifiedSearchFlags || !searchAssemblyDirectory || dllImportSearchPathFlags != 0) + { + ret = LoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, ref errorTracker); + if (ret != IntPtr.Zero) + { + return ret; + } + } + } + + return IntPtr.Zero; + } + + private static IntPtr LoadFromPath(string libraryName, bool throwOnError) + { + LoadLibErrorTracker errorTracker = default; + IntPtr ret = LoadLibraryHelper(libraryName, LoadWithAlteredSearchPathFlag, ref errorTracker); + if (throwOnError && ret == IntPtr.Zero) + { + errorTracker.Throw(libraryName); + } + + return ret; + } + + private static unsafe IntPtr GetSymbol(IntPtr handle, string symbolName, bool throwOnError) + { + IntPtr ret = GetSymbolOrNull(handle, symbolName); + if (throwOnError && ret == IntPtr.Zero) + throw new EntryPointNotFoundException(SR.Format(SR.Arg_EntryPointNotFoundExceptionParameterizedNoLibrary, symbolName)); + + return ret; + } +#endif } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs index 7816d79a680d6d..79669280df61c7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -789,6 +789,11 @@ internal static void InvokeAssemblyLoadEvent(Assembly assembly) return asm; } + internal IntPtr InvokeLoadUnmanagedDll(string unmanagedDllName) + { + return LoadUnmanagedDll(unmanagedDllName); + } + internal IntPtr GetResolvedUnmanagedDll(Assembly assembly, string unmanagedDllName) { // Loop through the event subscribers and return the first non-null native library handle