using System; using System.Diagnostics; namespace Hardcodet.Wpf.TaskbarNotification.Interop { /// /// Receives messages from the taskbar icon through /// window messages of an underlying helper window. /// public partial class WindowMessageSink : IDisposable { #region members /// /// The ID of messages that are received from the the /// taskbar icon. /// public const int CallbackMessageId = 0x400; /// /// The version of the underlying icon. Defines how /// incoming messages are interpreted. /// public NotifyIconVersion Version { get; set; } #endregion #region events /// /// The custom tooltip should be closed or hidden. /// public event Action ChangeToolTipStateRequest; /// /// Fired in case the user clicked or moved within /// the taskbar icon area. /// public event Action MouseEventReceived; /// /// Fired if a balloon ToolTip was either displayed /// or closed (indicated by the boolean flag). /// public event Action BallonToolTipChanged; /// /// Fired if the taskbar was created. Requires the taskbar /// icon to be reset. /// public event Action TaskbarCreated; #endregion #region construction /// /// Creates a new message sink that receives message from /// a given taskbar icon. /// /// public WindowMessageSink(NotifyIconVersion version) { Version = version; CreateMessageWindow(); } private WindowMessageSink() { } /// /// Creates a dummy instance that provides an empty /// pointer rather than a real window handler.
/// Used at design time. ///
/// internal static WindowMessageSink CreateEmpty() { return new WindowMessageSink { MessageWindowHandle = IntPtr.Zero, Version = NotifyIconVersion.Vista }; } #endregion #region Process Window Messages /// /// Processes incoming system messages. /// /// /// /// /// private void ProcessWindowMessage(uint msg, uint wParam, uint lParam) { if (msg != CallbackMessageId) return; switch (lParam) { case 0x200: // Debug.WriteLine("MOVE"); MouseEventReceived(MouseEvent.MouseMove); break; case 0x201: Debug.WriteLine("left down 1"); MouseEventReceived(MouseEvent.IconLeftMouseDown); break; case 0x202: Debug.WriteLine("left up"); MouseEventReceived(MouseEvent.IconLeftMouseUp); break; case 0x203: Debug.WriteLine("left click 2"); MouseEventReceived(MouseEvent.IconDoubleClick); break; case 0x204: Debug.WriteLine("right click 1"); MouseEventReceived(MouseEvent.IconRightMouseDown); break; case 0x205: Console.Out.WriteLine("right mouse up"); MouseEventReceived(MouseEvent.IconRightMouseUp); break; case 0x206: //double click with right mouse button - do not trigger event Debug.WriteLine("right click 2"); break; case 0x207: Debug.WriteLine("middle click 1"); MouseEventReceived(MouseEvent.IconMiddleMouseDown); break; case 520: Debug.WriteLine("mouse up middle"); MouseEventReceived(MouseEvent.IconMiddleMouseUp); break; case 0x209: //double click with middle mouse button - do not trigger event Debug.WriteLine("middle click 2"); break; case 0x402: Debug.WriteLine("balloon shown"); BallonToolTipChanged(true); break; case 0x403: case 0x404: Debug.WriteLine("balloon close"); BallonToolTipChanged(false); break; case 0x405: Debug.WriteLine("balloon clicked"); MouseEventReceived(MouseEvent.BalloonToolTipClicked); break; case 0x406: Debug.WriteLine("show custom tooltip"); ChangeToolTipStateRequest(true); break; case 0x407: Debug.WriteLine("close custom tooltip"); ChangeToolTipStateRequest(false); break; default: Debug.WriteLine("Unhandled message ID: " + lParam); break; } } #endregion #region Dispose /// /// Set to true as soon as /// has been invoked. /// public bool IsDisposed { get; private set; } /// /// Disposes the object. /// /// This method is not virtual by design. Derived classes /// should override . /// public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } /// /// This destructor will run only if the /// method does not get called. This gives this base class the /// opportunity to finalize. /// /// Important: Do not provide destructors in types derived from /// this class. /// /// ~WindowMessageSink() { Dispose(false); } /// /// Removes the windows hook that receives window /// messages and closes the underlying helper window. /// private void Dispose(bool disposing) { //don't do anything if the component is already disposed if (IsDisposed || !disposing) return; IsDisposed = true; WinApi.DestroyWindow(MessageWindowHandle); messageHandler = null; } #endregion } }