diff --git a/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs b/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs
index b271ee4a4..31bee1204 100644
--- a/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs
+++ b/Dalamud/Configuration/Internal/EnvironmentConfiguration.cs
@@ -25,7 +25,7 @@ namespace Dalamud.Configuration.Internal
///
/// Gets a value indicating whether the DalamudForceCoreHook setting has been enabled.
///
- public static bool DalamudForceCoreHook { get; } = GetEnvironmentVariable("DALAMUD_FORCE_COREHOOK");
+ public static bool DalamudForceMinHook { get; } = GetEnvironmentVariable("DALAMUD_FORCE_COREHOOK");
private static bool GetEnvironmentVariable(string name)
=> bool.Parse(Environment.GetEnvironmentVariable(name) ?? "false");
diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj
index 92c88db5c..57b33b75e 100644
--- a/Dalamud/Dalamud.csproj
+++ b/Dalamud/Dalamud.csproj
@@ -64,10 +64,10 @@
-
+
@@ -94,12 +94,6 @@
-
-
- PreserveNewest
-
-
-
diff --git a/Dalamud/Hooking/AsmHook.cs b/Dalamud/Hooking/AsmHook.cs
index 49c951867..35eac4efd 100644
--- a/Dalamud/Hooking/AsmHook.cs
+++ b/Dalamud/Hooking/AsmHook.cs
@@ -112,6 +112,9 @@ namespace Dalamud.Hooking
///
public bool IsDisposed { get; private set; }
+ ///
+ public string BackendName => "Reloaded/Asm";
+
///
/// Remove a hook from the current process.
///
diff --git a/Dalamud/Hooking/Hook.cs b/Dalamud/Hooking/Hook.cs
index 7171e2ec7..ba19ffb18 100644
--- a/Dalamud/Hooking/Hook.cs
+++ b/Dalamud/Hooking/Hook.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Reflection;
using Dalamud.Configuration.Internal;
@@ -18,8 +19,8 @@ namespace Dalamud.Hooking
{
private readonly IntPtr address;
private readonly Reloaded.Hooks.Definitions.IHook hookImpl;
- private readonly CoreHook.IHook coreHookImpl;
- private readonly bool isCoreHook;
+ private readonly MinSharp.Hook minHookImpl;
+ private readonly bool isMinHook;
///
/// Initializes a new instance of the class.
@@ -35,15 +36,15 @@ namespace Dalamud.Hooking
///
/// Initializes a new instance of the class.
/// Hook is not activated until Enable() method is called.
- /// Please do not use CoreHook unless you have thoroughly troubleshot why Reloaded does not work.
+ /// Please do not use MinHook unless you have thoroughly troubleshot why Reloaded does not work.
///
/// A memory address to install a hook.
/// Callback function. Delegate must have a same original function prototype.
- /// Use the corehook hooking library instead of Reloaded.
- public Hook(IntPtr address, T detour, bool useCoreHook)
+ /// Use the MinHook hooking library instead of Reloaded.
+ public Hook(IntPtr address, T detour, bool useMinHook)
{
address = HookManager.FollowJmp(address);
- this.isCoreHook = useCoreHook || EnvironmentConfiguration.DalamudForceCoreHook;
+ this.isMinHook = EnvironmentConfiguration.DalamudForceMinHook || useMinHook;
var hasOtherHooks = HookManager.Originals.ContainsKey(address);
if (!hasOtherHooks)
@@ -53,18 +54,17 @@ namespace Dalamud.Hooking
}
this.address = address;
- if (this.isCoreHook)
+ if (this.isMinHook)
{
- try
- {
- this.coreHookImpl = CoreHook.HookFactory.CreateHook(address, detour);
- }
- catch (Exception ex)
- {
- this.isCoreHook = false;
- Log.Error(ex, "CoreHook is having a bad day, defaulting to Reloaded");
- this.hookImpl = ReloadedHooks.Instance.CreateHook(detour, address.ToInt64());
- }
+ var indexList = hasOtherHooks
+ ? HookManager.MultiHookTracker[address]
+ : HookManager.MultiHookTracker[address] = new();
+ var index = (ulong)indexList.Count;
+
+ this.minHookImpl = new MinSharp.Hook(address, detour, index);
+
+ // Add afterwards, so the hookIdent starts at 0.
+ indexList.Add(this);
}
else
{
@@ -96,9 +96,9 @@ namespace Dalamud.Hooking
get
{
this.CheckDisposed();
- if (this.isCoreHook)
+ if (this.isMinHook)
{
- return this.coreHookImpl.Original;
+ return this.minHookImpl.Original;
}
else
{
@@ -115,9 +115,9 @@ namespace Dalamud.Hooking
get
{
this.CheckDisposed();
- if (this.isCoreHook)
+ if (this.isMinHook)
{
- return this.coreHookImpl.Enabled;
+ return this.minHookImpl.Enabled;
}
else
{
@@ -131,6 +131,18 @@ namespace Dalamud.Hooking
///
public bool IsDisposed { get; private set; }
+ ///
+ public string BackendName
+ {
+ get
+ {
+ if (this.isMinHook)
+ return "MinHook";
+
+ return "Reloaded";
+ }
+ }
+
///
/// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function.
/// The hook is not activated until Enable() method is called.
@@ -145,14 +157,14 @@ namespace Dalamud.Hooking
///
/// Creates a hook. Hooking address is inferred by calling to GetProcAddress() function.
/// The hook is not activated until Enable() method is called.
- /// Please do not use CoreHook unless you have thoroughly troubleshot why Reloaded does not work.
+ /// Please do not use MinHook unless you have thoroughly troubleshot why Reloaded does not work.
///
/// 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.
- /// Use the corehook hooking library instead of Reloaded.
+ /// Use the MinHook hooking library instead of Reloaded.
/// The hook with the supplied parameters.
- public static Hook FromSymbol(string moduleName, string exportName, T detour, bool useCoreHook)
+ public static Hook FromSymbol(string moduleName, string exportName, T detour, bool useMinHook)
{
var moduleHandle = NativeFunctions.GetModuleHandleW(moduleName);
if (moduleHandle == IntPtr.Zero)
@@ -162,7 +174,7 @@ namespace Dalamud.Hooking
if (procAddress == IntPtr.Zero)
throw new Exception($"Could not get the address of {moduleName}::{exportName}");
- return new Hook(procAddress, detour, useCoreHook);
+ return new Hook(procAddress, detour, useMinHook);
}
///
@@ -173,12 +185,10 @@ namespace Dalamud.Hooking
if (this.IsDisposed)
return;
- if (this.isCoreHook)
+ if (this.isMinHook)
{
- this.Disable();
- // Disposing CoreHook causes an APPCRASH on game exit.
- // We already overwrite the original hook code, so there shouldn't be any real risk with not disposing here.
- // this.coreHookImpl.Dispose();
+ this.minHookImpl.Dispose();
+ HookManager.MultiHookTracker[this.address] = null;
}
else
{
@@ -195,10 +205,12 @@ namespace Dalamud.Hooking
{
this.CheckDisposed();
- if (this.isCoreHook)
+ if (this.isMinHook)
{
- if (!this.coreHookImpl.Enabled)
- this.coreHookImpl.Enabled = true;
+ if (!this.minHookImpl.Enabled)
+ {
+ this.minHookImpl.Enable();
+ }
}
else
{
@@ -217,10 +229,12 @@ namespace Dalamud.Hooking
{
this.CheckDisposed();
- if (this.isCoreHook)
+ if (this.isMinHook)
{
- if (this.coreHookImpl.Enabled)
- this.coreHookImpl.Enabled = false;
+ if (this.minHookImpl.Enabled)
+ {
+ this.minHookImpl.Disable();
+ }
}
else
{
diff --git a/Dalamud/Hooking/IDalamudHook.cs b/Dalamud/Hooking/IDalamudHook.cs
index deaf62957..5a9ae2716 100644
--- a/Dalamud/Hooking/IDalamudHook.cs
+++ b/Dalamud/Hooking/IDalamudHook.cs
@@ -21,5 +21,10 @@ namespace Dalamud.Hooking
/// Gets a value indicating whether or not the hook is disposed.
///
public bool IsDisposed { get; }
+
+ ///
+ /// Gets the name of the hooking backend used for the hook.
+ ///
+ public string BackendName { get; }
}
}
diff --git a/Dalamud/Hooking/Internal/HookManager.cs b/Dalamud/Hooking/Internal/HookManager.cs
index 1f67ee1e8..8990930a0 100644
--- a/Dalamud/Hooking/Internal/HookManager.cs
+++ b/Dalamud/Hooking/Internal/HookManager.cs
@@ -79,6 +79,11 @@ namespace Dalamud.Hooking.Internal
///
internal static Dictionary Originals { get; } = new();
+ ///
+ /// Gets a static dictionary of the number of hooks on a given address.
+ ///
+ internal static Dictionary> MultiHookTracker { get; } = new();
+
///
public void Dispose()
{
diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs
index f6a45846d..e7355e2ed 100644
--- a/Dalamud/Interface/Internal/Windows/DataWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Reflection;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -27,6 +28,7 @@ using Dalamud.Game.Gui;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Text;
+using Dalamud.Hooking;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Windowing;
@@ -69,6 +71,9 @@ namespace Dalamud.Interface.Internal.Windows
private UIDebug addonInspector = null;
+ private Hook? messageBoxMinHook;
+ private bool hookUseMinHook = false;
+
// IPC
private ICallGateProvider ipcPub;
private ICallGateSubscriber ipcSub;
@@ -117,6 +122,12 @@ namespace Dalamud.Interface.Internal.Windows
this.Load();
}
+ private delegate int MessageBoxWDelegate(
+ IntPtr hWnd,
+ [MarshalAs(UnmanagedType.LPWStr)] string text,
+ [MarshalAs(UnmanagedType.LPWStr)] string caption,
+ NativeFunctions.MessageBoxType type);
+
private enum DataKind
{
Server_OpCode,
@@ -143,6 +154,7 @@ namespace Dalamud.Interface.Internal.Windows
Gamepad,
Configuration,
TaskSched,
+ Hook,
}
///
@@ -318,6 +330,10 @@ namespace Dalamud.Interface.Internal.Windows
case DataKind.TaskSched:
this.DrawTaskSched();
break;
+
+ case DataKind.Hook:
+ this.DrawHook();
+ break;
}
}
else
@@ -335,6 +351,12 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.EndChild();
}
+ private int MessageBoxWDetour(IntPtr hwnd, string text, string caption, NativeFunctions.MessageBoxType type)
+ {
+ Log.Information("[DATAHOOK] {0} {1} {2} {3}", hwnd, text, caption, type);
+ return this.messageBoxMinHook.Original(hwnd, text, caption, type);
+ }
+
private void DrawServerOpCode()
{
ImGui.TextUnformatted(this.serverOpString);
@@ -975,7 +997,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, fontWidth * 10);
ImGui.TableSetupColumn("Pointer", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
- for (int numberArrayIndex = 0; numberArrayIndex < atkArrayDataHolder->NumberArrayCount; numberArrayIndex++)
+ for (var numberArrayIndex = 0; numberArrayIndex < atkArrayDataHolder->NumberArrayCount; numberArrayIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
@@ -989,7 +1011,7 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.TreeNodeEx($"{(long)numberArrayData:X}###{numberArrayIndex}", ImGuiTreeNodeFlags.SpanFullWidth))
{
ImGui.NewLine();
- int tableHeight = Math.Min(40, numberArrayData->AtkArrayData.Size + 4);
+ var tableHeight = Math.Min(40, numberArrayData->AtkArrayData.Size + 4);
if (ImGui.BeginTable($"NumberArrayDataTable", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, new Vector2(0.0F, fontHeight * tableHeight)))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed, fontWidth * 6);
@@ -997,7 +1019,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.TableSetupColumn("Integer", ImGuiTableColumnFlags.WidthFixed, fontWidth * 12);
ImGui.TableSetupColumn("Float", ImGuiTableColumnFlags.WidthFixed, fontWidth * 20);
ImGui.TableHeadersRow();
- for (int numberIndex = 0; numberIndex < numberArrayData->AtkArrayData.Size; numberIndex++)
+ for (var numberIndex = 0; numberIndex < numberArrayData->AtkArrayData.Size; numberIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
@@ -1038,7 +1060,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, fontWidth * 10);
ImGui.TableSetupColumn("Pointer", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
- for (int stringArrayIndex = 0; stringArrayIndex < atkArrayDataHolder->StringArrayCount; stringArrayIndex++)
+ for (var stringArrayIndex = 0; stringArrayIndex < atkArrayDataHolder->StringArrayCount; stringArrayIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
@@ -1052,13 +1074,13 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.TreeNodeEx($"{(long)stringArrayData:X}###{stringArrayIndex}", ImGuiTreeNodeFlags.SpanFullWidth))
{
ImGui.NewLine();
- int tableHeight = Math.Min(40, stringArrayData->AtkArrayData.Size + 4);
+ var tableHeight = Math.Min(40, stringArrayData->AtkArrayData.Size + 4);
if (ImGui.BeginTable($"StringArrayDataTable", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, new Vector2(0.0F, fontHeight * tableHeight)))
{
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed, fontWidth * 6);
ImGui.TableSetupColumn("String", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
- for (int stringIndex = 0; stringIndex < stringArrayData->AtkArrayData.Size; stringIndex++)
+ for (var stringIndex = 0; stringIndex < stringArrayData->AtkArrayData.Size; stringIndex++)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
@@ -1563,6 +1585,42 @@ namespace Dalamud.Interface.Internal.Windows
}
}
+ private void DrawHook()
+ {
+ try
+ {
+ ImGui.Checkbox("Use MinHook", ref this.hookUseMinHook);
+
+ if (ImGui.Button("Create"))
+ this.messageBoxMinHook = Hook.FromSymbol("User32", "MessageBoxW", this.MessageBoxWDetour, this.hookUseMinHook);
+
+ if (ImGui.Button("Enable"))
+ this.messageBoxMinHook?.Enable();
+
+ if (ImGui.Button("Disable"))
+ this.messageBoxMinHook?.Disable();
+
+ if (ImGui.Button("Call Original"))
+ this.messageBoxMinHook?.Original(IntPtr.Zero, "Hello from .Original", "Hook Test", NativeFunctions.MessageBoxType.Ok);
+
+ if (ImGui.Button("Dispose"))
+ {
+ this.messageBoxMinHook?.Dispose();
+ this.messageBoxMinHook = null;
+ }
+
+ if (ImGui.Button("Test"))
+ _ = NativeFunctions.MessageBoxW(IntPtr.Zero, "Hi", "Hello", NativeFunctions.MessageBoxType.Ok);
+
+ if (this.messageBoxMinHook != null)
+ ImGui.Text("Enabled: " + this.messageBoxMinHook?.IsEnabled);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "MinHook error caught");
+ }
+ }
+
private async Task TestTaskInTaskDelay()
{
await Task.Delay(5000);
diff --git a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs
index e3760794a..257b67857 100644
--- a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs
@@ -4,6 +4,7 @@ using System.Reflection;
using Dalamud.Game;
using Dalamud.Game.Internal;
+using Dalamud.Hooking;
using Dalamud.Hooking.Internal;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Internal;
@@ -175,11 +176,12 @@ namespace Dalamud.Interface.Internal.Windows
if (ImGui.BeginTabItem("Hooks"))
{
- ImGui.Columns(3);
+ ImGui.Columns(4);
- ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 280);
+ ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 330);
ImGui.SetColumnWidth(1, 180f);
ImGui.SetColumnWidth(2, 100f);
+ ImGui.SetColumnWidth(3, 100f);
ImGui.Text("Detour Method");
ImGui.SameLine();
@@ -196,6 +198,9 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.Text("Status");
ImGui.NextColumn();
+ ImGui.Text("Backend");
+ ImGui.NextColumn();
+
ImGui.Separator();
ImGui.Separator();
@@ -240,6 +245,10 @@ namespace Dalamud.Interface.Internal.Windows
}
ImGui.NextColumn();
+
+ ImGui.Text(trackedHook.Hook.BackendName);
+
+ ImGui.NextColumn();
}
catch (Exception ex)
{
diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs
index e2e892b77..8034bb979 100644
--- a/Dalamud/Support/Troubleshooting.cs
+++ b/Dalamud/Support/Troubleshooting.cs
@@ -74,7 +74,7 @@ namespace Dalamud.Support
DoPluginTest = configuration.DoPluginTest,
InterfaceLoaded = interfaceManager?.IsReady ?? false,
ThirdRepo = configuration.ThirdRepoList,
- ForcedCoreHook = EnvironmentConfiguration.DalamudForceCoreHook,
+ ForcedMinHook = EnvironmentConfiguration.DalamudForceMinHook,
};
var encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload)));
@@ -113,7 +113,7 @@ namespace Dalamud.Support
public bool InterfaceLoaded { get; set; }
- public bool ForcedCoreHook { get; set; }
+ public bool ForcedMinHook { get; set; }
public List ThirdRepo { get; set; }
}
diff --git a/Dalamud/corehook64.dll b/Dalamud/corehook64.dll
deleted file mode 100644
index 9b21a40d1..000000000
Binary files a/Dalamud/corehook64.dll and /dev/null differ