private static unsafe bool ApplyUser32SetTimerPatch() { IntPtr original = PEUtils.GetExportedFunctionPointerForModule("USER32.dll", "SetTimer"); MelonLogger.Msg($"User32::SetTimer original: 0x{(long)original:X}"); if (original == IntPtr.Zero) { MelonLogger.Error("Failed to find USER32.dll::SetTimer"); return(false); } // We get a native function pointer to User32SetTimerDetour from our current class //IntPtr detourPtr = typeof(Core).GetMethod("User32SetTimerDetour", BindingFlags.NonPublic | BindingFlags.Static).MethodHandle.GetFunctionPointer(); IntPtr detourPtr = Marshal.GetFunctionPointerForDelegate((User32SetTimerDelegate)User32SetTimerDetour); if (detourPtr == IntPtr.Zero) { MelonLogger.Error("Failed to find User32SetTimerDetour"); return(false); } // And we patch SetTimer to replace it by our hook MelonLogger.Msg($"Applying USER32.dll::SetTimer Hook at 0x{original.ToInt64():X}"); MelonUtils.NativeHookAttach((IntPtr)(&original), detourPtr); MelonLogger.Msg($"Creating delegate for original USER32.dll::SetTimer (0x{original.ToInt64():X})"); user32SetTimerOriginal = (User32SetTimerDelegate)Marshal.GetDelegateForFunctionPointer(original, typeof(User32SetTimerDelegate)); MelonLogger.Msg("Applied USER32.dll::SetTimer patch"); return(true); }