From 0d2d1f76b6601d33c518905e84287b1e59852c00 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 27 Jul 2014 23:07:11 +0100 Subject: [PATCH] Adding Linux native dll loading Former-commit-id: 5993e028f751f80aaa9fe82a33831a7fef57e02b --- .../Configuration/NativeBinaryFactory.cs | 11 ++++++- .../Configuration/NativeMethods.cs | 28 ++++++++++++++++++ .../images/output/rotate.jpg | Bin 0 -> 26227 bytes 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/ImageProcessorConsole/images/output/rotate.jpg diff --git a/src/ImageProcessor/Configuration/NativeBinaryFactory.cs b/src/ImageProcessor/Configuration/NativeBinaryFactory.cs index 741da61e24..e210aa0362 100644 --- a/src/ImageProcessor/Configuration/NativeBinaryFactory.cs +++ b/src/ImageProcessor/Configuration/NativeBinaryFactory.cs @@ -94,7 +94,7 @@ namespace ImageProcessor.Configuration Assembly assembly = Assembly.GetExecutingAssembly(); string targetBasePath = new Uri(assembly.Location).LocalPath; string targetPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + name)); - + // Copy the file across if necessary. FileInfo fileInfo = new FileInfo(targetPath); bool rewrite = true; @@ -122,8 +122,13 @@ namespace ImageProcessor.Configuration try { +#if !__MonoCS__ // Load the binary into memory. pointer = NativeMethods.LoadLibrary(targetPath); +#else + // Load the binary into memory. The second parameter forces it to load immediately. + pointer = NativeMethods.dlopen(targetPath, 2); +#endif } catch (Exception ex) { @@ -187,9 +192,13 @@ namespace ImageProcessor.Configuration { IntPtr pointer = nativeBinary.Value; +#if !__MonoCS__ // According to http://stackoverflow.com/a/2445558/427899 you need to call this twice. NativeMethods.FreeLibrary(pointer); NativeMethods.FreeLibrary(pointer); +#else + NativeMethods.dlclose(pointer); +#endif } } } diff --git a/src/ImageProcessor/Configuration/NativeMethods.cs b/src/ImageProcessor/Configuration/NativeMethods.cs index a20b5a86f4..6c1ab98055 100644 --- a/src/ImageProcessor/Configuration/NativeMethods.cs +++ b/src/ImageProcessor/Configuration/NativeMethods.cs @@ -40,5 +40,33 @@ namespace ImageProcessor.Configuration /// If the function succeeds, the return value is nonzero; otherwise zero. [DllImport("kernel32", CharSet = CharSet.Auto)] public static extern bool FreeLibrary(IntPtr hModule); + + /// + /// Loads the specified module into the address space of the calling process. + /// The specified module may cause other modules to be loaded. + /// + /// + /// The name of the module. This can be either a library module or + /// an executable module. + /// + /// + /// The flag indicating whether to load the library immediately or lazily. + /// + /// + /// If the function succeeds, the return value is a handle to the module; otherwise null. + /// + [System.Runtime.InteropServices.DllImport("libdl")] + public static extern IntPtr dlopen(string libname, int flags); + + /// + /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. + /// When the reference count reaches zero, the module is unloaded from the address space of the calling + /// process and the handle is no longer valid. + /// + /// A handle to the loaded library module. + /// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle. + /// If the function succeeds, the return value is nonzero; otherwise zero. + [System.Runtime.InteropServices.DllImport("libdl")] + public static extern int dlclose(IntPtr hModule); } } diff --git a/src/ImageProcessorConsole/images/output/rotate.jpg b/src/ImageProcessorConsole/images/output/rotate.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45c192cd422f3cd55f26d6228d15f75ffc467851 GIT binary patch literal 26227 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 literal 0 HcmV?d00001