diff --git a/Dalamud/Hooking/Hook.cs b/Dalamud/Hooking/Hook.cs index a2c4ec3f6..83a8646af 100644 --- a/Dalamud/Hooking/Hook.cs +++ b/Dalamud/Hooking/Hook.cs @@ -2,126 +2,143 @@ using System; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using EasyHook; -namespace Dalamud.Hooking { +namespace Dalamud.Hooking +{ /// /// Manages a hook which can be used to intercept a call to native function. /// This class is basically a thin wrapper around the LocalHook type to provide helper functions. /// /// Delegate type to represents a function prototype. This must be the same prototype as original function do. - public sealed class Hook : IDisposable, IDalamudHook where T : Delegate { + public sealed class Hook : IDisposable, IDalamudHook where T : Delegate + { private readonly IntPtr address; private readonly T original; - + private readonly LocalHook hookInfo; /// - /// A memory address of the target function. + /// Initializes a new instance of the class. + /// Hook is not activated until Enable() method is called. + /// + /// A memory address to install a hook. + /// Callback function. Delegate must have a same original function prototype. + /// A callback object which can be accessed within the detour. + public Hook(IntPtr address, Delegate detour, object callbackParam = null) + { + this.hookInfo = LocalHook.Create(address, detour, callbackParam); // Installs a hook here + this.address = address; + this.original = Marshal.GetDelegateForFunctionPointer(this.hookInfo.HookBypassAddress); + HookInfo.TrackedHooks.Add(new HookInfo() { Delegate = detour, Hook = this, Assembly = Assembly.GetCallingAssembly() }); + } + + /// + /// Gets a memory address of the target function. /// /// Hook is already disposed. - public IntPtr Address { + public IntPtr Address + { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { - CheckDisposed(); + get + { + this.CheckDisposed(); return this.address; } } /// - /// A delegate function that can be used to call the actual function as if function is not hooked yet. + /// Gets a delegate function that can be used to call the actual function as if function is not hooked yet. /// - /// /// Hook is already disposed. - public T Original { + public T Original + { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { - CheckDisposed(); + get + { + this.CheckDisposed(); return this.original; } } - /// - /// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function. Hook is not activated until Enable() method is called. + /// Gets a value indicating whether or not the hook is enabled. /// - /// A name of the module currently loaded in the memory. (e.g. ws2_32.dll) - /// A name of the exported function name (e.g. send) - /// Callback function. Delegate must have a same original function prototype. - /// A callback object which can be accessed within the detour. - /// - public static Hook FromSymbol(string moduleName, string exportName, Delegate detour, object callbackParam = null) { - // Get a function address from the symbol name. - var address = LocalHook.GetProcAddress(moduleName, exportName); - - return new Hook(address, detour, callbackParam); - } - - /// - /// Createss a hook. Hook is not activated until Enable() method is called. - /// - /// A memory address to install a hook. - /// Callback function. Delegate must have a same original function prototype. - /// A callback object which can be accessed within the detour. - public Hook(IntPtr address, Delegate detour, object callbackParam = null) { - this.hookInfo = LocalHook.Create(address, detour, callbackParam); // Installs a hook here - this.address = address; - this.original = Marshal.GetDelegateForFunctionPointer(this.hookInfo.HookBypassAddress); - HookInfo.TrackedHooks.Add(new HookInfo() { Delegate = detour, Hook = this, Assembly = Assembly.GetCallingAssembly()}); - } - - /// - /// Remove a hook from the current process. - /// - public void Dispose() { - if (this.IsDisposed) { - return; - } - - this.hookInfo.Dispose(); - - this.IsDisposed = true; - } - - /// - /// Starts intercepting a call to the function. - /// - public void Enable() { - CheckDisposed(); - - this.hookInfo.ThreadACL.SetExclusiveACL(null); - } - - /// - /// Stops intercepting a call to the function. - /// - public void Disable() { - CheckDisposed(); - - this.hookInfo.ThreadACL.SetInclusiveACL(null); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void CheckDisposed() { - if (this.IsDisposed) { - throw new ObjectDisposedException("Hook is already disposed."); - } - } - - /// - /// Check if the hook is enabled. - /// - public bool IsEnabled { - get { - CheckDisposed(); + public bool IsEnabled + { + get + { + this.CheckDisposed(); return this.hookInfo.ThreadACL.IsExclusive; } } /// - /// Check if the hook has been disposed + /// Gets a value indicating whether or not the hook has been disposed. /// public bool IsDisposed { get; private set; } + + /// + /// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function. + /// Hook is not activated until Enable() method is called. + /// + /// A name of the module currently loaded in the memory. (e.g. ws2_32.dll). + /// A name of the exported function name (e.g. send). + /// Callback function. Delegate must have a same original function prototype. + /// A callback object which can be accessed within the detour. + /// The hook with the supplied parameters. + public static Hook FromSymbol(string moduleName, string exportName, Delegate detour, object callbackParam = null) + { + // Get a function address from the symbol name. + var address = LocalHook.GetProcAddress(moduleName, exportName); + + return new Hook(address, detour, callbackParam); + } + + /// + /// Remove a hook from the current process. + /// + public void Dispose() + { + if (this.IsDisposed) + { + return; + } + + this.hookInfo.Dispose(); + + this.IsDisposed = true; + } + + /// + /// Starts intercepting a call to the function. + /// + public void Enable() + { + this.CheckDisposed(); + + this.hookInfo.ThreadACL.SetExclusiveACL(null); + } + + /// + /// Stops intercepting a call to the function. + /// + public void Disable() + { + this.CheckDisposed(); + + this.hookInfo.ThreadACL.SetInclusiveACL(null); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CheckDisposed() + { + if (this.IsDisposed) + { + throw new ObjectDisposedException("Hook is already disposed."); + } + } } }