public void Dispose() { if (!Links.Contains(this)) { return; } Links.Remove(this); if (Links.Count > 0) { return; } // Last link - dispose. h_GBSIOInit.Undo(); h_GBSIOInit.Free(); h_GBSIOInit = null; h_GBSIODeinit.Undo(); h_GBSIODeinit.Free(); h_GBSIODeinit = null; h_mTimingInit.Undo(); h_mTimingInit.Free(); h_mTimingInit = null; h_mCoreConfigLoadDefaults.Undo(); h_mCoreConfigLoadDefaults.Free(); h_mCoreConfigLoadDefaults = null; h_mSDLAttachPlayer.Undo(); h_mSDLAttachPlayer.Free(); h_mSDLAttachPlayer = null; Timing = (mTiming *)IntPtr.Zero; SIO = (GBSIO *)IntPtr.Zero; Marshal.FreeHGlobal((IntPtr)Driver); Driver = (GBSIODriver *)IntPtr.Zero; Marshal.FreeHGlobal((IntPtr)QueueCheckEvent->name); Marshal.FreeHGlobal((IntPtr)QueueCheckEvent); QueueCheckEvent = (mTimingEvent *)IntPtr.Zero; }
public MGBALink() { if (Links.Count == 0) { // First link - setup. IntPtr libmgba = DynamicDll.OpenLibrary("libmgba.dll"); IntPtr libmgbasdl = DynamicDll.OpenLibrary("libmgba-sdl.dll"); // Hook GBSIOInit to grab a reference to GBSIO. h_GBSIOInit = new NativeDetour( libmgba.GetFunction("GBSIOInit"), typeof(MGBALink).GetMethod("GBSIOInit", BindingFlags.NonPublic | BindingFlags.Static) ); orig_GBSIOInit = h_GBSIOInit.GenerateTrampoline <d_GBSIOInit>(); // Hook GBSIODeinit to properly dispose everything. h_GBSIODeinit = new NativeDetour( libmgba.GetFunction("GBSIODeinit"), typeof(MGBALink).GetMethod("GBSIODeinit", BindingFlags.NonPublic | BindingFlags.Static) ); orig_GBSIODeinit = h_GBSIODeinit.GenerateTrampoline <d_GBSIODeinit>(); // Hook mTimingInit (called via non-exported GBInit) to set up any timing-related stuff and the driver. h_mTimingInit = new NativeDetour( libmgba.GetFunction("mTimingInit"), typeof(MGBALink).GetMethod("mTimingInit", BindingFlags.NonPublic | BindingFlags.Static) ); orig_mTimingInit = h_mTimingInit.GenerateTrampoline <d_mTimingInit>(); // Hook mCoreConfigLoadDefaults to change the configs before loading them. h_mCoreConfigLoadDefaults = new NativeDetour( libmgba.GetFunction("mCoreConfigLoadDefaults"), typeof(MGBALink).GetMethod("mCoreConfigLoadDefaults", BindingFlags.NonPublic | BindingFlags.Static) ); orig_mCoreConfigLoadDefaults = h_mCoreConfigLoadDefaults.GenerateTrampoline <d_mCoreConfigLoadDefaults>(); // Hook mSDLAttachPlayer to hook the renderer's runloop. // This is required to fix any managed runtime <-> unmanaged state bugs. h_mSDLAttachPlayer = new NativeDetour( libmgbasdl.GetFunction("mSDLAttachPlayer"), typeof(MGBALink).GetMethod("mSDLAttachPlayer", BindingFlags.NonPublic | BindingFlags.Static) ); orig_mSDLAttachPlayer = h_mSDLAttachPlayer.GenerateTrampoline <d_mSDLAttachPlayer>(); // Hook mSDLInitAudio to force our own sample rate. h_mSDLInitAudio = new NativeDetour( libmgbasdl.GetFunction("mSDLInitAudio"), typeof(MGBALink).GetMethod("mSDLInitAudio", BindingFlags.NonPublic | BindingFlags.Static) ); orig_mSDLInitAudio = h_mSDLInitAudio.GenerateTrampoline <d_mSDLInitAudio>(); // Setup the custom GBSIODriver, responsible for syncing dequeues. Driver = (GBSIODriver *)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(GBSIODriver))); // Slow but functional zeroing. for (int i = 0; i < sizeof(mTimingEvent); i++) { Driver->p = (GBSIO *)IntPtr.Zero; } Driver->init = PinnedPtr <GBSIODriver.d_init>(DriverInit); Driver->deinit = PinnedPtr <GBSIODriver.d_deinit>(DriverDeinit); Driver->writeSB = PinnedPtr <GBSIODriver.d_writeSB>(DriverWriteSB); Driver->writeSC = PinnedPtr <GBSIODriver.d_writeSC>(DriverWriteSC); // Setup the queue check event. QueueCheckEvent = (mTimingEvent *)Marshal.AllocHGlobal(sizeof(mTimingEvent)); // Slow but functional zeroing. for (int i = 0; i < sizeof(mTimingEvent); i++) { *((byte *)((IntPtr)QueueCheckEvent + i)) = 0x00; } QueueCheckEvent->context = (void *)IntPtr.Zero; QueueCheckEvent->name = (byte *)Marshal.StringToHGlobalAnsi("MidiToGBG Queue Check"); QueueCheckEvent->callback = PinnedPtr <mTimingEvent.d_callback>(QueueCheck); QueueCheckEvent->priority = 0x30; } Links.Add(this); }
public static void mTimingDeschedule(mTiming *timing, mTimingEvent * @event) => INTERNAL_mTimingDeschedule((IntPtr)timing, (IntPtr)@event);
public static bool mTimingIsScheduled(mTiming *timing, mTimingEvent * @event) => INTERNAL_mTimingIsScheduled((IntPtr)timing, (IntPtr)@event);
public static void mTimingSchedule(mTiming *timing, mTimingEvent * @event, int when) => INTERNAL_mTimingSchedule((IntPtr)timing, (IntPtr)@event, when);