using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace DelftTools.Utils.Interop
{
public abstract class NativeLibrary : IDisposable
{
private IntPtr lib = IntPtr.Zero;
protected NativeLibrary(string fileName)
{
lib = LoadLibrary(fileName);
}
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);
//private: use SwitchDllSearchDirectory with a using instead
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern void SetDllDirectory(string lpPathName);
public static string GetDllDirectory()
{
var tmp = new StringBuilder(4096);
GetDllDirectory(4096, tmp);
return tmp.ToString();
}
///
/// Call this from a static constructor in a class that has DllImport external methods. This
/// method uses LoadLibrary to load the correct dll for the current process (32bit or 64bit)
/// before DllImport has the chance to resolve the external calls. As long as the dll name is
/// the same this works.
///
/// The dll file to load.
/// The directory where x64 and x86 are situated.
public static void LoadNativeDllForCurrentPlatform(string dllFileName, string baseDirectory)
{
var platform = Environment.Is64BitProcess ? "x64" : "x86";
var nativeDirectory = Path.Combine(baseDirectory, platform);
LoadNativeDll(dllFileName, nativeDirectory);
}
///
/// Call this from a static constructor in a class that has DllImport external methods. This
/// method uses LoadLibrary to load the correct dll for the current process (32bit or 64bit)
/// before DllImport has the chance to resolve the external calls. As long as the dll name is
/// the same this works.
///
/// The dll file to load.
/// The directory to load the dll from.
public static void LoadNativeDll(string dllFileName, string directory)
{
using (SwitchDllSearchDirectory(directory))
{
// attempt to load the library
var ptr = LoadLibrary(dllFileName);
if (ptr == IntPtr.Zero)
{
var error = Marshal.GetLastWin32Error();
var exception = new Win32Exception(error);
throw new FileNotFoundException(
string.Format("Could not find / load {3}.{2}Error: {4} - {0}{2}File: {5}\\{1}",
exception.Message, dllFileName, Environment.NewLine, dllFileName, error, directory));
}
}
}
public static IDisposable SwitchDllSearchDirectory(string dllDirectory)
{
return new SwitchDllSearchDirectoryHelper(dllDirectory);
}
public void Dispose()
{
if (lib == IntPtr.Zero)
{
return;
}
FreeLibrary(lib);
lib = IntPtr.Zero;
}
protected IntPtr Library
{
get
{
if (lib == IntPtr.Zero)
{
throw new InvalidOperationException("Plug-in library is not loaded");
}
return lib;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetDllDirectory(int nBufferLength, StringBuilder lpPathName);
~NativeLibrary()
{
Dispose();
}
private class SwitchDllSearchDirectoryHelper : IDisposable // ???
{
private readonly string oldDirectory;
public SwitchDllSearchDirectoryHelper(string dllDirectory)
{
oldDirectory = GetDllDirectory();
SetDllDirectory(dllDirectory);
}
public void Dispose()
{
SetDllDirectory(oldDirectory);
}
}
}
}