From: RĂ©mi Denis-Courmont Date: Mon, 23 Feb 2009 18:00:52 +0000 (+0200) Subject: Simpler and safer event callbacks handling X-Git-Tag: 1.0.0-pre1~466 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=d14f8d432c2dfaea7365e728a61ec37c3cdcf837;p=vlc Simpler and safer event callbacks handling --- diff --git a/bindings/cil/src/marshal.cs b/bindings/cil/src/marshal.cs index 166b90d8a8..3a427f8f25 100644 --- a/bindings/cil/src/marshal.cs +++ b/bindings/cil/src/marshal.cs @@ -139,30 +139,12 @@ namespace VideoLAN.LibVLC */ public abstract class EventingObject : BaseObject { - /** - * @brief Managed to unmanaged event handler mapping - * @ingroup Internals - * - * The CLR cannot do reference counting for unmanaged callbacks. - * We keep track of handled events here instead. - */ - private class Event - { - public EventCallback managed; - public IntPtr unmanaged; - - public Event (EventCallback managed, IntPtr unmanaged) - { - this.managed = managed; - this.unmanaged = unmanaged; - } - }; - private Dictionary events; + private Dictionary events; /**< references to our unmanaged function pointers */ internal EventingObject () : base () { - events = new Dictionary (); + events = new Dictionary (); } /** @@ -187,19 +169,20 @@ namespace VideoLAN.LibVLC * @param callback callback to invoke when the event occurs * * @note - * For simplicity, we only allow one handler per type. - * Multicasting can be implemented higher up with managed code. + * For simplicity, we require distinct callbacks for each event type. + * This is hardly an issue since most events have different formats. */ - internal void Attach (EventType type, EventCallback callback) + internal void Attach (EventType type, Delegate callback) { EventManagerHandle manager; IntPtr cb = Marshal.GetFunctionPointerForDelegate (callback); - Event ev = new Event (callback, cb); bool unref = false; - if (events.ContainsKey (type)) - throw new ArgumentException ("Duplicate event"); - + /* If things go wrong, we will leak the callback thunk... until + * this object is destroyed anyway. If we added the thunk _after_ + * the critical section, the native code could try to jump to a + * non-existent address, which is much worse. */ + events.Add (callback, cb); try { handle.DangerousAddRef (ref unref); @@ -212,19 +195,19 @@ namespace VideoLAN.LibVLC handle.DangerousRelease (); } Raise (); - events.Add (type, ev); } - private void Detach (EventType type, IntPtr callback) + internal void Detach (EventType type, Delegate callback) { EventManagerHandle manager; + IntPtr cb = events[callback]; bool unref = false; try { handle.DangerousAddRef (ref unref); manager = GetManager (); - LibVLC.EventDetach (manager, type, callback, IntPtr.Zero, ex); + LibVLC.EventDetach (manager, type, cb, IntPtr.Zero, ex); } finally { @@ -232,12 +215,7 @@ namespace VideoLAN.LibVLC handle.DangerousRelease (); } Raise (); - events.Remove (type); - } - - internal void Detach (EventType type) - { - Detach(type, events[type].unmanaged); + events.Remove (callback); } }; };