| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 | 
							- // hardcodet.net NotifyIcon for WPF
 
- // Copyright (c) 2009 - 2013 Philipp Sumi
 
- // Contact and Information: http://www.hardcodet.net
 
- //
 
- // This library is free software; you can redistribute it and/or
 
- // modify it under the terms of the Code Project Open License (CPOL);
 
- // either version 1.0 of the License, or (at your option) any later
 
- // version.
 
- // 
 
- // The above copyright notice and this permission notice shall be
 
- // included in all copies or substantial portions of the Software.
 
- // 
 
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
- // OTHER DEALINGS IN THE SOFTWARE.
 
- //
 
- // THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
 
- using System;
 
- using System.ComponentModel;
 
- using System.Diagnostics;
 
- namespace Hardcodet.Wpf.TaskbarNotification.Interop
 
- {
 
-     /// <summary>
 
-     /// Receives messages from the taskbar icon through
 
-     /// window messages of an underlying helper window.
 
-     /// </summary>
 
-     public class WindowMessageSink : IDisposable
 
-     {
 
-         #region members
 
-         /// <summary>
 
-         /// The ID of messages that are received from the the
 
-         /// taskbar icon.
 
-         /// </summary>
 
-         public const int CallbackMessageId = 0x400;
 
-         /// <summary>
 
-         /// The ID of the message that is being received if the
 
-         /// taskbar is (re)started.
 
-         /// </summary>
 
-         private uint taskbarRestartMessageId;
 
-         /// <summary>
 
-         /// Used to track whether a mouse-up event is just
 
-         /// the aftermath of a double-click and therefore needs
 
-         /// to be suppressed.
 
-         /// </summary>
 
-         private bool isDoubleClick;
 
-         /// <summary>
 
-         /// A delegate that processes messages of the hidden
 
-         /// native window that receives window messages. Storing
 
-         /// this reference makes sure we don't loose our reference
 
-         /// to the message window.
 
-         /// </summary>
 
-         private WindowProcedureHandler messageHandler;
 
-         /// <summary>
 
-         /// Window class ID.
 
-         /// </summary>
 
-         internal string WindowId { get; private set; }
 
-         /// <summary>
 
-         /// Handle for the message window.
 
-         /// </summary> 
 
-         internal IntPtr MessageWindowHandle { get; private set; }
 
-         /// <summary>
 
-         /// The version of the underlying icon. Defines how
 
-         /// incoming messages are interpreted.
 
-         /// </summary>
 
-         public NotifyIconVersion Version { get; set; }
 
-         #endregion
 
-         #region events
 
-         /// <summary>
 
-         /// The custom tooltip should be closed or hidden.
 
-         /// </summary>
 
-         public event Action<bool> ChangeToolTipStateRequest;
 
-         /// <summary>
 
-         /// Fired in case the user clicked or moved within
 
-         /// the taskbar icon area.
 
-         /// </summary>
 
-         public event Action<MouseEvent> MouseEventReceived;
 
-         /// <summary>
 
-         /// Fired if a balloon ToolTip was either displayed
 
-         /// or closed (indicated by the boolean flag).
 
-         /// </summary>
 
-         public event Action<bool> BalloonToolTipChanged;
 
-         /// <summary>
 
-         /// Fired if the taskbar was created or restarted. Requires the taskbar
 
-         /// icon to be reset.
 
-         /// </summary>
 
-         public event Action TaskbarCreated;
 
-         #endregion
 
-         #region construction
 
-         /// <summary>
 
-         /// Creates a new message sink that receives message from
 
-         /// a given taskbar icon.
 
-         /// </summary>
 
-         /// <param name="version"></param>
 
-         public WindowMessageSink(NotifyIconVersion version)
 
-         {
 
-             Version = version;
 
-             CreateMessageWindow();
 
-         }
 
-         private WindowMessageSink()
 
-         {
 
-         }
 
-         /// <summary>
 
-         /// Creates a dummy instance that provides an empty
 
-         /// pointer rather than a real window handler.<br/>
 
-         /// Used at design time.
 
-         /// </summary>
 
-         /// <returns>WindowMessageSink</returns>
 
-         internal static WindowMessageSink CreateEmpty()
 
-         {
 
-             return new WindowMessageSink
 
-             {
 
-                 MessageWindowHandle = IntPtr.Zero,
 
-                 Version = NotifyIconVersion.Vista
 
-             };
 
-         }
 
-         #endregion
 
-         #region CreateMessageWindow
 
-         /// <summary>
 
-         /// Creates the helper message window that is used
 
-         /// to receive messages from the taskbar icon.
 
-         /// </summary>
 
-         private void CreateMessageWindow()
 
-         {
 
-             //generate a unique ID for the window
 
-             WindowId = "WPFTaskbarIcon_" + Guid.NewGuid();
 
-             //register window message handler
 
-             messageHandler = OnWindowMessageReceived;
 
-             // Create a simple window class which is reference through
 
-             //the messageHandler delegate
 
-             WindowClass wc;
 
-             wc.style = 0;
 
-             wc.lpfnWndProc = messageHandler;
 
-             wc.cbClsExtra = 0;
 
-             wc.cbWndExtra = 0;
 
-             wc.hInstance = IntPtr.Zero;
 
-             wc.hIcon = IntPtr.Zero;
 
-             wc.hCursor = IntPtr.Zero;
 
-             wc.hbrBackground = IntPtr.Zero;
 
-             wc.lpszMenuName = string.Empty;
 
-             wc.lpszClassName = WindowId;
 
-             // Register the window class
 
-             WinApi.RegisterClass(ref wc);
 
-             // Get the message used to indicate the taskbar has been restarted
 
-             // This is used to re-add icons when the taskbar restarts
 
-             taskbarRestartMessageId = WinApi.RegisterWindowMessage("TaskbarCreated");
 
-             // Create the message window
 
-             MessageWindowHandle = WinApi.CreateWindowEx(0, WindowId, "", 0, 0, 0, 1, 1, IntPtr.Zero, IntPtr.Zero,
 
-                 IntPtr.Zero, IntPtr.Zero);
 
-             if (MessageWindowHandle == IntPtr.Zero)
 
-             {
 
-                 throw new Win32Exception("Message window handle was not a valid pointer");
 
-             }
 
-         }
 
-         #endregion
 
-         #region Handle Window Messages
 
-         /// <summary>
 
-         /// Callback method that receives messages from the taskbar area.
 
-         /// </summary>
 
-         private IntPtr OnWindowMessageReceived(IntPtr hWnd, uint messageId, IntPtr wParam, IntPtr lParam)
 
-         {
 
-             if (messageId == taskbarRestartMessageId)
 
-             {
 
-                 //recreate the icon if the taskbar was restarted (e.g. due to Win Explorer shutdown)
 
-                 var listener = TaskbarCreated;
 
-                 listener?.Invoke();
 
-             }
 
-             //forward message
 
-             ProcessWindowMessage(messageId, wParam, lParam);
 
-             // Pass the message to the default window procedure
 
-             return WinApi.DefWindowProc(hWnd, messageId, wParam, lParam);
 
-         }
 
-         /// <summary>
 
-         /// Processes incoming system messages.
 
-         /// </summary>
 
-         /// <param name="msg">Callback ID.</param>
 
-         /// <param name="wParam">If the version is <see cref="NotifyIconVersion.Vista"/>
 
-         /// or higher, this parameter can be used to resolve mouse coordinates.
 
-         /// Currently not in use.</param>
 
-         /// <param name="lParam">Provides information about the event.</param>
 
-         private void ProcessWindowMessage(uint msg, IntPtr wParam, IntPtr lParam)
 
-         {
 
-             if (msg != CallbackMessageId) return;
 
-             var message = (WindowsMessages) lParam.ToInt32();
 
-             //Debug.WriteLine("Got message " + message);
 
-             switch (message)
 
-             {
 
-                 case WindowsMessages.WM_CONTEXTMENU:
 
-                     // TODO: Handle WM_CONTEXTMENU, see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw
 
-                     //Debug.WriteLine("Unhandled WM_CONTEXTMENU");
 
-                     break;
 
-                 case WindowsMessages.WM_MOUSEMOVE:
 
-                     MouseEventReceived?.Invoke(MouseEvent.MouseMove);
 
-                     break;
 
-                 case WindowsMessages.WM_LBUTTONDOWN:
 
-                     MouseEventReceived?.Invoke(MouseEvent.IconLeftMouseDown);
 
-                     break;
 
-                 case WindowsMessages.WM_LBUTTONUP:
 
-                     if (!isDoubleClick)
 
-                     {
 
-                         MouseEventReceived?.Invoke(MouseEvent.IconLeftMouseUp);
 
-                     }
 
-                     isDoubleClick = false;
 
-                     break;
 
-                 case WindowsMessages.WM_LBUTTONDBLCLK:
 
-                     isDoubleClick = true;
 
-                     MouseEventReceived?.Invoke(MouseEvent.IconDoubleClick);
 
-                     break;
 
-                 case WindowsMessages.WM_RBUTTONDOWN:
 
-                     MouseEventReceived?.Invoke(MouseEvent.IconRightMouseDown);
 
-                     break;
 
-                 case WindowsMessages.WM_RBUTTONUP:
 
-                     MouseEventReceived?.Invoke(MouseEvent.IconRightMouseUp);
 
-                     break;
 
-                 case WindowsMessages.WM_RBUTTONDBLCLK:
 
-                     //double click with right mouse button - do not trigger event
 
-                     break;
 
-                 case WindowsMessages.WM_MBUTTONDOWN:
 
-                     MouseEventReceived?.Invoke(MouseEvent.IconMiddleMouseDown);
 
-                     break;
 
-                 case WindowsMessages.WM_MBUTTONUP:
 
-                     MouseEventReceived?.Invoke(MouseEvent.IconMiddleMouseUp);
 
-                     break;
 
-                 case WindowsMessages.WM_MBUTTONDBLCLK:
 
-                     //double click with middle mouse button - do not trigger event
 
-                     break;
 
-                 case WindowsMessages.NIN_BALLOONSHOW:
 
-                     BalloonToolTipChanged?.Invoke(true);
 
-                     break;
 
-                 case WindowsMessages.NIN_BALLOONHIDE:
 
-                 case WindowsMessages.NIN_BALLOONTIMEOUT:
 
-                     BalloonToolTipChanged?.Invoke(false);
 
-                     break;
 
-                 case WindowsMessages.NIN_BALLOONUSERCLICK:
 
-                     MouseEventReceived?.Invoke(MouseEvent.BalloonToolTipClicked);
 
-                     break;
 
-                 case WindowsMessages.NIN_POPUPOPEN:
 
-                     ChangeToolTipStateRequest?.Invoke(true);
 
-                     break;
 
-                 case WindowsMessages.NIN_POPUPCLOSE:
 
-                     ChangeToolTipStateRequest?.Invoke(false);
 
-                     break;
 
-                 case WindowsMessages.NIN_SELECT:
 
-                     // TODO: Handle NIN_SELECT see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw
 
-                     //Debug.WriteLine("Unhandled NIN_SELECT");
 
-                     break;
 
-                 case WindowsMessages.NIN_KEYSELECT:
 
-                     // TODO: Handle NIN_KEYSELECT see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw
 
-                     //Debug.WriteLine("Unhandled NIN_KEYSELECT");
 
-                     break;
 
-                 default:
 
-                     //Debug.WriteLine("Unhandled NotifyIcon message ID: " + lParam);
 
-                     break;
 
-             }
 
-         }
 
-         #endregion
 
-         #region Dispose
 
-         /// <summary>
 
-         /// Set to true as soon as <c>Dispose</c> has been invoked.
 
-         /// </summary>
 
-         public bool IsDisposed { get; private set; }
 
-         /// <summary>
 
-         /// Disposes the object.
 
-         /// </summary>
 
-         /// <remarks>This method is not virtual by design. Derived classes
 
-         /// should override <see cref="Dispose(bool)"/>.
 
-         /// </remarks>
 
-         public void Dispose()
 
-         {
 
-             Dispose(true);
 
-             // This object will be cleaned up by the Dispose method.
 
-             // Therefore, you should call GC.SuppressFinalize to
 
-             // take this object off the finalization queue 
 
-             // and prevent finalization code for this object
 
-             // from executing a second time.
 
-             GC.SuppressFinalize(this);
 
-         }
 
-         /// <summary>
 
-         /// This destructor will run only if the <see cref="Dispose()"/>
 
-         /// method does not get called. This gives this base class the
 
-         /// opportunity to finalize.
 
-         /// <para>
 
-         /// Important: Do not provide destructor in types derived from
 
-         /// this class.
 
-         /// </para>
 
-         /// </summary>
 
-         ~WindowMessageSink()
 
-         {
 
-             Dispose(false);
 
-         }
 
-         /// <summary>
 
-         /// Removes the windows hook that receives window
 
-         /// messages and closes the underlying helper window.
 
-         /// </summary>
 
-         private void Dispose(bool disposing)
 
-         {
 
-             //don't do anything if the component is already disposed
 
-             if (IsDisposed) return;
 
-             IsDisposed = true;
 
-             //always destroy the unmanaged handle (even if called from the GC)
 
-             WinApi.DestroyWindow(MessageWindowHandle);
 
-             messageHandler = null;
 
-         }
 
-         #endregion
 
-     }
 
- }
 
 
  |