diff options
author | Swaroop Sridhar <Swaroop.Sridhar@microsoft.com> | 2019-01-12 22:25:25 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-12 22:25:25 -0800 |
commit | 8b7d300c164971f573d8186e78204597a679c7d8 (patch) | |
tree | 4bae0726ff3cb5b97c43ad127b8b41a117e2c06f | |
parent | 908891ce9df8d94f28ec6a53a012d39d00c8e65d (diff) | |
download | coreclr-8b7d300c164971f573d8186e78204597a679c7d8.tar.gz coreclr-8b7d300c164971f573d8186e78204597a679c7d8.tar.bz2 coreclr-8b7d300c164971f573d8186e78204597a679c7d8.zip |
Add NativeLibrary Resolve Event (#21929)
This change adds the Native library resolving event, to be raised as the last attempt to resolve a native DLL in an AssemblyLoadContext.
With this change, the DllImport resolution sequence is as follows (stopping at any step with successful resolution):
* If the invoking-assembly is not in the default load context, call AssemblyLoadContext.LoadUnmanagedDll()
* Run the default load logic, try loading from:
* AppDomain cache
* NATIVE_DLL_SEARCH_DIRECTORIES
* Invoking-assembly directory, System32, etc. based on DllImportSearchPaths
* Raise the ResolvingUnmanagedDll event
API Review: https://github.com/dotnet/corefx/issues/32850
The ResolveEventTests triggered a pre-existing bug in the exception handling code (#21964).
Disabling the test on ARM64 Windows until the issue is fixed.
-rw-r--r-- | src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs | 50 | ||||
-rw-r--r-- | src/vm/dllimport.cpp | 126 | ||||
-rw-r--r-- | src/vm/dllimport.h | 3 | ||||
-rw-r--r-- | src/vm/metasig.h | 1 | ||||
-rw-r--r-- | src/vm/mscorlib.h | 1 | ||||
-rw-r--r-- | tests/issues.targets | 6 | ||||
-rw-r--r-- | tests/src/Interop/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/src/Interop/NativeLibraryResolveEvent/CMakeLists.txt | 13 | ||||
-rw-r--r-- | tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.cs | 118 | ||||
-rw-r--r-- | tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.csproj | 36 | ||||
-rw-r--r-- | tests/src/Interop/NativeLibraryResolveEvent/ResolvedLib.cpp | 12 | ||||
-rw-r--r-- | tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.cs | 16 | ||||
-rw-r--r-- | tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.csproj | 33 | ||||
-rw-r--r-- | tests/src/Interop/ReadMe.md | 4 |
14 files changed, 391 insertions, 29 deletions
diff --git a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs index 7ec6cf4c29..fdb27d95f6 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -78,6 +78,7 @@ namespace System.Runtime.Loader m_pNativeAssemblyLoadContext = InitializeAssemblyLoadContext(thisHandlePtr, fRepresentsTPALoadContext, isCollectible); // Initialize event handlers to be null by default + ResolvingUnmanagedDll = null; Resolving = null; Unloading = null; @@ -304,12 +305,12 @@ namespace System.Runtime.Loader resolvedAssembly = handler(this, assemblyName); if (resolvedAssembly != null) { - break; + return resolvedAssembly; } } } - return resolvedAssembly; + return null; } private Assembly ValidateAssemblyNameWithSimpleName(Assembly assembly, string requestedSimpleName) @@ -413,6 +414,36 @@ namespace System.Runtime.Loader return context.LoadUnmanagedDll(unmanagedDllName); } + // This method is invoked by the VM to resolve a native library using the ResolvingUnmanagedDll event + // after trying all other means of resolution. + private static IntPtr ResolveUnmanagedDllUsingEvent(string unmanagedDllName, Assembly assembly, IntPtr gchManagedAssemblyLoadContext) + { + AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target); + return context.GetResolvedUnmanagedDll(assembly, unmanagedDllName); + } + + private IntPtr GetResolvedUnmanagedDll(Assembly assembly, string unmanagedDllName) + { + IntPtr resolvedDll = IntPtr.Zero; + + Func<Assembly, string, IntPtr> dllResolveHandler = ResolvingUnmanagedDll; + + if (dllResolveHandler != null) + { + // Loop through the event subscribers and return the first non-null native library handle + foreach (Func<Assembly, string, IntPtr> handler in dllResolveHandler.GetInvocationList()) + { + resolvedDll = handler(assembly, unmanagedDllName); + if (resolvedDll != IntPtr.Zero) + { + return resolvedDll; + } + } + } + + return IntPtr.Zero; + } + public static AssemblyLoadContext Default { get @@ -509,7 +540,22 @@ namespace System.Runtime.Loader } } + // Event handler for resolving native libraries. + // This event is raised if the native library could not be resolved via + // the default resolution logic [including AssemblyLoadContext.LoadUnmanagedDll()] + // + // Inputs: Invoking assembly, and library name to resolve + // Returns: A handle to the loaded native library + public event Func<Assembly, string, IntPtr> ResolvingUnmanagedDll; + + // Event handler for resolving managed assemblies. + // This event is raised if the managed assembly could not be resolved via + // the default resolution logic [including AssemblyLoadContext.Load()] + // + // Inputs: The AssemblyLoadContext and AssemblyName to be loaded + // Returns: The Loaded assembly object. public event Func<AssemblyLoadContext, AssemblyName, Assembly> Resolving; + public event Action<AssemblyLoadContext> Unloading; // Contains the reference to VM's representation of the AssemblyLoadContext diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp index 8c86882006..37cfda9775 100644 --- a/src/vm/dllimport.cpp +++ b/src/vm/dllimport.cpp @@ -6275,7 +6275,7 @@ INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR sy } // static -NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, PCWSTR wszLibName) +NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, PCWSTR wszLibName) { STANDARD_VM_CONTRACT; //Dynamic Pinvoke Support: @@ -6290,7 +6290,8 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, } #endif - LPVOID hmod = NULL; + NATIVE_LIBRARY_HANDLE hmod = NULL; + AppDomain* pDomain = GetAppDomain(); CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext(); Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly(); @@ -6349,11 +6350,92 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext); // Make the call - CALL_MANAGED_METHOD(hmod,LPVOID,args); + CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args); + + GCPROTECT_END(); + + return hmod; +} + +// 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<ICLRPrivBinder *>(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 (NATIVE_LIBRARY_HANDLE)hmod; + return hmod; } // Try to load the module alongside the assembly where the PInvoke was declared. @@ -6633,15 +6715,13 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke AppDomain* pDomain = GetAppDomain(); // AssemblyLoadContext is not supported in AppX mode and thus, - // we should not perform PInvoke resolution via it when operating in - // AppX mode. + // we should not perform PInvoke resolution via it when operating in AppX mode. if (!AppX::IsAppXProcess()) { - hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName); + hmod = LoadLibraryModuleViaHost(pMD, wszLibName); if (hmod != NULL) { #ifdef FEATURE_PAL - // Register the system library handle with PAL and get a PAL library handle hmod = PAL_RegisterLibraryDirect(hmod, wszLibName); #endif // FEATURE_PAL return hmod.Extract(); @@ -6654,36 +6734,30 @@ HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracke return hmod.Extract(); } -#ifdef FEATURE_PAL - // In the PAL version of CoreCLR, the CLR module itself exports the functionality - // that the Windows version obtains from kernel32 and friends. In order to avoid - // picking up the wrong instance, we perform this redirection first. - // This is also true for CoreSystem builds, where mscorlib p/invokes are forwarded through coreclr - // itself so we can control CoreSystem library/API name re-mapping from one central location. - if (SString::_wcsicmp(wszLibName, MAIN_CLR_MODULE_NAME_W) == 0) + hmod = LoadLibraryModuleBySearch(pMD, pErrorTracker, wszLibName); + if (hmod != NULL) { - hmod = GetCLRModule(); - } +#ifdef FEATURE_PAL + hmod = PAL_RegisterLibraryDirect(hmod, wszLibName); #endif // FEATURE_PAL - if (hmod == NULL) + // If we have a handle add it to the cache. + pDomain->AddUnmanagedImageToCache(wszLibName, hmod); + return hmod.Extract(); + } + + if (!AppX::IsAppXProcess()) { - hmod = LoadLibraryModuleBySearch(pMD, pErrorTracker, wszLibName); + hmod = LoadLibraryModuleViaEvent(pMD, wszLibName); if (hmod != NULL) { #ifdef FEATURE_PAL - // Register the system library handle with PAL and get a PAL library handle hmod = PAL_RegisterLibraryDirect(hmod, wszLibName); #endif // FEATURE_PAL + return hmod.Extract(); } } - if (hmod != NULL) - { - // If we have a handle add it to the cache. - pDomain->AddUnmanagedImageToCache(wszLibName, hmod); - } - return hmod.Extract(); } diff --git a/src/vm/dllimport.h b/src/vm/dllimport.h index 2f25e59570..1203803b9a 100644 --- a/src/vm/dllimport.h +++ b/src/vm/dllimport.h @@ -124,7 +124,8 @@ private: static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); static NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); - static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName); + static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, LPCWSTR wszLibName); + static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaEvent(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); diff --git a/src/vm/metasig.h b/src/vm/metasig.h index 154c91570c..cfa844012e 100644 --- a/src/vm/metasig.h +++ b/src/vm/metasig.h @@ -551,6 +551,7 @@ DEFINE_METASIG_T(IM(RefGuid_OutIntPtr_RetCustomQueryInterfaceResult, r(g(GUID)) #endif //FEATURE_COMINTEROP DEFINE_METASIG_T(SM(IntPtr_AssemblyName_RetAssemblyBase, I C(ASSEMBLY_NAME), C(ASSEMBLYBASE))) +DEFINE_METASIG_T(SM(Str_AssemblyBase_IntPtr_RetIntPtr, s C(ASSEMBLYBASE) I, I)) // ThreadPool DEFINE_METASIG(SM(Obj_Bool_RetVoid, j F, v)) diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 62205d39bc..a1341dd70f 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -864,6 +864,7 @@ DEFINE_METHOD(FIRSTCHANCE_EVENTARGS, CTOR, .ctor, DEFINE_CLASS(ASSEMBLYLOADCONTEXT, Loader, AssemblyLoadContext) DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVE, Resolve, SM_IntPtr_AssemblyName_RetAssemblyBase) DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUNMANAGEDDLL, ResolveUnmanagedDll, SM_Str_IntPtr_RetIntPtr) +DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUNMANAGEDDLLUSINGEVENT, ResolveUnmanagedDllUsingEvent, SM_Str_AssemblyBase_IntPtr_RetIntPtr) DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUSINGEVENT, ResolveUsingResolvingEvent, SM_IntPtr_AssemblyName_RetAssemblyBase) DEFINE_FIELD(ASSEMBLYLOADCONTEXT, ASSEMBLY_LOAD, AssemblyLoad) DEFINE_METHOD(ASSEMBLYLOADCONTEXT, ON_ASSEMBLY_LOAD, OnAssemblyLoad, SM_Assembly_RetVoid) diff --git a/tests/issues.targets b/tests/issues.targets index 11043ffd2a..fd1d96558f 100644 --- a/tests/issues.targets +++ b/tests/issues.targets @@ -388,6 +388,9 @@ <ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl/*"> <Issue>9565</Issue> </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/Interop/NativeLibraryResolveEvent/ResolveEventTests/*"> + <Issue>21964</Issue> + </ExcludeList> <ExcludeList Include="$(XunitTestBinBase)/Regressions/coreclr/16064/methodimpl/*"> <Issue>9565</Issue> </ExcludeList> @@ -819,6 +822,9 @@ <ExcludeList Include="$(XunitTestBinBase)/Interop/NativeLibrary/NativeLibraryTests/*"> <Issue>Issue building native components for the test. Since tests are currently built on Windows, the native components end up at Core_Root instead of Test directory, which is not suitable for the test.</Issue> </ExcludeList> + <ExcludeList Include="$(XunitTestBinBase)/Interop/MarshalAPI/ResolveEvent/ResolveEventTests/*"> + <Issue>Issue building native components for the test. Since tests are currently built on Windows, the native components end up at Core_Root instead of Test directory, which is not suitable for the test.</Issue> + </ExcludeList> <ExcludeList Include="$(XunitTestBinBase)/CoreMangLib/cti/system/byte/ByteToString3/*"> <Issue>needs triage</Issue> </ExcludeList> diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 9784ea1c95..e46e78a8ff 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory(StringMarshalling/VBByRefStr) add_subdirectory(MarshalAPI/FunctionPointer) add_subdirectory(MarshalAPI/IUnknown) add_subdirectory(NativeLibrary) +add_subdirectory(NativeLibraryResolveEvent) add_subdirectory(SizeConst) add_subdirectory(DllImportAttribute/ExeFile) add_subdirectory(DllImportAttribute/FileNameContainDot) diff --git a/tests/src/Interop/NativeLibraryResolveEvent/CMakeLists.txt b/tests/src/Interop/NativeLibraryResolveEvent/CMakeLists.txt new file mode 100644 index 0000000000..20935806ca --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveEvent/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 2.6) +project (ResolvedLib) +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES ResolvedLib.cpp) + +# add the executable +add_library (ResolvedLib SHARED ${SOURCES}) +target_link_libraries(ResolvedLib ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS ResolvedLib DESTINATION bin) + + diff --git a/tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.cs b/tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.cs new file mode 100644 index 0000000000..245bfc6529 --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.cs @@ -0,0 +1,118 @@ +// 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.Runtime.Loader; +using System.Reflection; +using System.Runtime.InteropServices; + +using Console = Internal.Console; + +public class ALC : AssemblyLoadContext +{ + protected override Assembly Load(AssemblyName assemblyName) + { + return Assembly.Load(assemblyName); + } +} + +public class ResolveEventTests +{ + static int HandlerTracker = 1; + + public static int Main() + { + // Events on the Default Load Context + + try + { + AssemblyLoadContext.Default.ResolvingUnmanagedDll += HandlerFail; + NativeSum(10, 10); + } + catch (DllNotFoundException e) + { + if (HandlerTracker != 0) + { + Console.WriteLine("Event Handlers not called as expected"); + return 101; + } + } + catch (Exception e) + { + Console.WriteLine($"Unexpected exception: {e.Message}"); + return 102; + } + + try + { + AssemblyLoadContext.Default.ResolvingUnmanagedDll += HandlerPass; + + if(NativeSum(10, 10) != 20) + { + Console.WriteLine("Unexpected ReturnValue from NativeSum()"); + return 103; + } + if (HandlerTracker != 0) + { + Console.WriteLine("Event Handlers not called as expected"); + return 104; + } + } + catch (Exception e) + { + Console.WriteLine($"Unexpected exception: {e.Message}"); + return 105; + } + + // Events on a Custom Load Context + + try + { + string currentDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string testAsmDir = Path.Combine(currentDir, "..", "TestAsm", "TestAsm"); + + ALC alc = new ALC(); + alc.ResolvingUnmanagedDll += HandlerPass; + + var assembly = alc.LoadFromAssemblyPath(Path.Combine(testAsmDir, "TestAsm.dll")); + var type = assembly.GetType("TestAsm"); + var method = type.GetMethod("Sum"); + int value = (int)method.Invoke(null, new object[] { 10, 10 }); + + if(value != 20) + { + Console.WriteLine("Unexpected ReturnValue from TestAsm.Sum()"); + return 106; + } + if (HandlerTracker != 1) + { + Console.WriteLine("Event Handlers not called as expected"); + return 107; + } + } + catch (Exception e) + { + Console.WriteLine($"Unexpected exception: {e.Message}"); + return 108; + } + + return 100; + } + + public static IntPtr HandlerFail(Assembly assembly, string libraryName) + { + HandlerTracker--; + return IntPtr.Zero; + } + + public static IntPtr HandlerPass(Assembly assembly, string libraryName) + { + HandlerTracker++; + return NativeLibrary.Load("ResolvedLib", assembly, null); + } + + [DllImport("NativeLib")] + static extern int NativeSum(int arg1, int arg2); + +} diff --git a/tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.csproj b/tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.csproj new file mode 100644 index 0000000000..d912938457 --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveEvent/ResolveEventTests.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>ResolveEventTests</AssemblyName> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <ReferenceSystemPrivateCoreLib>true</ReferenceSystemPrivateCoreLib> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="*.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="CMakeLists.txt" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/Interop/NativeLibraryResolveEvent/ResolvedLib.cpp b/tests/src/Interop/NativeLibraryResolveEvent/ResolvedLib.cpp new file mode 100644 index 0000000000..87ae50ed58 --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveEvent/ResolvedLib.cpp @@ -0,0 +1,12 @@ +// 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 <stdio.h> +#include <xplatform.h> + +extern "C" DLL_EXPORT int NativeSum(int a, int b) +{ + return a + b; +} + + diff --git a/tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.cs b/tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.cs new file mode 100644 index 0000000000..1517c94f6e --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.cs @@ -0,0 +1,16 @@ +// 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.Runtime.InteropServices; + +public class TestAsm +{ + public static int Sum(int a, int b) + { + return NativeSum(a, b); + } + + [DllImport("NativeLib")] + static extern int NativeSum(int arg1, int arg2); +} diff --git a/tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.csproj b/tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.csproj new file mode 100644 index 0000000000..e8f3e3af21 --- /dev/null +++ b/tests/src/Interop/NativeLibraryResolveEvent/TestAsm/TestAsm.csproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>TestAsm</AssemblyName> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid> + <OutputType>Library</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <ReferenceSystemPrivateCoreLib>true</ReferenceSystemPrivateCoreLib> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="*.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/Interop/ReadMe.md b/tests/src/Interop/ReadMe.md index 9bd1d79313..97e4202580 100644 --- a/tests/src/Interop/ReadMe.md +++ b/tests/src/Interop/ReadMe.md @@ -57,6 +57,10 @@ Testing P/Invoke has two aspects: The Marshal API surface area testing is traditionally done via unit testing and far better suited in the [CoreFX](https://github.com/dotnet/corefx/tree/master/src/System.Runtime.InteropServices/tests) repo. Cases where testing the API surface area requires native tests assets will be performed in the [CoreCLR](https://github.com/dotnet/coreclr/tree/master/tests/src/Interop) repo. +### NativeLibrary + +This series has unit tests corresponding to `System.Runtime.NativeLibrary` APIs and related events in `System.Runtime.Loader.AssemblyLoadContext`. + ## Common Task steps ### Adding new native project |