mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-01 05:13:40 +01:00
feat: IHookProvider service, no more static hook creation
This commit is contained in:
parent
b96ef30c20
commit
e1da238cb5
5 changed files with 238 additions and 34 deletions
|
|
@ -12,7 +12,7 @@ namespace Dalamud.Hooking;
|
|||
/// This class is basically a thin wrapper around the LocalHook type to provide helper functions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Delegate type to represents a function prototype. This must be the same prototype as original function do.</typeparam>
|
||||
public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
||||
public abstract class Hook<T> : IDalamudHook where T : Delegate
|
||||
{
|
||||
#pragma warning disable SA1310
|
||||
// ReSharper disable once InconsistentNaming
|
||||
|
|
@ -70,6 +70,27 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
|
||||
/// <inheritdoc/>
|
||||
public virtual string BackendName => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Remove a hook from the current process.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (this.IsDisposed)
|
||||
return;
|
||||
|
||||
this.IsDisposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts intercepting a call to the function.
|
||||
/// </summary>
|
||||
public virtual void Enable() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Stops intercepting a call to the function.
|
||||
/// </summary>
|
||||
public virtual void Disable() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hook by rewriting import table address.
|
||||
|
|
@ -77,7 +98,7 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
/// <param name="address">A memory address to install a hook.</param>
|
||||
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
|
||||
/// <returns>The hook with the supplied parameters.</returns>
|
||||
public static unsafe Hook<T> FromFunctionPointerVariable(IntPtr address, T detour)
|
||||
internal static Hook<T> FromFunctionPointerVariable(IntPtr address, T detour)
|
||||
{
|
||||
return new FunctionPointerVariableHook<T>(address, detour, Assembly.GetCallingAssembly());
|
||||
}
|
||||
|
|
@ -91,7 +112,7 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
/// <param name="hintOrOrdinal">Hint or ordinal. 0 to unspecify.</param>
|
||||
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
|
||||
/// <returns>The hook with the supplied parameters.</returns>
|
||||
public static unsafe Hook<T> FromImport(ProcessModule? module, string moduleName, string functionName, uint hintOrOrdinal, T detour)
|
||||
internal static unsafe Hook<T> FromImport(ProcessModule? module, string moduleName, string functionName, uint hintOrOrdinal, T detour)
|
||||
{
|
||||
module ??= Process.GetCurrentProcess().MainModule;
|
||||
if (module == null)
|
||||
|
|
@ -156,7 +177,7 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
/// <param name="exportName">A name of the exported function name (e.g. send).</param>
|
||||
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
|
||||
/// <returns>The hook with the supplied parameters.</returns>
|
||||
public static Hook<T> FromSymbol(string moduleName, string exportName, T detour)
|
||||
internal static Hook<T> FromSymbol(string moduleName, string exportName, T detour)
|
||||
=> FromSymbol(moduleName, exportName, detour, false);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -169,7 +190,7 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
|
||||
/// <param name="useMinHook">Use the MinHook hooking library instead of Reloaded.</param>
|
||||
/// <returns>The hook with the supplied parameters.</returns>
|
||||
public static Hook<T> FromSymbol(string moduleName, string exportName, T detour, bool useMinHook)
|
||||
internal static Hook<T> FromSymbol(string moduleName, string exportName, T detour, bool useMinHook)
|
||||
{
|
||||
if (EnvironmentConfiguration.DalamudForceMinHook)
|
||||
useMinHook = true;
|
||||
|
|
@ -198,7 +219,7 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
/// <param name="detour">Callback function. Delegate must have a same original function prototype.</param>
|
||||
/// <param name="useMinHook">Use the MinHook hooking library instead of Reloaded.</param>
|
||||
/// <returns>The hook with the supplied parameters.</returns>
|
||||
public static Hook<T> FromAddress(IntPtr procAddress, T detour, bool useMinHook = false)
|
||||
internal static Hook<T> FromAddress(IntPtr procAddress, T detour, bool useMinHook = false)
|
||||
{
|
||||
if (EnvironmentConfiguration.DalamudForceMinHook)
|
||||
useMinHook = true;
|
||||
|
|
@ -210,27 +231,6 @@ public abstract class Hook<T> : IDisposable, IDalamudHook where T : Delegate
|
|||
return new ReloadedHook<T>(procAddress, detour, Assembly.GetCallingAssembly());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a hook from the current process.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (this.IsDisposed)
|
||||
return;
|
||||
|
||||
this.IsDisposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts intercepting a call to the function.
|
||||
/// </summary>
|
||||
public virtual void Enable() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Stops intercepting a call to the function.
|
||||
/// </summary>
|
||||
public virtual void Disable() => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Check if this object has been disposed already.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Dalamud.Hooking;
|
|||
/// <summary>
|
||||
/// Interface describing a generic hook.
|
||||
/// </summary>
|
||||
public interface IDalamudHook
|
||||
public interface IDalamudHook : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address to hook.
|
||||
|
|
|
|||
99
Dalamud/Hooking/Internal/HookProviderPluginScoped.cs
Normal file
99
Dalamud/Hooking/Internal/HookProviderPluginScoped.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Hooking.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a texture manager.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.ScopedService]
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IHookProvider>]
|
||||
#pragma warning restore SA1015
|
||||
internal class HookProviderPluginScoped : IHookProvider, IServiceType, IDisposable
|
||||
{
|
||||
private readonly LocalPlugin plugin;
|
||||
private readonly SigScanner scanner;
|
||||
|
||||
private readonly ConcurrentBag<IDalamudHook> trackedHooks = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HookProviderPluginScoped"/> class.
|
||||
/// </summary>
|
||||
/// <param name="plugin">Plugin this instance belongs to.</param>
|
||||
/// <param name="scanner">SigScanner instance for target module.</param>
|
||||
public HookProviderPluginScoped(LocalPlugin plugin, SigScanner scanner)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.scanner = scanner;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void InitializeFromAttributes(object self)
|
||||
{
|
||||
foreach (var hook in SignatureHelper.Initialise(self))
|
||||
this.trackedHooks.Add(hook);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Hook<T> FromFunctionPointerVariable<T>(IntPtr address, T detour) where T : Delegate
|
||||
{
|
||||
var hook = Hook<T>.FromFunctionPointerVariable(address, detour);
|
||||
this.trackedHooks.Add(hook);
|
||||
return hook;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Hook<T> FromImport<T>(ProcessModule? module, string moduleName, string functionName, uint hintOrOrdinal, T detour) where T : Delegate
|
||||
{
|
||||
var hook = Hook<T>.FromImport(module, moduleName, functionName, hintOrOrdinal, detour);
|
||||
this.trackedHooks.Add(hook);
|
||||
return hook;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Hook<T> FromSymbol<T>(string moduleName, string exportName, T detour, IHookProvider.HookBackend backend = IHookProvider.HookBackend.Automatic) where T : Delegate
|
||||
{
|
||||
var hook = Hook<T>.FromSymbol(moduleName, exportName, detour, backend == IHookProvider.HookBackend.MinHook);
|
||||
this.trackedHooks.Add(hook);
|
||||
return hook;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Hook<T> FromAddress<T>(IntPtr procAddress, T detour, IHookProvider.HookBackend backend = IHookProvider.HookBackend.Automatic) where T : Delegate
|
||||
{
|
||||
var hook = Hook<T>.FromAddress(procAddress, detour, backend == IHookProvider.HookBackend.MinHook);
|
||||
this.trackedHooks.Add(hook);
|
||||
return hook;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Hook<T> FromSignature<T>(string signature, T detour, IHookProvider.HookBackend backend = IHookProvider.HookBackend.Automatic) where T : Delegate
|
||||
=> this.FromAddress(this.scanner.ScanText(signature), detour);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
var notDisposed = this.trackedHooks.Where(x => !x.IsDisposed).ToArray();
|
||||
if (notDisposed.Length != 0)
|
||||
Log.Warning("{PluginName} is leaking {Num} hooks! Make sure that all of them are disposed properly.", this.plugin.InternalName, notDisposed.Length);
|
||||
|
||||
foreach (var hook in notDisposed)
|
||||
{
|
||||
hook.Dispose();
|
||||
}
|
||||
|
||||
this.trackedHooks.Clear();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue