SString m_message;
}; // class LoadLibErrorTracker
-// Load the library directly. On Unix systems, don't register it yet with PAL.
-// * External callers like System.Runtime.InteropServices.NativeLibrary.Load() need the raw system handle
-// * Internal callers like LoadLibraryModule() can convert this handle to a HMODULE via PAL APIs on Unix
+// Load the library directly and return the raw system handle
static NATIVE_LIBRARY_HANDLE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker )
{
STANDARD_VM_CONTRACT;
return hmod;
}
-// static
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly,
- BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags,
- BOOL throwOnError)
-{
- CONTRACTL
- {
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(libraryName));
- PRECONDITION(CheckPointer(callingAssembly));
- }
- CONTRACTL_END;
-
- 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;
- DWORD dllImportSearchPathFlags;
-
- if (hasDllImportSearchFlags)
- {
- dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
- searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
-
- }
- else
- {
- GetDllImportSearchPathFlags(callingAssembly->GetManifestModule(),
- &dllImportSearchPathFlags, &searchAssemblyDirectory);
- }
-
- NATIVE_LIBRARY_HANDLE hmod =
- LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName);
-
- if (throwOnError && (hmod == nullptr))
- {
- SString libraryPathSString(libraryName);
- errorTracker.Throw(libraryPathSString);
- }
-
- return hmod;
-}
-
-// static
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, PCWSTR wszLibName)
-{
- STANDARD_VM_CONTRACT;
-
- BOOL searchAssemblyDirectory;
- DWORD dllImportSearchPathFlags;
-
- GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory);
-
- Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
- return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName);
-}
-
// static
void NDirect::FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle)
{
return address;
}
-#ifndef TARGET_UNIX
-BOOL IsWindowsAPISet(PCWSTR wszLibName)
+namespace
{
- STANDARD_VM_CONTRACT;
+#ifndef TARGET_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;
-}
+ // 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 // !TARGET_UNIX
-// static
-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
+ NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaAssemblyLoadContext(Assembly * pAssembly, PCWSTR wszLibName)
+ {
+ STANDARD_VM_CONTRACT;
#ifndef TARGET_UNIX
- if (IsWindowsAPISet(wszLibName))
- {
- // Prevent Overriding of Windows API sets.
- return NULL;
- }
+ if (IsWindowsAPISet(wszLibName))
+ {
+ // Prevent Overriding of Windows API sets.
+ return NULL;
+ }
#endif // !TARGET_UNIX
- NATIVE_LIBRARY_HANDLE hmod = NULL;
- AppDomain* pDomain = GetAppDomain();
- CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
- Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
+ NATIVE_LIBRARY_HANDLE hmod = NULL;
+ AppDomain* pDomain = GetAppDomain();
+ CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
- PEFile *pManifestFile = pAssembly->GetManifestFile();
- PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext();
+ PEFile *pManifestFile = pAssembly->GetManifestFile();
+ PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext();
- //Step 0: Check if the assembly was bound using TPA.
- // The Binding Context can be null or an overridden TPA context
- if (pBindingContext == NULL)
- {
- // If we do not have any binder associated, then return to the default resolution mechanism.
- return NULL;
- }
+ //Step 0: Check if the assembly was bound using TPA.
+ // The Binding Context can be null or an overridden TPA context
+ if (pBindingContext == NULL)
+ {
+ // If we do not have any binder associated, then return to the default resolution mechanism.
+ return NULL;
+ }
- UINT_PTR assemblyBinderID = 0;
- IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
+ UINT_PTR assemblyBinderID = 0;
+ IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
- ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
+ ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
- // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
- if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
- {
- return NULL;
- }
+ // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
+ if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
+ {
+ return NULL;
+ }
#ifdef FEATURE_COMINTEROP
- CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
- if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
- {
- // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
- // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
- //
- // For this, we should use the standard mechanism to make pinvoke call as well.
- return NULL;
- }
+ CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
+ if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
+ {
+ // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
+ // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
+ //
+ // For this, we should use the standard mechanism to make pinvoke call as well.
+ return NULL;
+ }
#endif // FEATURE_COMINTEROP
- //Step 1: If the assembly was not bound using TPA,
- // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll to give
- // The custom assembly context a chance to load the unmanaged dll.
+ //Step 1: If the assembly was not bound using TPA,
+ // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll to give
+ // The custom assembly context a chance to load the unmanaged dll.
- GCX_COOP();
+ GCX_COOP();
- STRINGREF pUnmanagedDllName;
- pUnmanagedDllName = StringObject::NewString(wszLibName);
+ STRINGREF pUnmanagedDllName;
+ pUnmanagedDllName = StringObject::NewString(wszLibName);
- GCPROTECT_BEGIN(pUnmanagedDllName);
+ GCPROTECT_BEGIN(pUnmanagedDllName);
- // Get the pointer to the managed assembly load context
- INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
+ // Get the pointer to the managed assembly load context
+ INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
- // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll method.
- PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
- DECLARE_ARGHOLDER_ARRAY(args, 2);
- args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
- args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
+ // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll method.
+ PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
+ DECLARE_ARGHOLDER_ARRAY(args, 2);
+ args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
+ args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
- // Make the call
- CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args);
+ // Make the call
+ CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args);
- GCPROTECT_END();
+ GCPROTECT_END();
- return hmod;
-}
-
-// Return the AssemblyLoadContext for an assembly
-INT_PTR GetManagedAssemblyLoadContext(Assembly* pAssembly)
-{
- STANDARD_VM_CONTRACT;
+ return hmod;
+ }
- PTR_ICLRPrivBinder pBindingContext = pAssembly->GetManifestFile()->GetBindingContext();
- if (pBindingContext == NULL)
+ // Return the AssemblyLoadContext for an assembly
+ INT_PTR GetManagedAssemblyLoadContext(Assembly* pAssembly)
{
- // GetBindingContext() returns NULL for System.Private.CoreLib
- return NULL;
- }
+ 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));
+ UINT_PTR assemblyBinderID = 0;
+ IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
- AppDomain *pDomain = GetAppDomain();
- ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
+ AppDomain *pDomain = GetAppDomain();
+ ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
#ifdef FEATURE_COMINTEROP
- if (AreSameBinderInstance(pCurrentBinder, pDomain->GetWinRtBinder()))
- {
- // No ALC associated handle with WinRT Binders.
- return NULL;
- }
+ 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;
+ // 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();
- NATIVE_LIBRARY_HANDLE hmod = NULL;
- Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
- INT_PTR ptrManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(pAssembly);
+ return ptrManagedAssemblyLoadContext;
+ }
- if (ptrManagedAssemblyLoadContext == NULL)
+ NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaAssemblyLoadContextEvent(Assembly * pAssembly, PCWSTR wszLibName)
{
- return NULL;
- }
+ STANDARD_VM_CONTRACT;
- GCX_COOP();
+ INT_PTR ptrManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(pAssembly);
+ if (ptrManagedAssemblyLoadContext == NULL)
+ {
+ return NULL;
+ }
- struct {
- STRINGREF DllName;
- OBJECTREF AssemblyRef;
- } gc = { NULL, NULL };
+ NATIVE_LIBRARY_HANDLE hmod = NULL;
- GCPROTECT_BEGIN(gc);
+ GCX_COOP();
- gc.DllName = StringObject::NewString(wszLibName);
- gc.AssemblyRef = pAssembly->GetExposedObject();
+ struct {
+ STRINGREF DllName;
+ OBJECTREF AssemblyRef;
+ } gc = { NULL, NULL };
- // 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);
+ GCPROTECT_BEGIN(gc);
- // Make the call
- CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args);
+ gc.DllName = StringObject::NewString(wszLibName);
+ gc.AssemblyRef = pAssembly->GetExposedObject();
- GCPROTECT_END();
+ // 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);
- return hmod;
-}
+ // Make the call
+ CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args);
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallback(NDirectMethodDesc * pMD, LPCWSTR wszLibName)
-{
- STANDARD_VM_CONTRACT;
+ GCPROTECT_END();
- if (pMD->GetModule()->IsSystem())
- {
- // Don't attempt to callback on Corelib itself.
- // The LoadLibrary callback stub is managed code that requires CoreLib
- return NULL;
+ return hmod;
}
- 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;
+ NATIVE_LIBRARY_HANDLE LoadNativeLibraryViaDllImportResolver(NDirectMethodDesc * pMD, LPCWSTR wszLibName)
+ {
+ STANDARD_VM_CONTRACT;
- GCX_COOP();
+ if (pMD->GetModule()->IsSystem())
+ {
+ // Don't attempt to callback on Corelib itself.
+ // The LoadLibrary callback stub is managed code that requires CoreLib
+ return NULL;
+ }
- struct {
- STRINGREF libNameRef;
- OBJECTREF assemblyRef;
- } gc = { NULL, NULL };
+ DWORD dllImportSearchPathFlags;
+ BOOL searchAssemblyDirectory;
+ BOOL hasDllImportSearchPathFlags = GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory);
+ dllImportSearchPathFlags |= searchAssemblyDirectory ? DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY : 0;
- GCPROTECT_BEGIN(gc);
+ Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
+ NATIVE_LIBRARY_HANDLE handle = NULL;
- gc.libNameRef = StringObject::NewString(wszLibName);
- gc.assemblyRef = pAssembly->GetExposedObject();
+ GCX_COOP();
- PREPARE_NONVIRTUAL_CALLSITE(METHOD__NATIVELIBRARY__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);
+ struct {
+ STRINGREF libNameRef;
+ OBJECTREF assemblyRef;
+ } gc = { NULL, NULL };
- // Make the call
- CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args);
- GCPROTECT_END();
+ GCPROTECT_BEGIN(gc);
- return handle;
-}
+ gc.libNameRef = StringObject::NewString(wszLibName);
+ gc.assemblyRef = pAssembly->GetExposedObject();
-// 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)
-{
- STANDARD_VM_CONTRACT;
+ PREPARE_NONVIRTUAL_CALLSITE(METHOD__NATIVELIBRARY__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);
- NATIVE_LIBRARY_HANDLE hmod = NULL;
+ // Make the call
+ CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args);
+ GCPROTECT_END();
- SString path = pAssembly->GetManifestFile()->GetPath();
+ return handle;
+ }
- SString::Iterator lastPathSeparatorIter = path.End();
- if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter))
+ // Try to load the module alongside the assembly where the PInvoke was declared.
+ NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
{
- lastPathSeparatorIter++;
- path.Truncate(lastPathSeparatorIter);
+ STANDARD_VM_CONTRACT;
- path.Append(libName);
- hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
- }
+ NATIVE_LIBRARY_HANDLE hmod = NULL;
- return hmod;
-}
+ SString path = pAssembly->GetManifestFile()->GetPath();
-// Try to load the module from the native DLL search directories
-NATIVE_LIBRARY_HANDLE NDirect::LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
-{
- STANDARD_VM_CONTRACT;
+ SString::Iterator lastPathSeparatorIter = path.End();
+ if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter))
+ {
+ lastPathSeparatorIter++;
+ path.Truncate(lastPathSeparatorIter);
- NATIVE_LIBRARY_HANDLE hmod = NULL;
- AppDomain* pDomain = GetAppDomain();
+ path.Append(libName);
+ hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
+ }
+
+ return hmod;
+ }
- if (pDomain->HasNativeDllSearchDirectories())
+ // Try to load the module from the native DLL search directories
+ NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
{
- AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories();
- while (hmod == NULL && pathIter.Next())
+ STANDARD_VM_CONTRACT;
+
+ NATIVE_LIBRARY_HANDLE hmod = NULL;
+ AppDomain* pDomain = GetAppDomain();
+
+ if (pDomain->HasNativeDllSearchDirectories())
{
- SString qualifiedPath(*(pathIter.GetPath()));
- qualifiedPath.Append(libName);
- if (!Path::IsRelative(qualifiedPath))
+ AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories();
+ while (hmod == NULL && pathIter.Next())
{
- hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker);
+ SString qualifiedPath(*(pathIter.GetPath()));
+ qualifiedPath.Append(libName);
+ if (!Path::IsRelative(qualifiedPath))
+ {
+ hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker);
+ }
}
}
- }
- return hmod;
-}
+ return hmod;
+ }
#ifdef TARGET_UNIX
-static const int MaxVariationCount = 4;
-static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath)
-{
- // Supported lib name variations
- static auto NameFmt = W("%.0s%s%.0s");
- static auto PrefixNameFmt = W("%s%s%.0s");
- static auto NameSuffixFmt = W("%.0s%s%s");
- static auto PrefixNameSuffixFmt = W("%s%s%s");
+ const int MaxVariationCount = 4;
+ void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath)
+ {
+ // Supported lib name variations
+ static auto NameFmt = W("%.0s%s%.0s");
+ static auto PrefixNameFmt = W("%s%s%.0s");
+ static auto NameSuffixFmt = W("%.0s%s%s");
+ static auto PrefixNameSuffixFmt = W("%s%s%s");
- _ASSERTE(*numberOfVariations >= MaxVariationCount);
+ _ASSERTE(*numberOfVariations >= MaxVariationCount);
- int varCount = 0;
- if (!libNameIsRelativePath)
- {
- libNameVariations[varCount++] = NameFmt;
- }
- else
- {
- // We check if the suffix is contained in the name, because on Linux it is common to append
- // a version number to the library name (e.g. 'libicuuc.so.57').
- bool containsSuffix = false;
- SString::CIterator it = libName.Begin();
- if (libName.Find(it, PLATFORM_SHARED_LIB_SUFFIX_W))
+ int varCount = 0;
+ if (!libNameIsRelativePath)
{
- it += COUNTOF(PLATFORM_SHARED_LIB_SUFFIX_W);
- containsSuffix = it == libName.End() || *it == (WCHAR)'.';
+ libNameVariations[varCount++] = NameFmt;
}
+ else
+ {
+ // We check if the suffix is contained in the name, because on Linux it is common to append
+ // a version number to the library name (e.g. 'libicuuc.so.57').
+ bool containsSuffix = false;
+ SString::CIterator it = libName.Begin();
+ if (libName.Find(it, PLATFORM_SHARED_LIB_SUFFIX_W))
+ {
+ it += COUNTOF(PLATFORM_SHARED_LIB_SUFFIX_W);
+ containsSuffix = it == libName.End() || *it == (WCHAR)'.';
+ }
- // If the path contains a path delimiter, we don't add a prefix
- it = libName.Begin();
- bool containsDelim = libName.Find(it, DIRECTORY_SEPARATOR_STR_W);
+ // If the path contains a path delimiter, we don't add a prefix
+ it = libName.Begin();
+ bool containsDelim = libName.Find(it, DIRECTORY_SEPARATOR_STR_W);
- if (containsSuffix)
- {
- libNameVariations[varCount++] = NameFmt;
+ if (containsSuffix)
+ {
+ libNameVariations[varCount++] = NameFmt;
- if (!containsDelim)
- libNameVariations[varCount++] = PrefixNameFmt;
+ if (!containsDelim)
+ libNameVariations[varCount++] = PrefixNameFmt;
- libNameVariations[varCount++] = NameSuffixFmt;
+ libNameVariations[varCount++] = NameSuffixFmt;
- if (!containsDelim)
- libNameVariations[varCount++] = PrefixNameSuffixFmt;
- }
- else
- {
- libNameVariations[varCount++] = NameSuffixFmt;
+ if (!containsDelim)
+ libNameVariations[varCount++] = PrefixNameSuffixFmt;
+ }
+ else
+ {
+ libNameVariations[varCount++] = NameSuffixFmt;
- if (!containsDelim)
- libNameVariations[varCount++] = PrefixNameSuffixFmt;
+ if (!containsDelim)
+ libNameVariations[varCount++] = PrefixNameSuffixFmt;
- libNameVariations[varCount++] = NameFmt;
+ libNameVariations[varCount++] = NameFmt;
- if (!containsDelim)
- libNameVariations[varCount++] = PrefixNameFmt;
+ if (!containsDelim)
+ libNameVariations[varCount++] = PrefixNameFmt;
+ }
}
- }
- *numberOfVariations = varCount;
-}
-#else // TARGET_UNIX
-static const int MaxVariationCount = 2;
-static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath)
-{
- // Supported lib name variations
- static auto NameFmt = W("%.0s%s%.0s");
- static auto NameSuffixFmt = W("%.0s%s%s");
-
- _ASSERTE(*numberOfVariations >= MaxVariationCount);
-
- int varCount = 0;
-
- // The purpose of following code is to workaround LoadLibrary limitation:
- // LoadLibrary won't append extension if filename itself contains '.'. Thus it will break the following scenario:
- // [DllImport("A.B")] // The full name for file is "A.B.dll". This is common code pattern for cross-platform PInvoke
- // The workaround for above scenario is to call LoadLibrary with "A.B" first, if it fails, then call LoadLibrary with "A.B.dll"
- auto it = libName.Begin();
- if (!libNameIsRelativePath ||
- !libName.Find(it, W('.')) ||
- libName.EndsWith(W(".")) ||
- libName.EndsWithCaseInsensitive(W(".dll")) ||
- libName.EndsWithCaseInsensitive(W(".exe")))
- {
- // Follow LoadLibrary rules in MSDN doc: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
- // If the string specifies a full path, the function searches only that path for the module.
- // If the string specifies a module name without a path and the file name extension is omitted, the function appends the default library extension .dll to the module name.
- // To prevent the function from appending .dll to the module name, include a trailing point character (.) in the module name string.
- libNameVariations[varCount++] = NameFmt;
- }
- else
- {
- libNameVariations[varCount++] = NameFmt;
- libNameVariations[varCount++] = NameSuffixFmt;
+ *numberOfVariations = varCount;
}
+#else // TARGET_UNIX
+ const int MaxVariationCount = 2;
+ void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath)
+ {
+ // Supported lib name variations
+ static auto NameFmt = W("%.0s%s%.0s");
+ static auto NameSuffixFmt = W("%.0s%s%s");
+
+ _ASSERTE(*numberOfVariations >= MaxVariationCount);
+
+ int varCount = 0;
+
+ // The purpose of following code is to workaround LoadLibrary limitation:
+ // LoadLibrary won't append extension if filename itself contains '.'. Thus it will break the following scenario:
+ // [DllImport("A.B")] // The full name for file is "A.B.dll". This is common code pattern for cross-platform PInvoke
+ // The workaround for above scenario is to call LoadLibrary with "A.B" first, if it fails, then call LoadLibrary with "A.B.dll"
+ auto it = libName.Begin();
+ if (!libNameIsRelativePath ||
+ !libName.Find(it, W('.')) ||
+ libName.EndsWith(W(".")) ||
+ libName.EndsWithCaseInsensitive(W(".dll")) ||
+ libName.EndsWithCaseInsensitive(W(".exe")))
+ {
+ // Follow LoadLibrary rules in MSDN doc: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
+ // If the string specifies a full path, the function searches only that path for the module.
+ // If the string specifies a module name without a path and the file name extension is omitted, the function appends the default library extension .dll to the module name.
+ // To prevent the function from appending .dll to the module name, include a trailing point character (.) in the module name string.
+ libNameVariations[varCount++] = NameFmt;
+ }
+ else
+ {
+ libNameVariations[varCount++] = NameFmt;
+ libNameVariations[varCount++] = NameSuffixFmt;
+ }
- *numberOfVariations = varCount;
-}
+ *numberOfVariations = varCount;
+ }
#endif // TARGET_UNIX
-// Search for the library and variants of its name in probing directories.
-//static
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssembly,
- BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags,
- LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName)
-{
- STANDARD_VM_CONTRACT;
+ // Search for the library and variants of its name in probing directories.
+ NATIVE_LIBRARY_HANDLE LoadNativeLibraryBySearch(Assembly *callingAssembly,
+ BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags,
+ LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName)
+ {
+ STANDARD_VM_CONTRACT;
- NATIVE_LIBRARY_HANDLE hmod = NULL;
+ NATIVE_LIBRARY_HANDLE hmod = NULL;
#if defined(FEATURE_CORESYSTEM) && !defined(TARGET_UNIX)
- // Try to go straight to System32 for Windows API sets. This is replicating quick check from
- // the OS implementation of api sets.
- if (IsWindowsAPISet(wszLibName))
- {
- hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
- if (hmod != NULL)
+ // Try to go straight to System32 for Windows API sets. This is replicating quick check from
+ // the OS implementation of api sets.
+ if (IsWindowsAPISet(wszLibName))
{
- return hmod;
+ hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
}
- }
#endif // FEATURE_CORESYSTEM && !TARGET_UNIX
- AppDomain* pDomain = GetAppDomain();
- DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
- bool libNameIsRelativePath = Path::IsRelative(wszLibName);
-
- // 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.
- const WCHAR* prefixSuffixCombinations[MaxVariationCount] = {};
- int numberOfVariations = COUNTOF(prefixSuffixCombinations);
- DetermineLibNameVariations(prefixSuffixCombinations, &numberOfVariations, wszLibName, libNameIsRelativePath);
- for (int i = 0; i < numberOfVariations; i++)
- {
- SString currLibNameVariation;
- 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(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
- if (hmod != NULL)
- {
- return hmod;
- }
+ AppDomain* pDomain = GetAppDomain();
+ DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
+ bool libNameIsRelativePath = Path::IsRelative(wszLibName);
+
+ // 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.
+ const WCHAR* prefixSuffixCombinations[MaxVariationCount] = {};
+ int numberOfVariations = COUNTOF(prefixSuffixCombinations);
+ DetermineLibNameVariations(prefixSuffixCombinations, &numberOfVariations, wszLibName, libNameIsRelativePath);
+ for (int i = 0; i < numberOfVariations; i++)
+ {
+ SString currLibNameVariation;
+ 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(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
- if (!libNameIsRelativePath)
- {
- DWORD flags = loadWithAlteredPathFlags;
- if ((dllImportSearchPathFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
+ if (!libNameIsRelativePath)
{
- // 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 |= dllImportSearchPathFlags;
+ DWORD flags = loadWithAlteredPathFlags;
+ 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 |= dllImportSearchPathFlags;
+ }
+
+ hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
+ }
+ else if ((callingAssembly != nullptr) && searchAssemblyDirectory)
+ {
+ hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
+ if (hmod != NULL)
+ {
+ return hmod;
+ }
}
- hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker);
+ hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker);
if (hmod != NULL)
{
return hmod;
}
}
- else if ((callingAssembly != nullptr) && searchAssemblyDirectory)
+
+ // This may be an assembly name
+ // Format is "fileName, assemblyDisplayName"
+ MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
+ char *szComma = strchr(szLibName, ',');
+ if (szComma)
{
- hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
- if (hmod != NULL)
+ *szComma = '\0';
+ // Trim white spaces
+ while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
+
+ AssemblySpec spec;
+ if (SUCCEEDED(spec.Init(szComma)))
{
- return hmod;
+ // Need to perform case insensitive hashing.
+ SString moduleName(SString::Utf8, szLibName);
+ moduleName.LowerCase();
+
+ StackScratchBuffer buffer;
+ szLibName = (LPSTR)moduleName.GetUTF8(buffer);
+
+ Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
+ Module *pModule = pAssembly->FindModuleByName(szLibName);
+
+ hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
}
}
- hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker);
- if (hmod != NULL)
- {
- return hmod;
- }
+ return hmod;
}
- // This may be an assembly name
- // Format is "fileName, assemblyDisplayName"
- MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
- char *szComma = strchr(szLibName, ',');
- if (szComma)
+ NATIVE_LIBRARY_HANDLE LoadNativeLibraryBySearch(NDirectMethodDesc *pMD, LoadLibErrorTracker *pErrorTracker, PCWSTR wszLibName)
{
- *szComma = '\0';
- // Trim white spaces
- while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
+ STANDARD_VM_CONTRACT;
- AssemblySpec spec;
- if (SUCCEEDED(spec.Init(szComma)))
- {
- // Need to perform case insensitive hashing.
- SString moduleName(SString::Utf8, szLibName);
- moduleName.LowerCase();
+ BOOL searchAssemblyDirectory;
+ DWORD dllImportSearchPathFlags;
- StackScratchBuffer buffer;
- szLibName = (LPSTR)moduleName.GetUTF8(buffer);
+ GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory);
- Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
- Module *pModule = pAssembly->FindModuleByName(szLibName);
+ Assembly *pAssembly = pMD->GetMethodTable()->GetAssembly();
+ return LoadNativeLibraryBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName);
+ }
+}
- hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
- }
+// static
+NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly,
+ BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags,
+ BOOL throwOnError)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(libraryName));
+ PRECONDITION(CheckPointer(callingAssembly));
+ }
+ CONTRACTL_END;
+
+ 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
+ {
+ GetDllImportSearchPathFlags(callingAssembly->GetManifestModule(),
+ &dllImportSearchPathFlags, &searchAssemblyDirectory);
+ }
+
+ LoadLibErrorTracker errorTracker;
+ hmod = LoadNativeLibraryBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName);
+ if (hmod != nullptr)
+ return hmod;
+
+ // Resolve using the AssemblyLoadContext.ResolvingUnmanagedDll event
+ hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(callingAssembly, libraryName);
+ if (hmod != nullptr)
+ return hmod;
+
+ if (throwOnError)
+ {
+ SString libraryPathSString(libraryName);
+ errorTracker.Throw(libraryPathSString);
}
return hmod;
}
-// This Method returns an instance of the PAL-Registered handle
-NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
+NATIVE_LIBRARY_HANDLE NDirect::LoadNativeLibrary(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
{
CONTRACTL
{
PREFIX_ASSUME( name != NULL );
MAKE_WIDEPTR_FROMUTF8( wszLibName, name );
- NativeLibraryHandleHolder hmod = LoadLibraryModuleViaCallback(pMD, wszLibName);
+ NativeLibraryHandleHolder hmod = LoadNativeLibraryViaDllImportResolver(pMD, wszLibName);
if (hmod != NULL)
{
return hmod.Extract();
}
AppDomain* pDomain = GetAppDomain();
+ Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
- // AssemblyLoadContext is not supported in AppX mode and thus,
- // we should not perform PInvoke resolution via it when operating in AppX mode.
- if (!AppX::IsAppXProcess())
+ hmod = LoadNativeLibraryViaAssemblyLoadContext(pAssembly, wszLibName);
+ if (hmod != NULL)
{
- hmod = LoadLibraryModuleViaHost(pMD, wszLibName);
- if (hmod != NULL)
- {
- return hmod.Extract();
- }
+ return hmod.Extract();
}
hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
return hmod.Extract();
}
- hmod = LoadLibraryModuleBySearch(pMD, pErrorTracker, wszLibName);
+ hmod = LoadNativeLibraryBySearch(pMD, pErrorTracker, wszLibName);
if (hmod != NULL)
{
// If we have a handle add it to the cache.
return hmod.Extract();
}
- if (!AppX::IsAppXProcess())
+ hmod = LoadNativeLibraryViaAssemblyLoadContextEvent(pAssembly, wszLibName);
+ if (hmod != NULL)
{
- hmod = LoadLibraryModuleViaEvent(pMD, wszLibName);
- if (hmod != NULL)
- {
- return hmod.Extract();
- }
+ return hmod.Extract();
}
return hmod.Extract();
LoadLibErrorTracker errorTracker;
BOOL fSuccess = FALSE;
- NATIVE_LIBRARY_HANDLE hmod = LoadLibraryModule( pMD, &errorTracker );
+ NATIVE_LIBRARY_HANDLE hmod = LoadNativeLibrary( pMD, &errorTracker );
if ( hmod )
{
LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);