diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 0541c4bba3df..f24051c6ad21 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -288,6 +288,7 @@ + diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index 594b7585465a..1ac33e00ba3f 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -1788,164 +1788,5 @@ public static unsafe void ZeroFreeGlobalAllocUnicode(IntPtr s) RuntimeImports.RhZeroMemory(s, (UIntPtr)(string.wcslen((char*)s) * 2)); FreeHGlobal(s); } - - /// APIs for managing Native Libraries - - /// - /// NativeLibrary Loader: Simple API - /// This method is a wrapper around OS loader, using "default" flags. - /// - /// The name of the native library to be loaded - /// The handle for the loaded native library - /// If libraryPath is null - /// If the library can't be found. - /// If the library is not valid. - public static IntPtr LoadLibrary(string libraryPath) - { - if (libraryPath == null) - throw new ArgumentNullException(nameof(libraryPath)); - - return LoadLibraryFromPath(libraryPath, throwOnError: true); - } - - /// - /// NativeLibrary Loader: Simple API that doesn't throw - /// - /// The name of the native library to be loaded - /// The out-parameter for the loaded native library handle - /// True on successful load, false otherwise - /// If libraryPath is null - public static bool TryLoadLibrary(string libraryPath, out IntPtr handle) - { - if (libraryPath == null) - throw new ArgumentNullException(nameof(libraryPath)); - - handle = LoadLibraryFromPath(libraryPath, throwOnError: false); - return handle != IntPtr.Zero; - } - - /// - /// NativeLibrary Loader: High-level API - /// Given a library name, this function searches specific paths based on the - /// runtime configuration, input parameters, and attributes of the calling assembly. - /// If DllImportSearchPath parameter is non-null, the flags in this enumeration are used. - /// Otherwise, the flags specified by the DefaultDllImportSearchPaths attribute on the - /// calling assembly (if any) are used. - /// This LoadLibrary() method does not invoke the managed call-backs for native library resolution: - /// * AssemblyLoadContext.LoadUnmanagedDll() - /// - /// The name of the native library to be loaded - /// The assembly loading the native library - /// The search path - /// The handle for the loaded library - /// If libraryPath or assembly is null - /// If assembly is not a RuntimeAssembly - /// If the library can't be found. - /// If the library is not valid. - public static IntPtr LoadLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) - { - if (libraryName == null) - throw new ArgumentNullException(nameof(libraryName)); - if (assembly == null) - throw new ArgumentNullException(nameof(assembly)); - if (!(assembly is RuntimeAssembly)) - throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); - - return LoadLibraryByName(libraryName, - ((RuntimeAssembly)assembly).GetNativeHandle(), - searchPath.HasValue, - (uint) searchPath.GetValueOrDefault(), - throwOnError: true); - } - - /// - /// NativeLibrary Loader: High-level API that doesn't throw. - /// - /// The name of the native library to be loaded - /// The search path - /// The assembly loading the native library - /// The out-parameter for the loaded native library handle - /// True on successful load, false otherwise - /// If libraryPath or assembly is null - /// If assembly is not a RuntimeAssembly - public static bool TryLoadLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, out IntPtr handle) - { - if (libraryName == null) - throw new ArgumentNullException(nameof(libraryName)); - if (assembly == null) - throw new ArgumentNullException(nameof(assembly)); - if (!(assembly is RuntimeAssembly)) - throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); - - handle = LoadLibraryByName(libraryName, - ((RuntimeAssembly)assembly).GetNativeHandle(), - searchPath.HasValue, - (uint) searchPath.GetValueOrDefault(), - throwOnError: false); - return handle != IntPtr.Zero; - } - - /// - /// Free a loaded library - /// Given a library handle, free it. - /// No action if the input handle is null. - /// - /// The native library handle to be freed - /// If the operation fails - public static void FreeLibrary(IntPtr handle) - { - FreeNativeLibrary(handle); - } - - /// - /// Get the address of an exported Symbol - /// This is a simple wrapper around OS calls, and does not perform any name mangling. - /// - /// The native library handle - /// The name of the exported symbol - /// The address of the symbol - /// If handle or name is null - /// If the symbol is not found - public static IntPtr GetLibraryExport(IntPtr handle, string name) - { - if (handle == IntPtr.Zero) - throw new ArgumentNullException(nameof(handle)); - if (name == null) - throw new ArgumentNullException(nameof(name)); - - return GetNativeLibraryExport(handle, name, throwOnError: true); - } - - /// - /// Get the address of an exported Symbol, but do not throw - /// - /// The native library handle - /// The name of the exported symbol - /// The out-parameter for the symbol address, if it exists - /// True on success, false otherwise - /// If handle or name is null - public static bool TryGetLibraryExport(IntPtr handle, string name, out IntPtr address) - { - if (handle == IntPtr.Zero) - throw new ArgumentNullException(nameof(handle)); - if (name == null) - throw new ArgumentNullException(nameof(name)); - - address = GetNativeLibraryExport(handle, name, throwOnError: false); - return address != IntPtr.Zero; - } - - /// External functions that implement the NativeLibrary interface - - [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern IntPtr LoadLibraryFromPath(string libraryName, bool throwOnError); - [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern IntPtr LoadLibraryByName(string libraryName, RuntimeAssembly callingAssembly, - bool hasDllImportSearchPathFlag, uint dllImportSearchPathFlag, - bool throwOnError); - [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern void FreeNativeLibrary(IntPtr handle); - [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern IntPtr GetNativeLibraryExport(IntPtr handle, string symbolName, bool throwOnError); } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs new file mode 100644 index 000000000000..38712ac1b724 --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.cs @@ -0,0 +1,180 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using Win32Native = Microsoft.Win32.Win32Native; +using System.Diagnostics; + +namespace System.Runtime.InteropServices +{ + /// + /// APIs for managing Native Libraries + /// + public static partial class NativeLibrary + { + /// + /// NativeLibrary Loader: Simple API + /// This method is a wrapper around OS loader, using "default" flags. + /// + /// The name of the native library to be loaded + /// The handle for the loaded native library + /// If libraryPath is null + /// If the library can't be found. + /// If the library is not valid. + public static IntPtr Load(string libraryPath) + { + if (libraryPath == null) + throw new ArgumentNullException(nameof(libraryPath)); + + return LoadFromPath(libraryPath, throwOnError: true); + } + + /// + /// NativeLibrary Loader: Simple API that doesn't throw + /// + /// The name of the native library to be loaded + /// The out-parameter for the loaded native library handle + /// True on successful load, false otherwise + /// If libraryPath is null + public static bool TryLoad(string libraryPath, out IntPtr handle) + { + if (libraryPath == null) + throw new ArgumentNullException(nameof(libraryPath)); + + handle = LoadFromPath(libraryPath, throwOnError: false); + return handle != IntPtr.Zero; + } + + /// + /// NativeLibrary Loader: High-level API + /// Given a library name, this function searches specific paths based on the + /// runtime configuration, input parameters, and attributes of the calling assembly. + /// If DllImportSearchPath parameter is non-null, the flags in this enumeration are used. + /// Otherwise, the flags specified by the DefaultDllImportSearchPaths attribute on the + /// calling assembly (if any) are used. + /// This LoadLibrary() method does not invoke the managed call-backs for native library resolution: + /// * AssemblyLoadContext.LoadUnmanagedDll() + /// + /// The name of the native library to be loaded + /// The assembly loading the native library + /// The search path + /// The handle for the loaded library + /// If libraryPath or assembly is null + /// If assembly is not a RuntimeAssembly + /// If the library can't be found. + /// If the library is not valid. + public static IntPtr Load(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) + { + if (libraryName == null) + throw new ArgumentNullException(nameof(libraryName)); + if (assembly == null) + throw new ArgumentNullException(nameof(assembly)); + if (!(assembly is RuntimeAssembly)) + throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); + + return LoadByName(libraryName, + ((RuntimeAssembly)assembly).GetNativeHandle(), + searchPath.HasValue, + (uint) searchPath.GetValueOrDefault(), + throwOnError: true); + } + + /// + /// NativeLibrary Loader: High-level API that doesn't throw. + /// + /// The name of the native library to be loaded + /// The search path + /// The assembly loading the native library + /// The out-parameter for the loaded native library handle + /// True on successful load, false otherwise + /// If libraryPath or assembly is null + /// If assembly is not a RuntimeAssembly + public static bool TryLoad(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, out IntPtr handle) + { + if (libraryName == null) + throw new ArgumentNullException(nameof(libraryName)); + if (assembly == null) + throw new ArgumentNullException(nameof(assembly)); + if (!(assembly is RuntimeAssembly)) + throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); + + handle = LoadByName(libraryName, + ((RuntimeAssembly)assembly).GetNativeHandle(), + searchPath.HasValue, + (uint) searchPath.GetValueOrDefault(), + throwOnError: false); + return handle != IntPtr.Zero; + } + + /// + /// Free a loaded library + /// Given a library handle, free it. + /// No action if the input handle is null. + /// + /// The native library handle to be freed + /// If the operation fails + public static void Free(IntPtr handle) + { + FreeLib(handle); + } + + /// + /// Get the address of an exported Symbol + /// This is a simple wrapper around OS calls, and does not perform any name mangling. + /// + /// The native library handle + /// The name of the exported symbol + /// The address of the symbol + /// If handle or name is null + /// If the symbol is not found + public static IntPtr GetExport(IntPtr handle, string name) + { + if (handle == IntPtr.Zero) + throw new ArgumentNullException(nameof(handle)); + if (name == null) + throw new ArgumentNullException(nameof(name)); + + return GetSymbol(handle, name, throwOnError: true); + } + + /// + /// Get the address of an exported Symbol, but do not throw + /// + /// The native library handle + /// The name of the exported symbol + /// The out-parameter for the symbol address, if it exists + /// True on success, false otherwise + /// If handle or name is null + public static bool TryGetExport(IntPtr handle, string name, out IntPtr address) + { + if (handle == IntPtr.Zero) + throw new ArgumentNullException(nameof(handle)); + if (name == null) + throw new ArgumentNullException(nameof(name)); + + address = GetSymbol(handle, name, throwOnError: false); + return address != IntPtr.Zero; + } + + /// External functions that implement the NativeLibrary interface + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + internal static extern IntPtr LoadFromPath(string libraryName, bool throwOnError); + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + internal static extern IntPtr LoadByName(string libraryName, RuntimeAssembly callingAssembly, + bool hasDllImportSearchPathFlag, uint dllImportSearchPathFlag, + bool throwOnError); + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + internal static extern void FreeLib(IntPtr handle); + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + internal static extern IntPtr GetSymbol(IntPtr handle, string symbolName, bool throwOnError); + } +} diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index 93ccb83f5f45..9bb26d402db1 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -355,6 +355,7 @@ set(VM_SOURCES_WKS multicorejitplayer.cpp # Condition="'$(FeatureMulticoreJIT)' == 'true' nativeeventsource.cpp nativeoverlapped.cpp + nativelibrarynative.cpp objectlist.cpp olevariant.cpp pendingload.cpp @@ -473,6 +474,7 @@ set(VM_HEADERS_WKS multicorejitimpl.h nativeeventsource.h nativeoverlapped.h + nativelibrarynative.h objectlist.h olevariant.h pendingload.h diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h index 021705231955..67eca4c147d2 100644 --- a/src/vm/ecalllist.h +++ b/src/vm/ecalllist.h @@ -841,11 +841,6 @@ FCFuncStart(gInteropMarshalFuncs) FCFuncElement("GetDelegateForFunctionPointerInternal", MarshalNative::GetDelegateForFunctionPointerInternal) FCFuncElement("GetFunctionPointerForDelegateInternal", MarshalNative::GetFunctionPointerForDelegateInternal) - QCFuncElement("LoadLibraryFromPath", MarshalNative::LoadLibraryFromPath) - QCFuncElement("LoadLibraryByName", MarshalNative::LoadLibraryByName) - QCFuncElement("FreeNativeLibrary", MarshalNative::FreeNativeLibrary) - QCFuncElement("GetNativeLibraryExport", MarshalNative::GetNativeLibraryExport) - #ifdef FEATURE_COMINTEROP FCFuncElement("GetHRForException", MarshalNative::GetHRForException) FCFuncElement("GetHRForException_WinRT", MarshalNative::GetHRForException_WinRT) @@ -880,6 +875,13 @@ FCFuncStart(gInteropMarshalFuncs) #endif // FEATURE_COMINTEROP FCFuncEnd() +FCFuncStart(gInteropNativeLibraryFuncs) + QCFuncElement("LoadFromPath", NativeLibraryNative::LoadFromPath) + QCFuncElement("LoadByName", NativeLibraryNative::LoadByName) + QCFuncElement("FreeLib", NativeLibraryNative::FreeLib) + QCFuncElement("GetSymbol", NativeLibraryNative::GetSymbol) +FCFuncEnd() + FCFuncStart(gArrayWithOffsetFuncs) FCFuncElement("CalculateCount", MarshalNative::CalculateCount) FCFuncEnd() @@ -1290,6 +1292,7 @@ FCClassElement("MngdSafeArrayMarshaler", "System.StubHelpers", gMngdSafeArrayMar FCClassElement("ModuleBuilder", "System.Reflection.Emit", gCOMModuleBuilderFuncs) FCClassElement("ModuleHandle", "System", gCOMModuleHandleFuncs) FCClassElement("Monitor", "System.Threading", gMonitorFuncs) +FCClassElement("NativeLibrary", "System.Runtime.InteropServices", gInteropNativeLibraryFuncs) #ifdef FEATURE_COMINTEROP FCClassElement("OAVariantLib", "Microsoft.Win32", gOAVariantFuncs) #endif diff --git a/src/vm/marshalnative.cpp b/src/vm/marshalnative.cpp index a2cb827d3497..e2b248289be0 100644 --- a/src/vm/marshalnative.cpp +++ b/src/vm/marshalnative.cpp @@ -923,69 +923,6 @@ FCIMPL1(int, MarshalNative::GetHRForException_WinRT, Object* eUNSAFE) } FCIMPLEND -// static -INT_PTR QCALLTYPE MarshalNative::LoadLibraryFromPath(LPCWSTR path, BOOL throwOnError) -{ - QCALL_CONTRACT; - - NATIVE_LIBRARY_HANDLE handle = nullptr; - - BEGIN_QCALL; - - handle = NDirect::LoadLibraryFromPath(path, throwOnError); - - END_QCALL; - - return reinterpret_cast(handle); -} - -// static -INT_PTR QCALLTYPE MarshalNative::LoadLibraryByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly, - BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, - BOOL throwOnError) -{ - QCALL_CONTRACT; - - NATIVE_LIBRARY_HANDLE handle = nullptr; - Assembly *pAssembly = callingAssembly->GetAssembly(); - - BEGIN_QCALL; - - handle = NDirect::LoadLibraryByName(name, pAssembly, hasDllImportSearchPathFlag, dllImportSearchPathFlag, throwOnError); - - END_QCALL; - - return reinterpret_cast(handle); -} - -// static -void QCALLTYPE MarshalNative::FreeNativeLibrary(INT_PTR handle) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - NDirect::FreeNativeLibrary((NATIVE_LIBRARY_HANDLE) handle); - - END_QCALL; -} - -//static -INT_PTR QCALLTYPE MarshalNative::GetNativeLibraryExport(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError) -{ - QCALL_CONTRACT; - - INT_PTR address = NULL; - - BEGIN_QCALL; - - address = NDirect::GetNativeLibraryExport((NATIVE_LIBRARY_HANDLE)handle, symbolName, throwOnError); - - END_QCALL; - - return address; -} - #ifdef FEATURE_COMINTEROP //==================================================================== diff --git a/src/vm/marshalnative.h b/src/vm/marshalnative.h index ddc835109402..85be41a86b93 100644 --- a/src/vm/marshalnative.h +++ b/src/vm/marshalnative.h @@ -85,17 +85,6 @@ class MarshalNative static FCDECL2(Object*, GetDelegateForFunctionPointerInternal, LPVOID FPtr, ReflectClassBaseObject* refTypeUNSAFE); static FCDECL1(LPVOID, GetFunctionPointerForDelegateInternal, Object* refDelegateUNSAFE); - - //==================================================================== - // These methods provide the native callbacks for library loading APIs - //==================================================================== - static INT_PTR QCALLTYPE LoadLibraryFromPath(LPCWSTR path, BOOL throwOnError); - static INT_PTR QCALLTYPE LoadLibraryByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly, - BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, - BOOL throwOnError); - static void QCALLTYPE FreeNativeLibrary(INT_PTR handle); - static INT_PTR QCALLTYPE GetNativeLibraryExport(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError); - #ifdef FEATURE_COMINTEROP //==================================================================== // map GUID to Type diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp index ca7f6b6bb580..e7a1eefb221e 100644 --- a/src/vm/mscorlib.cpp +++ b/src/vm/mscorlib.cpp @@ -36,6 +36,7 @@ #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/vm/nativelibrarynative.cpp b/src/vm/nativelibrarynative.cpp new file mode 100644 index 000000000000..c5bf24f06e65 --- /dev/null +++ b/src/vm/nativelibrarynative.cpp @@ -0,0 +1,74 @@ +// 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. +// +// File: NativeLibraryNative.cpp +// + +#include "common.h" +#include "dllimport.h" +#include "nativelibrarynative.h" + +// static +INT_PTR QCALLTYPE NativeLibraryNative::LoadFromPath(LPCWSTR path, BOOL throwOnError) +{ + QCALL_CONTRACT; + + NATIVE_LIBRARY_HANDLE handle = nullptr; + + BEGIN_QCALL; + + handle = NDirect::LoadLibraryFromPath(path, throwOnError); + + END_QCALL; + + return reinterpret_cast(handle); +} + +// static +INT_PTR QCALLTYPE NativeLibraryNative::LoadByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly, + BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, + BOOL throwOnError) +{ + QCALL_CONTRACT; + + NATIVE_LIBRARY_HANDLE handle = nullptr; + Assembly *pAssembly = callingAssembly->GetAssembly(); + + BEGIN_QCALL; + + handle = NDirect::LoadLibraryByName(name, pAssembly, hasDllImportSearchPathFlag, dllImportSearchPathFlag, throwOnError); + + END_QCALL; + + return reinterpret_cast(handle); +} + +// static +void QCALLTYPE NativeLibraryNative::FreeLib(INT_PTR handle) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + + NDirect::FreeNativeLibrary((NATIVE_LIBRARY_HANDLE) handle); + + END_QCALL; +} + +//static +INT_PTR QCALLTYPE NativeLibraryNative::GetSymbol(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError) +{ + QCALL_CONTRACT; + + INT_PTR address = NULL; + + BEGIN_QCALL; + + address = NDirect::GetNativeLibraryExport((NATIVE_LIBRARY_HANDLE)handle, symbolName, throwOnError); + + END_QCALL; + + return address; +} + diff --git a/src/vm/nativelibrarynative.h b/src/vm/nativelibrarynative.h new file mode 100644 index 000000000000..e22031cad656 --- /dev/null +++ b/src/vm/nativelibrarynative.h @@ -0,0 +1,26 @@ +// 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. +// +// File: NativeLibraryNative.h +// +// +// QCall's for the NativeLibrary class +// + +#ifndef __NATIVELIBRARYNATIVE_H__ +#define __NATIVELIBRARYNATIVE_H__ + +class NativeLibraryNative +{ +public: + static INT_PTR QCALLTYPE LoadFromPath(LPCWSTR path, BOOL throwOnError); + static INT_PTR QCALLTYPE LoadByName(LPCWSTR name, QCall::AssemblyHandle callingAssembly, + BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag, + BOOL throwOnError); + static void QCALLTYPE FreeLib(INT_PTR handle); + static INT_PTR QCALLTYPE GetSymbol(INT_PTR handle, LPCWSTR symbolName, BOOL throwOnError); + +}; + +#endif // __NATIVELIBRARYNATIVE_H__ diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 5685e79762c6..9e0bf85e9ccd 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -55,7 +55,7 @@ add_subdirectory(StringMarshalling/AnsiBSTR) add_subdirectory(StringMarshalling/VBByRefStr) add_subdirectory(MarshalAPI/FunctionPointer) add_subdirectory(MarshalAPI/IUnknown) -add_subdirectory(MarshalAPI/NativeLibrary) +add_subdirectory(NativeLibrary) add_subdirectory(SizeConst) add_subdirectory(DllImportAttribute/ExeFile) add_subdirectory(DllImportAttribute/FileNameContainDot) diff --git a/tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibraryTests.cs b/tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibraryTests.cs deleted file mode 100644 index dfc7335b3024..000000000000 --- a/tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibraryTests.cs +++ /dev/null @@ -1,385 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using TestLibrary; - -using Console = Internal.Console; - -enum TestResult { - Success, - ReturnFailure, - ReturnNull, - IncorrectEvaluation, - ArgumentNull, - ArgumentBad, - - DllNotFound, - BadImage, - InvalidOperation, - EntryPointNotFound, - GenericException - }; - -public class NativeLibraryTest -{ - static string CurrentTest; - static bool Verbose = false; - - public static int Main() - { - bool success = true; - - Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); - string testBinDir = Path.GetDirectoryName(assembly.Location); - string libName; - IntPtr handle; - - // ----------------------------------------------- - // Simple LoadLibrary() API Tests - // ----------------------------------------------- - - // Calls on correct full-path to native lib - libName = Path.Combine(testBinDir, GetNativeLibraryName()); - success &= EXPECT(LoadLibrarySimple(libName)); - success &= EXPECT(TryLoadLibrarySimple(libName)); - - // Calls on non-existant file - libName = Path.Combine(testBinDir, "notfound"); - success &= EXPECT(LoadLibrarySimple(libName), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure); - - // Calls on an invalid file - libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); - success &= EXPECT(LoadLibrarySimple(libName), - (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound); - success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure); - - // Calls on null input - libName = null; - success &= EXPECT(LoadLibrarySimple(libName), TestResult.ArgumentNull); - success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ArgumentNull); - - // ----------------------------------------------- - // Advanced LoadLibrary() API Tests - // ----------------------------------------------- - - // Advanced LoadLibrary() API Tests - // Calls on correct full-path to native lib - libName = Path.Combine(testBinDir, GetNativeLibraryName()); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); - - // Calls on non-existant file - libName = Path.Combine(testBinDir, "notfound"); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure); - - // Calls on an invalid file - libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); - // The VM can only distinguish BadImageFormatException from DllNotFoundException on Windows. - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), - (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure); - - // Calls on just Native Library name - libName = GetNativeLibraryPlainName(); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); - - // Calls on Native Library name with correct prefix-suffix - libName = GetNativeLibraryName(); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); - - // Calls on full path without prefix-siffix - libName = Path.Combine(testBinDir, GetNativeLibraryPlainName()); - // DllImport doesn't add a prefix if the name is preceeded by a path specification. - // Windows only needs a suffix, but Linux and Mac need both prefix and suffix - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), - (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), - (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.ReturnFailure); - - if (TestLibrary.Utilities.IsWindows) - { - libName = GetWin32LibName(); - - // Calls on a valid library from System32 directory - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32)); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32)); - - // Calls on a valid library from application directory - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.ReturnFailure); - } - - // Calls with null libName input - success &= EXPECT(LoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull); - success &= EXPECT(TryLoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull); - - // Calls with null assembly - libName = GetNativeLibraryPlainName(); - success &= EXPECT(LoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull); - success &= EXPECT(TryLoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull); - - // Ensure that a lib is not picked up from current directory when - // a different full-path is specified. - libName = Path.Combine(testBinDir, Path.Combine("lib", GetNativeLibraryPlainName())); - success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.DllNotFound); - success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.ReturnFailure); - - // ----------------------------------------------- - // FreeLibrary Tests - // ----------------------------------------------- - - libName = Path.Combine(testBinDir, GetNativeLibraryName()); - handle = Marshal.LoadLibrary(libName); - - // Valid Free - success &= EXPECT(FreeLibrary(handle)); - - // Double Free - success &= EXPECT(FreeLibrary(handle), TestResult.InvalidOperation); - - // Null Free - success &= EXPECT(FreeLibrary(IntPtr.Zero)); - - // ----------------------------------------------- - // GetLibraryExport Tests - // ----------------------------------------------- - libName = Path.Combine(testBinDir, GetNativeLibraryName()); - handle = Marshal.LoadLibrary(libName); - - // Valid Call (with some hard-coded name mangling) - success &= EXPECT(GetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum")); - success &= EXPECT(TryGetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum")); - - // Call with null handle - success &= EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); - success &= EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); - - // Call with null string - success &= EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull); - success &= EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull); - - // Call with wrong string - success &= EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound); - success &= EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure); - - Marshal.FreeLibrary(handle); - - return (success) ? 100 : -100; - } - - static string GetNativeLibraryPlainName() - { - return "NativeLibrary"; - } - - static string GetWin32LibName() - { - return "msi.dll"; - } - - static string GetNativeLibraryName() - { - string baseName = GetNativeLibraryPlainName(); - - if (TestLibrary.Utilities.IsWindows) - { - return baseName + ".dll"; - } - if (TestLibrary.Utilities.IsLinux) - { - return "lib" + baseName + ".so"; - } - if (TestLibrary.Utilities.IsMacOSX) - { - return "lib" + baseName + ".dylib"; - } - - return "ERROR"; - } - - static bool EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success) - { - if (actualValue == expectedValue) - { - if (Verbose) - Console.WriteLine(String.Format("{0} : {1} : [OK]", CurrentTest, actualValue)); - return true; - } - else - { - Console.WriteLine(String.Format(" {0} : {1} : [FAIL]", CurrentTest, actualValue)); - return false; - } - } - - static TestResult Run (Func test) - { - - TestResult result; - - try - { - result = test(); - } - catch (ArgumentNullException e) - { - return TestResult.ArgumentNull; - } - catch (ArgumentException e) - { - return TestResult.ArgumentBad; - } - catch (DllNotFoundException e) - { - return TestResult.DllNotFound; - } - catch (BadImageFormatException e) - { - return TestResult.BadImage; - } - catch (InvalidOperationException e) - { - return TestResult.InvalidOperation; - } - catch (EntryPointNotFoundException e) - { - return TestResult.EntryPointNotFound; - } - catch (Exception e) - { - //Console.WriteLine(e.ToString()); - return TestResult.GenericException; - } - - return result; - } - - static TestResult LoadLibrarySimple(string libPath) - { - CurrentTest = String.Format("LoadLibrary({0})", libPath); - - IntPtr handle = IntPtr.Zero; - - TestResult result = Run(() => { - handle = Marshal.LoadLibrary(libPath); - if (handle == IntPtr.Zero) - return TestResult.ReturnNull; - return TestResult.Success; - }); - - Marshal.FreeLibrary(handle); - - return result; - } - - static TestResult TryLoadLibrarySimple(string libPath) - { - CurrentTest = String.Format("TryLoadLibrary({0})", libPath); - - IntPtr handle = IntPtr.Zero; - - TestResult result = Run(() => { - bool success = Marshal.TryLoadLibrary(libPath, out handle); - if(!success) - return TestResult.ReturnFailure; - if (handle == null) - return TestResult.ReturnNull; - return TestResult.Success; - }); - - Marshal.FreeLibrary(handle); - - return result; - } - - - static TestResult LoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath) - { - CurrentTest = String.Format("LoadLibrary({0}, {1}, {2})", libName, assembly, searchPath); - - IntPtr handle = IntPtr.Zero; - - TestResult result = Run(() => { - handle = Marshal.LoadLibrary(libName, assembly, searchPath); - if (handle == IntPtr.Zero) - return TestResult.ReturnNull; - return TestResult.Success; - }); - - Marshal.FreeLibrary(handle); - - return result; - } - - static TestResult TryLoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath) - { - CurrentTest = String.Format("TryLoadLibrary({0}, {1}, {2})", libName, assembly, searchPath); - - IntPtr handle = IntPtr.Zero; - - TestResult result = Run(() => { - bool success = Marshal.TryLoadLibrary(libName, assembly, searchPath, out handle); - if (!success) - return TestResult.ReturnFailure; - if (handle == IntPtr.Zero) - return TestResult.ReturnNull; - return TestResult.Success; - }); - - Marshal.FreeLibrary(handle); - - return result; - } - - static TestResult FreeLibrary(IntPtr handle) - { - CurrentTest = String.Format("FreeLibrary({0})", handle); - - return Run(() => { - Marshal.FreeLibrary(handle); - return TestResult.Success; - }); - } - - static TestResult GetLibraryExport(IntPtr handle, string name) - { - CurrentTest = String.Format("GetLibraryExport({0}, {1})", handle, name); - - return Run(() => { - IntPtr address = Marshal.GetLibraryExport(handle, name); - if (address == null) - return TestResult.ReturnNull; - if (RunExportedFunction(address, 1, 1) != 2) - return TestResult.IncorrectEvaluation; - return TestResult.Success; - }); - } - - static TestResult TryGetLibraryExport(IntPtr handle, string name) - { - CurrentTest = String.Format("TryGetLibraryExport({0}, {1})", handle, name); - - return Run(() => { - IntPtr address = IntPtr.Zero; - bool success = Marshal.TryGetLibraryExport(handle, name, out address); - if (!success) - return TestResult.ReturnFailure; - if (address == null) - return TestResult.ReturnNull; - if (RunExportedFunction(address, 1, 1) != 2) - return TestResult.IncorrectEvaluation; - return TestResult.Success; - }); - } - - [DllImport("NativeLibrary")] - static extern int RunExportedFunction(IntPtr address, int arg1, int arg2); -} diff --git a/tests/src/Interop/MarshalAPI/NativeLibrary/CMakeLists.txt b/tests/src/Interop/NativeLibrary/CMakeLists.txt similarity index 100% rename from tests/src/Interop/MarshalAPI/NativeLibrary/CMakeLists.txt rename to tests/src/Interop/NativeLibrary/CMakeLists.txt diff --git a/tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibrary.cpp b/tests/src/Interop/NativeLibrary/NativeLibrary.cpp similarity index 100% rename from tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibrary.cpp rename to tests/src/Interop/NativeLibrary/NativeLibrary.cpp diff --git a/tests/src/Interop/NativeLibrary/NativeLibraryTests.cs b/tests/src/Interop/NativeLibrary/NativeLibraryTests.cs new file mode 100644 index 000000000000..19eb125c32c6 --- /dev/null +++ b/tests/src/Interop/NativeLibrary/NativeLibraryTests.cs @@ -0,0 +1,395 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using TestLibrary; + +using Console = Internal.Console; + +enum TestResult { + Success, + ReturnFailure, + ReturnNull, + IncorrectEvaluation, + ArgumentNull, + ArgumentBad, + DllNotFound, + BadImage, + InvalidOperation, + EntryPointNotFound, + GenericException + }; + +public class NativeLibraryTest +{ + static string CurrentTest; + static bool Verbose = false; + + public static int Main() + { + bool success = true; + + Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); + string testBinDir = Path.GetDirectoryName(assembly.Location); + string libName; + IntPtr handle; + + try + { + // ----------------------------------------------- + // Simple LoadLibrary() API Tests + // ----------------------------------------------- + + // Calls on correct full-path to native lib + libName = Path.Combine(testBinDir, GetNativeLibraryName()); + success &= EXPECT(LoadLibrarySimple(libName)); + success &= EXPECT(TryLoadLibrarySimple(libName)); + + // Calls on non-existant file + libName = Path.Combine(testBinDir, "notfound"); + success &= EXPECT(LoadLibrarySimple(libName), TestResult.DllNotFound); + success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure); + + // Calls on an invalid file + libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); + success &= EXPECT(LoadLibrarySimple(libName), + (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound); + success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ReturnFailure); + + // Calls on null input + libName = null; + success &= EXPECT(LoadLibrarySimple(libName), TestResult.ArgumentNull); + success &= EXPECT(TryLoadLibrarySimple(libName), TestResult.ArgumentNull); + + // ----------------------------------------------- + // Advanced LoadLibrary() API Tests + // ----------------------------------------------- + + // Advanced LoadLibrary() API Tests + // Calls on correct full-path to native lib + libName = Path.Combine(testBinDir, GetNativeLibraryName()); + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); + + // Calls on non-existant file + libName = Path.Combine(testBinDir, "notfound"); + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), TestResult.DllNotFound); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure); + + // Calls on an invalid file + libName = Path.Combine(testBinDir, "NativeLibrary.cpp"); + // The VM can only distinguish BadImageFormatException from DllNotFoundException on Windows. + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), + (TestLibrary.Utilities.IsWindows) ? TestResult.BadImage : TestResult.DllNotFound); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), TestResult.ReturnFailure); + + // Calls on just Native Library name + libName = GetNativeLibraryPlainName(); + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); + + // Calls on Native Library name with correct prefix-suffix + libName = GetNativeLibraryName(); + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null)); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null)); + + // Calls on full path without prefix-siffix + libName = Path.Combine(testBinDir, GetNativeLibraryPlainName()); + // DllImport doesn't add a prefix if the name is preceeded by a path specification. + // Windows only needs a suffix, but Linux and Mac need both prefix and suffix + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, null), + (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.DllNotFound); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, null), + (TestLibrary.Utilities.IsWindows) ? TestResult.Success : TestResult.ReturnFailure); + + if (TestLibrary.Utilities.IsWindows) + { + libName = GetWin32LibName(); + + // Calls on a valid library from System32 directory + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32)); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.System32)); + + // Calls on a valid library from application directory + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.DllNotFound); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.ApplicationDirectory), TestResult.ReturnFailure); + } + + // Calls with null libName input + success &= EXPECT(LoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull); + success &= EXPECT(TryLoadLibraryAdvanced(null, assembly, null), TestResult.ArgumentNull); + + // Calls with null assembly + libName = GetNativeLibraryPlainName(); + success &= EXPECT(LoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull); + success &= EXPECT(TryLoadLibraryAdvanced(libName, null, null), TestResult.ArgumentNull); + + // Ensure that a lib is not picked up from current directory when + // a different full-path is specified. + libName = Path.Combine(testBinDir, Path.Combine("lib", GetNativeLibraryPlainName())); + success &= EXPECT(LoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.DllNotFound); + success &= EXPECT(TryLoadLibraryAdvanced(libName, assembly, DllImportSearchPath.AssemblyDirectory), TestResult.ReturnFailure); + + // ----------------------------------------------- + // FreeLibrary Tests + // ----------------------------------------------- + + libName = Path.Combine(testBinDir, GetNativeLibraryName()); + handle = NativeLibrary.Load(libName); + + // Valid Free + success &= EXPECT(FreeLibrary(handle)); + + // Double Free + success &= EXPECT(FreeLibrary(handle), TestResult.InvalidOperation); + + // Null Free + success &= EXPECT(FreeLibrary(IntPtr.Zero)); + + // ----------------------------------------------- + // GetLibraryExport Tests + // ----------------------------------------------- + libName = Path.Combine(testBinDir, GetNativeLibraryName()); + handle = NativeLibrary.Load(libName); + + // Valid Call (with some hard-coded name mangling) + success &= EXPECT(GetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum")); + success &= EXPECT(TryGetLibraryExport(handle, TestLibrary.Utilities.IsX86 ? "_NativeSum@8" : "NativeSum")); + + // Call with null handle + success &= EXPECT(GetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); + success &= EXPECT(TryGetLibraryExport(IntPtr.Zero, "NativeSum"), TestResult.ArgumentNull); + + // Call with null string + success &= EXPECT(GetLibraryExport(handle, null), TestResult.ArgumentNull); + success &= EXPECT(TryGetLibraryExport(handle, null), TestResult.ArgumentNull); + + // Call with wrong string + success &= EXPECT(GetLibraryExport(handle, "NonNativeSum"), TestResult.EntryPointNotFound); + success &= EXPECT(TryGetLibraryExport(handle, "NonNativeSum"), TestResult.ReturnFailure); + + NativeLibrary.Free(handle); + } + catch (Exception e) + { + // Catch any exceptions in NativeLibrary calls directly within this function. + // These calls are used to setup the environment for tests that follow, and are not expected to fail. + // If they do fail (ex: incorrect build environment) fail with an error code, rather than segmentation fault. + Console.WriteLine(String.Format("Unhandled exception {0}", e)); + success = false; + } + + return (success) ? 100 : -100; + } + + static string GetNativeLibraryPlainName() + { + return "NativeLibrary"; + } + + static string GetWin32LibName() + { + return "msi.dll"; + } + + static string GetNativeLibraryName() + { + string baseName = GetNativeLibraryPlainName(); + + if (TestLibrary.Utilities.IsWindows) + { + return baseName + ".dll"; + } + if (TestLibrary.Utilities.IsLinux) + { + return "lib" + baseName + ".so"; + } + if (TestLibrary.Utilities.IsMacOSX) + { + return "lib" + baseName + ".dylib"; + } + + return "ERROR"; + } + + static bool EXPECT(TestResult actualValue, TestResult expectedValue = TestResult.Success) + { + if (actualValue == expectedValue) + { + if (Verbose) + Console.WriteLine(String.Format("{0} : {1} : [OK]", CurrentTest, actualValue)); + return true; + } + else + { + Console.WriteLine(String.Format(" {0} : {1} : [FAIL]", CurrentTest, actualValue)); + return false; + } + } + + static TestResult Run (Func test) + { + + TestResult result; + + try + { + result = test(); + } + catch (ArgumentNullException e) + { + return TestResult.ArgumentNull; + } + catch (ArgumentException e) + { + return TestResult.ArgumentBad; + } + catch (DllNotFoundException e) + { + return TestResult.DllNotFound; + } + catch (BadImageFormatException e) + { + return TestResult.BadImage; + } + catch (InvalidOperationException e) + { + return TestResult.InvalidOperation; + } + catch (EntryPointNotFoundException e) + { + return TestResult.EntryPointNotFound; + } + catch (Exception e) + { + //Console.WriteLine(e.ToString()); + return TestResult.GenericException; + } + + return result; + } + + static TestResult LoadLibrarySimple(string libPath) + { + CurrentTest = String.Format("LoadLibrary({0})", libPath); + + IntPtr handle = IntPtr.Zero; + + TestResult result = Run(() => { + handle = NativeLibrary.Load(libPath); + if (handle == IntPtr.Zero) + return TestResult.ReturnNull; + return TestResult.Success; + }); + + NativeLibrary.Free(handle); + + return result; + } + + static TestResult TryLoadLibrarySimple(string libPath) + { + CurrentTest = String.Format("TryLoadLibrary({0})", libPath); + + IntPtr handle = IntPtr.Zero; + + TestResult result = Run(() => { + bool success = NativeLibrary.TryLoad(libPath, out handle); + if(!success) + return TestResult.ReturnFailure; + if (handle == null) + return TestResult.ReturnNull; + return TestResult.Success; + }); + + NativeLibrary.Free(handle); + + return result; + } + + + static TestResult LoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath) + { + CurrentTest = String.Format("LoadLibrary({0}, {1}, {2})", libName, assembly, searchPath); + + IntPtr handle = IntPtr.Zero; + + TestResult result = Run(() => { + handle = NativeLibrary.Load(libName, assembly, searchPath); + if (handle == IntPtr.Zero) + return TestResult.ReturnNull; + return TestResult.Success; + }); + + NativeLibrary.Free(handle); + + return result; + } + + static TestResult TryLoadLibraryAdvanced(string libName, Assembly assembly, DllImportSearchPath? searchPath) + { + CurrentTest = String.Format("TryLoadLibrary({0}, {1}, {2})", libName, assembly, searchPath); + + IntPtr handle = IntPtr.Zero; + + TestResult result = Run(() => { + bool success = NativeLibrary.TryLoad(libName, assembly, searchPath, out handle); + if (!success) + return TestResult.ReturnFailure; + if (handle == IntPtr.Zero) + return TestResult.ReturnNull; + return TestResult.Success; + }); + + NativeLibrary.Free(handle); + + return result; + } + + static TestResult FreeLibrary(IntPtr handle) + { + CurrentTest = String.Format("FreeLibrary({0})", handle); + + return Run(() => { + NativeLibrary.Free(handle); + return TestResult.Success; + }); + } + + static TestResult GetLibraryExport(IntPtr handle, string name) + { + CurrentTest = String.Format("GetLibraryExport({0}, {1})", handle, name); + + return Run(() => { + IntPtr address = NativeLibrary.GetExport(handle, name); + if (address == null) + return TestResult.ReturnNull; + if (RunExportedFunction(address, 1, 1) != 2) + return TestResult.IncorrectEvaluation; + return TestResult.Success; + }); + } + + static TestResult TryGetLibraryExport(IntPtr handle, string name) + { + CurrentTest = String.Format("TryGetLibraryExport({0}, {1})", handle, name); + + return Run(() => { + IntPtr address = IntPtr.Zero; + bool success = NativeLibrary.TryGetExport(handle, name, out address); + if (!success) + return TestResult.ReturnFailure; + if (address == null) + return TestResult.ReturnNull; + if (RunExportedFunction(address, 1, 1) != 2) + return TestResult.IncorrectEvaluation; + return TestResult.Success; + }); + } + + [DllImport("NativeLibrary")] + static extern int RunExportedFunction(IntPtr address, int arg1, int arg2); +} diff --git a/tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibraryTests.csproj b/tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj similarity index 95% rename from tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibraryTests.csproj rename to tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj index d3d7eb2be78c..9f01b9f70c4a 100644 --- a/tests/src/Interop/MarshalAPI/NativeLibrary/NativeLibraryTests.csproj +++ b/tests/src/Interop/NativeLibrary/NativeLibraryTests.csproj @@ -35,7 +35,7 @@ - + {c8c0dc74-fac4-45b1-81fe-70c4808366e0} CoreCLRTestLibrary