mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-15 13:14:17 +01:00
Safer unload
This commit is contained in:
parent
0afb3d2c8a
commit
6fefc3bee0
1 changed files with 21 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Logging.Internal;
|
using Dalamud.Logging.Internal;
|
||||||
|
|
||||||
|
|
@ -21,6 +22,8 @@ internal sealed class WndProcHookManager : IServiceType, IDisposable
|
||||||
private readonly Hook<DispatchMessageWDelegate> dispatchMessageWHook;
|
private readonly Hook<DispatchMessageWDelegate> dispatchMessageWHook;
|
||||||
private readonly Dictionary<HWND, WndProcEventArgs> wndProcOverrides = new();
|
private readonly Dictionary<HWND, WndProcEventArgs> wndProcOverrides = new();
|
||||||
|
|
||||||
|
private HWND mainWindowHwnd;
|
||||||
|
|
||||||
[ServiceManager.ServiceConstructor]
|
[ServiceManager.ServiceConstructor]
|
||||||
private unsafe WndProcHookManager()
|
private unsafe WndProcHookManager()
|
||||||
{
|
{
|
||||||
|
|
@ -31,6 +34,12 @@ internal sealed class WndProcHookManager : IServiceType, IDisposable
|
||||||
0,
|
0,
|
||||||
this.DispatchMessageWDetour);
|
this.DispatchMessageWDetour);
|
||||||
this.dispatchMessageWHook.Enable();
|
this.dispatchMessageWHook.Enable();
|
||||||
|
|
||||||
|
// Capture the game main window handle,
|
||||||
|
// so that no guarantees would have to be made on the service dispose order.
|
||||||
|
Service<InterfaceManager.InterfaceManagerWithScene>
|
||||||
|
.GetAsync()
|
||||||
|
.ContinueWith(r => this.mainWindowHwnd = (HWND)r.Result.Manager.GameWindowHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||||
|
|
@ -49,7 +58,19 @@ internal sealed class WndProcHookManager : IServiceType, IDisposable
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
if (this.dispatchMessageWHook.IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
this.dispatchMessageWHook.Dispose();
|
this.dispatchMessageWHook.Dispose();
|
||||||
|
|
||||||
|
// Ensure that either we're on the main thread, or DispatchMessage is executed at least once.
|
||||||
|
// The game calls DispatchMessageW only from its main thread, so if we're already on one,
|
||||||
|
// this line does nothing; if not, it will require a cycle of GetMessage ... DispatchMessageW,
|
||||||
|
// which at the point of returning from DispatchMessageW(=point of returning from SendMessageW),
|
||||||
|
// the hook would be guaranteed to be fully disabled and detour delegate would be safe to be released.
|
||||||
|
SendMessageW(this.mainWindowHwnd, WM.WM_NULL, 0, 0);
|
||||||
|
|
||||||
|
// Now this.wndProcOverrides cannot be touched from other thread.
|
||||||
foreach (var v in this.wndProcOverrides.Values)
|
foreach (var v in this.wndProcOverrides.Values)
|
||||||
v.InternalRelease();
|
v.InternalRelease();
|
||||||
this.wndProcOverrides.Clear();
|
this.wndProcOverrides.Clear();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue