// Copyright 2015 gRPC authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace Unix.Terminal; /// /// Represents a dynamically loaded unmanaged library in a (partially) platform independent manner. First, the /// native library is loaded using dlopen (on Unix systems) or using LoadLibrary (on Windows). dlsym or GetProcAddress /// are then used to obtain symbol addresses. Marshal.GetDelegateForFunctionPointer transforms the addresses /// into delegates to native methods. See /// http://stackoverflow.com/questions/13461989/p-invoke-to-dynamically-loaded-library-on-mono. /// internal class UnmanagedLibrary { public readonly string LibraryPath; public nint NativeLibraryHandle { get; } // // if isFullPath is set to true, the provided array of libraries are full paths // and are tested for the file existing, otherwise the file is merely the name // of the shared library that we pass to dlopen // public UnmanagedLibrary (string [] libraryPathAlternatives, bool isFullPath) { if (isFullPath) { foreach (string path in libraryPathAlternatives) { if (File.Exists (path)) { LibraryPath = path; break; } } if (LibraryPath is null) throw new FileNotFoundException ($"Error loading native library. Not found in any of the possible locations: {string.Join (",", libraryPathAlternatives)}"); NativeLibraryHandle = NativeLibrary.Load (LibraryPath); } else { foreach (string lib in libraryPathAlternatives) { NativeLibraryHandle = NativeLibrary.Load (lib); if (NativeLibraryHandle != nint.Zero) { LibraryPath = lib; break; } } } if (NativeLibraryHandle == nint.Zero) { throw new IOException ($"Error loading native library \"{string.Join (", ", libraryPathAlternatives)}\""); } } /// Loads symbol in a platform specific way. /// /// public nint LoadSymbol (string symbolName) { return NativeLibrary.GetExport(NativeLibraryHandle, symbolName); } public T GetNativeMethodDelegate (string methodName) where T : class { nint ptr = LoadSymbol (methodName); if (ptr == nint.Zero) { throw new MissingMethodException (string.Format ("The native method \"{0}\" does not exist", methodName)); } return Marshal.GetDelegateForFunctionPointer (ptr); // non-generic version is obsolete } }