using System; using System.IO; using System.Runtime.InteropServices; namespace BizHawk.Common { public class InstanceDll : IDisposable, IImportResolver { [DllImport("kernel32.dll")] public static extern UInt32 GetLastError(); public InstanceDll(string dllPath) { // copy the dll to a temp directory var path = TempFileCleaner.GetTempFilename(string.Format("{0}", Path.GetFileNameWithoutExtension(dllPath)),".dll",false); using (var stream = new FileStream(path, FileMode.Create, System.Security.AccessControl.FileSystemRights.FullControl, FileShare.ReadWrite | FileShare.Delete, 4 * 1024, FileOptions.None)) using (var sdll = File.OpenRead(dllPath)) sdll.CopyTo(stream); // try to locate dlls in the current directory (for libretro cores) // this isnt foolproof but its a little better than nothing // setting PWD temporarily doesnt work. that'd be ideal since it supposedly gets searched early on, // but i guess not with SetDllDirectory in effect var envpath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); try { string envpath_new = Path.GetDirectoryName(path) + ";" + envpath; Environment.SetEnvironmentVariable("PATH", envpath_new, EnvironmentVariableTarget.Process); _hModule = LoadLibrary(path); //consider using LoadLibraryEx instead of shenanigans? if (_hModule == IntPtr.Zero) { var lastError = GetLastError(); throw new InvalidOperationException($"Failed to load plugin {path}, error code: 0x{lastError:X}"); } var newfname = TempFileCleaner.RenameTempFilenameForDelete(path); File.Move(path, newfname); } finally { Environment.SetEnvironmentVariable("PATH", envpath, EnvironmentVariableTarget.Process); } } [Flags] enum LoadLibraryFlags : uint { DONT_RESOLVE_DLL_REFERENCES = 0x00000001, LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, LOAD_LIBRARY_AS_DATAFILE = 0x00000002, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 } [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr LoadLibrary(string dllToLoad); [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); [DllImport("kernel32.dll")] static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); [DllImport("kernel32.dll")] static extern bool FreeLibrary(IntPtr hModule); public IntPtr GetProcAddress(string procName) { return GetProcAddress(_hModule, procName); } public IntPtr HModule { get { return _hModule; } } IntPtr IImportResolver.Resolve(string entryPoint) { return GetProcAddress(entryPoint); } public void Dispose() { if (_hModule != IntPtr.Zero) { FreeLibrary(_hModule); _hModule = IntPtr.Zero; } } private IntPtr _hModule; } }