CPF/CPF.Windows/NotifyIcon.cs
2023-11-21 23:05:03 +08:00

1054 lines
38 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using CPF.Drawing;
using System.Globalization;
using CPF.Controls;
using CPF.Input;
using CPF.Platform;
namespace CPF.Windows
{
public sealed class NotifyIcon : CpfObject, INotifyIconImpl
{
private const int WM_TRAYMOUSEMESSAGE = (int)UnmanagedMethods.WindowsMessage.WM_USER + 1024;
private static int WM_TASKBARCREATED = UnmanagedMethods.RegisterWindowMessage("TaskbarCreated");
private object syncObj = new object();
IntPtr iconHandle;
//private Image icon = null;
private string text = "";
private int id = 0;
private bool added = false;
private NotifyIconNativeWindow window = null;
private static int nextId = 0;
//private object userData;
private bool doubleClick = false; // checks if doubleclick is fired
// Visible defaults to false, but the NotifyIconDesigner makes it seem like the default is
// true. We do this because while visible is the more common case, if it was a true default,
// there would be no way to create a hidden NotifyIcon without being visible for a moment.
private bool visible = false;
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.NotifyIcon"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Windows.Forms.NotifyIcon'/> class.
/// </para>
/// </devdoc>
public NotifyIcon()
{
id = ++nextId;
window = new NotifyIconNativeWindow(this);
UpdateIcon(visible);
}
/// <include file='doc\NotifyIcon.uex' path='docs/doc[@for="NotifyIcon.BalloonTipClicked"]/*' />
/// <devdoc>
/// <para>[This event is raised on the NIN_BALLOONUSERCLICK message.]</para>
/// </devdoc>
public event EventHandler BalloonTipClicked
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\NotifyIcon.uex' path='docs/doc[@for="NotifyIcon.BalloonTipClosed"]/*' />
/// <devdoc>
/// <para>[This event is raised on the NIN_BALLOONTIMEOUT message.]</para>
/// </devdoc>
public event EventHandler BalloonTipClosed
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\NotifyIcon.uex' path='docs/doc[@for="NotifyIcon.BalloonTipShown"]/*' />
/// <devdoc>
/// <para>[This event is raised on the NIN_BALLOONSHOW or NIN_BALLOONHIDE message.]</para>
/// </devdoc>
public event EventHandler BalloonTipShown
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
[PropertyMetadata("")]
public string BalloonTipText
{
get
{
return GetValue<string>();
}
set
{
SetValue(value);
}
}
public static bool IsEnumValid(Enum enumValue, int value, int minValue, int maxValue)
{
bool valid = (value >= minValue) && (value <= maxValue);
return valid;
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.BalloonTipIcon"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the BalloonTip icon displayed when
/// the mouse hovers over a system tray icon.
/// </para>
/// </devdoc>
public ToolTipIcon BalloonTipIcon
{
get
{
return GetValue<ToolTipIcon>();
}
set
{
//valid values are 0x0 to 0x3
if (!IsEnumValid(value, (int)value, (int)ToolTipIcon.None, (int)ToolTipIcon.Error))
{
throw new InvalidEnumArgumentException("value", (int)value, typeof(ToolTipIcon));
}
SetValue(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.BalloonTipTitle"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the BalloonTip title displayed when
/// the mouse hovers over a system tray icon.
/// </para>
/// </devdoc>
[PropertyMetadata("")]
public string BalloonTipTitle
{
get
{
return GetValue<string>();
}
set
{
SetValue(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.ContextMenu"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets context menu
/// for the tray icon.
/// </para>
/// </devdoc>
public ContextMenu ContextMenu
{
get
{
return GetValue<ContextMenu>();
}
set
{
SetValue(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.Icon"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the current
/// icon.
/// </para>
/// </devdoc>
public Image Icon
{
get
{
return GetValue<Image>();
}
set
{
SetValue(value);
}
}
[PropertyChanged(nameof(Icon))]
void OnIcon(object newValue, object oldValue, CPF.PropertyMetadataAttribute attribute)
{
UpdateIcon(visible);
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.Text"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the ToolTip text displayed when
/// the mouse hovers over a system tray icon.
/// </para>
/// </devdoc>
public string Text
{
get
{
return text;
}
set
{
if (value == null) value = "";
if (value != null && !value.Equals(this.text))
{
if (value != null && value.Length > 63)
{
throw new ArgumentOutOfRangeException("Text", value, "文字太长不能超过63个字符");
}
this.text = value;
if (added)
{
UpdateIcon(true);
}
}
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.Visible"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the icon is visible in the Windows System Tray.
/// </para>
/// </devdoc>
public bool Visible
{
get
{
return visible;
}
set
{
if (visible != value)
{
UpdateIcon(value);
visible = value;
}
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.Click"]/*' />
/// <devdoc>
/// Occurs when the user clicks the icon in the system tray.
/// </devdoc>
public event EventHandler Click
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.DoubleClick"]/*' />
/// <devdoc>
/// Occurs when the user double-clicks the icon in the system tray.
/// </devdoc>
public event EventHandler DoubleClick
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
public event EventHandler MouseClick
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
public event EventHandler MouseDoubleClick
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.MouseDown"]/*' />
/// <devdoc>
/// <para>
/// Occurs when the
/// user presses a mouse button while the pointer is over the icon in the system tray.
/// </para>
/// </devdoc>
public event EventHandler<CPF.Input.NotifyIconMouseEventArgs> MouseDown
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.MouseMove"]/*' />
/// <devdoc>
/// <para>
/// Occurs
/// when the user moves the mouse pointer over the icon in the system tray.
/// </para>
/// </devdoc>
public event EventHandler<NotifyIconMouseEventArgs> MouseMove
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.MouseUp"]/*' />
/// <devdoc>
/// <para>
/// Occurs when the
/// user releases the mouse button while the pointer
/// is over the icon in the system tray.
/// </para>
/// </devdoc>
public event EventHandler<CPF.Input.NotifyIconMouseEventArgs> MouseUp
{
add
{
AddHandler(value);
}
remove
{
RemoveHandler(value);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.Dispose"]/*' />
/// <devdoc>
/// <para>
/// Disposes of the resources (other than memory) used by the
/// <see cref='System.Windows.Forms.NotifyIcon'/>.
/// </para>
/// </devdoc>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (window != null)
{
this.Icon = null;
this.Text = String.Empty;
UpdateIcon(false);
window.DestroyHandle();
window = null;
ContextMenu = null;
if (iconHandle != IntPtr.Zero)
{
UnmanagedMethods.DestroyIcon(iconHandle);
}
iconHandle = IntPtr.Zero;
}
}
//else
//{
// // This same post is done in ControlNativeWindow's finalize method, so if you change
// // it, change it there too.
// //
// if (window != null && window.Handle != IntPtr.Zero)
// {
// UnmanagedMethods.PostMessage(new HandleRef(window, window.Handle), UnmanagedMethods.WindowsMessage.WM_CLOSE, 0, 0);
// window.ReleaseHandle();
// }
//}
base.Dispose(disposing);
}
private void OnBalloonTipClicked()
{
this.RaiseEvent(EventArgs.Empty, nameof(BalloonTipClicked));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnBalloonTipClosed"]/*' />
/// <devdoc>
/// <para>
/// This method raised the BalloonTipClosed event.
/// </para>
/// </devdoc>
private void OnBalloonTipClosed()
{
this.RaiseEvent(EventArgs.Empty, nameof(BalloonTipClosed));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnBalloonTipShown"]/*' />
/// <devdoc>
/// <para>
/// This method raised the BalloonTipShown event.
/// </para>
/// </devdoc>
private void OnBalloonTipShown()
{
this.RaiseEvent(EventArgs.Empty, nameof(BalloonTipShown));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnClick"]/*' />
/// <devdoc>
/// <para>
/// This method actually raises the Click event. Inheriting classes should
/// override this if they wish to be notified of a Click event. (This is far
/// preferable to actually adding an event handler.) They should not,
/// however, forget to call base.onClick(e); before exiting, to ensure that
/// other recipients do actually get the event.
/// </para>
/// </devdoc>
private void OnClick(EventArgs e)
{
RaiseEvent(e, nameof(Click));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnDoubleClick"]/*' />
/// <devdoc>
/// Inheriting classes should override this method to handle this event.
/// Call base.onDoubleClick to send this event to any registered event listeners.
/// </devdoc>
private void OnDoubleClick(EventArgs e)
{
RaiseEvent(e, nameof(DoubleClick));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnMouseClick"]/*' />
/// <devdoc>
/// Inheriting classes should override this method to handle this event.
/// Call base.OnMouseClick to send this event to any registered event listeners.
/// </devdoc>
private void OnMouseClick(NotifyIconMouseEventArgs mea)
{
RaiseEvent(mea, nameof(MouseClick));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnMouseDoubleClick"]/*' />
/// <devdoc>
/// Inheriting classes should override this method to handle this event.
/// Call base.OnMouseDoubleClick to send this event to any registered event listeners.
/// </devdoc>
private void OnMouseDoubleClick(NotifyIconMouseEventArgs mea)
{
RaiseEvent(mea, nameof(MouseDoubleClick));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnMouseDown"]/*' />
/// <devdoc>
/// <para>
/// Raises the <see cref='System.Windows.Forms.NotifyIcon.MouseDown'/> event.
/// Inheriting classes should override this method to handle this event.
/// Call base.onMouseDown to send this event to any registered event listeners.
///
/// </para>
/// </devdoc>
private void OnMouseDown(NotifyIconMouseEventArgs e)
{
RaiseEvent(new Input.NotifyIconMouseEventArgs(e.Button), nameof(MouseDown));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnMouseMove"]/*' />
/// <devdoc>
/// <para>
/// Inheriting classes should override this method to handle this event.
/// Call base.onMouseMove to send this event to any registered event listeners.
///
/// </para>
/// </devdoc>
private void OnMouseMove(NotifyIconMouseEventArgs e)
{
RaiseEvent(e, nameof(MouseMove));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.OnMouseUp"]/*' />
/// <devdoc>
/// <para>
/// Inheriting classes should override this method to handle this event.
/// Call base.onMouseUp to send this event to any registered event listeners.
/// </para>
/// </devdoc>
private void OnMouseUp(NotifyIconMouseEventArgs e)
{
RaiseEvent(new Input.NotifyIconMouseEventArgs(e.Button), nameof(MouseUp));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.ShowBalloonTip"]/*' />
/// <devdoc>
/// <para>
/// Displays a balloon tooltip in the taskbar.
///
/// The system enforces minimum and maximum timeout values. Timeout
/// values that are too large are set to the maximum value and values
/// that are too small default to the minimum value. The operating system's
/// default minimum and maximum timeout values are 10 seconds and 30 seconds,
/// respectively.
///
/// No more than one balloon ToolTip at at time is displayed for the taskbar.
/// If an application attempts to display a ToolTip when one is already being displayed,
/// the ToolTip will not appear until the existing balloon ToolTip has been visible for at
/// least the system minimum timeout value. For example, a balloon ToolTip with timeout
/// set to 30 seconds has been visible for seven seconds when another application attempts
/// to display a balloon ToolTip. If the system minimum timeout is ten seconds, the first
/// ToolTip displays for an additional three seconds before being replaced by the second ToolTip.
/// </para>
/// </devdoc>
public void ShowBalloonTip(int timeout)
{
ShowBalloonTip(timeout, this.BalloonTipTitle, this.BalloonTipText, this.BalloonTipIcon);
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.ShowBalloonTip"]/*' />
/// <devdoc>
/// <para>
/// Displays a balloon tooltip in the taskbar with the specified title,
/// text, and icon for a duration of the specified timeout value.
///
/// The system enforces minimum and maximum timeout values. Timeout
/// values that are too large are set to the maximum value and values
/// that are too small default to the minimum value. The operating system's
/// default minimum and maximum timeout values are 10 seconds and 30 seconds,
/// respectively.
///
/// No more than one balloon ToolTip at at time is displayed for the taskbar.
/// If an application attempts to display a ToolTip when one is already being displayed,
/// the ToolTip will not appear until the existing balloon ToolTip has been visible for at
/// least the system minimum timeout value. For example, a balloon ToolTip with timeout
/// set to 30 seconds has been visible for seven seconds when another application attempts
/// to display a balloon ToolTip. If the system minimum timeout is ten seconds, the first
/// ToolTip displays for an additional three seconds before being replaced by the second ToolTip.
/// </para>
/// </devdoc>
public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon)
{
if (timeout < 0)
{
throw new ArgumentOutOfRangeException("timeout", "ShowBalloonTip超时" + timeout);
}
if (string.IsNullOrEmpty(tipText))
{
throw new ArgumentException("tipText不能为空");
}
//valid values are 0x0 to 0x3
if (!IsEnumValid(tipIcon, (int)tipIcon, (int)ToolTipIcon.None, (int)ToolTipIcon.Error))
{
throw new InvalidEnumArgumentException("tipIcon", (int)tipIcon, typeof(ToolTipIcon));
}
if (added)
{
// Bail if in design mode...
//if (DesignMode)
//{
// return;
//}
//IntSecurity.UnrestrictedWindows.Demand();
UnmanagedMethods.NOTIFYICONDATA data = new UnmanagedMethods.NOTIFYICONDATA();
if (window.Handle == IntPtr.Zero)
{
window.CreateHandle(new CreateParams());
}
data.hWnd = window.Handle;
data.uID = id;
data.uFlags = UnmanagedMethods.NIF_INFO;
data.uTimeoutOrVersion = timeout;
data.szInfoTitle = tipTitle;
data.szInfo = tipText;
switch (tipIcon)
{
case ToolTipIcon.Info: data.dwInfoFlags = UnmanagedMethods.NIIF_INFO; break;
case ToolTipIcon.Warning: data.dwInfoFlags = UnmanagedMethods.NIIF_WARNING; break;
case ToolTipIcon.Error: data.dwInfoFlags = UnmanagedMethods.NIIF_ERROR; break;
case ToolTipIcon.None: data.dwInfoFlags = UnmanagedMethods.NIIF_NONE; break;
}
UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM_MODIFY, data);
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.ShowContextMenu"]/*' />
/// <devdoc>
/// Shows the context menu for the tray icon.
/// </devdoc>
/// <internalonly/>
private void ShowContextMenu()
{
UnmanagedMethods.SetForegroundWindow(window.Handle);
var contextMenu = ContextMenu;
if (contextMenu != null)
{
//UnmanagedMethods.POINT pt;
//UnmanagedMethods.GetCursorPos(out pt);
// VS7 #38994
// The solution to this problem was found in MSDN Article ID: Q135788.
// Summary: the current window must be made the foreground window
// before calling TrackPopupMenuEx, and a task switch must be
// forced after the call.
if (contextMenu != null)
{
contextMenu.Placement = PlacementMode.Mouse;
contextMenu.PopupMarginBottm = 1;
contextMenu.PopupMarginTop = "auto";
contextMenu.IsOpen = true;
//contextMenu.OnPopup(EventArgs.Empty);
//SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle),
// UnmanagedMethods.TPM_VERTICAL | UnmanagedMethods.TPM_RIGHTALIGN,
// pt.x,
// pt.y,
// new HandleRef(window, window.Handle),
// null);
//// Force task switch (see above)
//UnmanagedMethods.PostMessage(new HandleRef(window, window.Handle), UnmanagedMethods.WindowsMessage.WM_NULL, IntPtr.Zero, IntPtr.Zero);
}
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.UpdateIcon"]/*' />
/// <devdoc>
/// Updates the icon in the system tray.
/// </devdoc>
/// <internalonly/>
private void UpdateIcon(bool showIconInTray)
{
lock (syncObj)
{
// Bail if in design mode...
//
//if (DesignMode)
//{
// return;
//}
//IntSecurity.UnrestrictedWindows.Demand();
window.LockReference(showIconInTray);
UnmanagedMethods.NOTIFYICONDATA data = new UnmanagedMethods.NOTIFYICONDATA();
data.uCallbackMessage = WM_TRAYMOUSEMESSAGE;
data.uFlags = UnmanagedMethods.NIF_MESSAGE;
if (showIconInTray)
{
if (window.Handle == IntPtr.Zero)
{
window.CreateHandle(new CreateParams());
}
}
data.hWnd = window.Handle;
data.uID = id;
data.hIcon = IntPtr.Zero;
data.szTip = null;
if (iconHandle != IntPtr.Zero)
{
UnmanagedMethods.DestroyIcon(iconHandle);
}
iconHandle = IntPtr.Zero;
if (Icon != null)
{
data.uFlags |= UnmanagedMethods.NIF_ICON;
var stream = Icon.SaveToStream(ImageFormat.Png);
var states = UnmanagedMethods.GdipCreateBitmapFromStream(new GPStream(stream), out IntPtr bitmap);
stream.Dispose();
UnmanagedMethods.GdipCreateHICONFromBitmap(bitmap, out IntPtr hIcon);
UnmanagedMethods.GdipDisposeImage(bitmap);
iconHandle = hIcon;
data.hIcon = iconHandle;
}
data.uFlags |= UnmanagedMethods.NIF_TIP;
data.szTip = text;
if (showIconInTray && Icon != null)
{
if (!added)
{
UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM_ADD, data);
added = true;
}
else
{
UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM_MODIFY, data);
}
}
else if (added)
{
UnmanagedMethods.Shell_NotifyIcon(UnmanagedMethods.NIM_DELETE, data);
added = false;
}
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.WmMouseDown"]/*' />
/// <devdoc>
/// Handles the mouse-down event
/// </devdoc>
/// <internalonly/>
private void WmMouseDown(ref Message m, MouseButton button, int clicks)
{
if (clicks == 2)
{
OnDoubleClick(new NotifyIconMouseEventArgs(button, 2));
OnMouseDoubleClick(new NotifyIconMouseEventArgs(button, 2));
doubleClick = true;
}
OnMouseDown(new NotifyIconMouseEventArgs(button, clicks));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.WmMouseMove"]/*' />
/// <devdoc>
/// Handles the mouse-move event
/// </devdoc>
/// <internalonly/>
private void WmMouseMove(ref Message m)
{
OnMouseMove(new NotifyIconMouseEventArgs(MouseButton.None, 0));
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.WmMouseUp"]/*' />
/// <devdoc>
/// Handles the mouse-up event
/// </devdoc>
/// <internalonly/>
private void WmMouseUp(ref Message m, MouseButton button)
{
OnMouseUp(new NotifyIconMouseEventArgs(button, 0));
//subhag
if (!doubleClick)
{
OnClick(new NotifyIconMouseEventArgs(button, 0));
OnMouseClick(new NotifyIconMouseEventArgs(button, 0));
}
doubleClick = false;
}
private void WmTaskbarCreated(ref Message m)
{
added = false;
UpdateIcon(visible);
}
private void WndProc(ref Message msg)
{
switch ((UnmanagedMethods.WindowsMessage)msg.Msg)
{
case (UnmanagedMethods.WindowsMessage)WM_TRAYMOUSEMESSAGE:
switch ((UnmanagedMethods.WindowsMessage)msg.LParam)
{
case UnmanagedMethods.WindowsMessage.WM_LBUTTONDBLCLK:
WmMouseDown(ref msg, MouseButton.Left, 2);
break;
case UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN:
WmMouseDown(ref msg, MouseButton.Left, 1);
break;
case UnmanagedMethods.WindowsMessage.WM_LBUTTONUP:
WmMouseUp(ref msg, MouseButton.Left);
break;
case UnmanagedMethods.WindowsMessage.WM_MBUTTONDBLCLK:
WmMouseDown(ref msg, MouseButton.Middle, 2);
break;
case UnmanagedMethods.WindowsMessage.WM_MBUTTONDOWN:
WmMouseDown(ref msg, MouseButton.Middle, 1);
break;
case UnmanagedMethods.WindowsMessage.WM_MBUTTONUP:
WmMouseUp(ref msg, MouseButton.Middle);
break;
case UnmanagedMethods.WindowsMessage.WM_MOUSEMOVE:
WmMouseMove(ref msg);
break;
case UnmanagedMethods.WindowsMessage.WM_RBUTTONDBLCLK:
WmMouseDown(ref msg, MouseButton.Right, 2);
break;
case UnmanagedMethods.WindowsMessage.WM_RBUTTONDOWN:
WmMouseDown(ref msg, MouseButton.Right, 1);
break;
case UnmanagedMethods.WindowsMessage.WM_RBUTTONUP:
//if (ContextMenu != null)
{
ShowContextMenu();
}
WmMouseUp(ref msg, MouseButton.Right);
break;
case (UnmanagedMethods.WindowsMessage)UnmanagedMethods.NIN_BALLOONSHOW:
OnBalloonTipShown();
break;
case (UnmanagedMethods.WindowsMessage)UnmanagedMethods.NIN_BALLOONHIDE:
OnBalloonTipClosed();
break;
case (UnmanagedMethods.WindowsMessage)UnmanagedMethods.NIN_BALLOONTIMEOUT:
OnBalloonTipClosed();
break;
case (UnmanagedMethods.WindowsMessage)UnmanagedMethods.NIN_BALLOONUSERCLICK:
OnBalloonTipClicked();
break;
}
break;
case UnmanagedMethods.WindowsMessage.WM_COMMAND:
if (IntPtr.Zero == msg.LParam)
{
//if (Command.DispatchID((int)msg.WParam & 0xFFFF)) return;
}
else
{
window.DefWndProc(ref msg);
}
break;
case UnmanagedMethods.WindowsMessage.WM_DRAWITEM:
// If the wparam is zero, then the message was sent by a menu.
// See WM_DRAWITEM in MSDN.
if (msg.WParam == IntPtr.Zero)
{
//WmDrawItemMenuItem(ref msg);
}
break;
case UnmanagedMethods.WindowsMessage.WM_MEASUREITEM:
// If the wparam is zero, then the message was sent by a menu.
if (msg.WParam == IntPtr.Zero)
{
//WmMeasureMenuItem(ref msg);
}
break;
case UnmanagedMethods.WindowsMessage.WM_INITMENUPOPUP:
WmInitMenuPopup(ref msg);
break;
case UnmanagedMethods.WindowsMessage.WM_DESTROY:
// Remove the icon from the taskbar
UpdateIcon(false);
break;
default:
if (msg.Msg == WM_TASKBARCREATED)
{
WmTaskbarCreated(ref msg);
}
window.DefWndProc(ref msg);
break;
}
}
private void WmInitMenuPopup(ref Message m)
{
//if (contextMenu != null)
//{
// if (contextMenu.ProcessInitMenuPopup(m.WParam))
// {
// return;
// }
//}
window.DefWndProc(ref m);
}
//private void WmMeasureMenuItem(ref Message m)
//{
// // Obtain the menu item object
// UnmanagedMethods.MEASUREITEMSTRUCT mis = (UnmanagedMethods.MEASUREITEMSTRUCT)m.GetLParam(typeof(UnmanagedMethods.MEASUREITEMSTRUCT));
// Debug.Assert(m.LParam != IntPtr.Zero, "m.lparam is null");
// // A pointer to the correct MenuItem is stored in the measure item
// // information sent with the message.
// // (See MenuItem.CreateMenuItemInfo)
// MenuItem menuItem = MenuItem.GetMenuItemFromItemData(mis.itemData);
// Debug.Assert(menuItem != null, "UniqueID is not associated with a menu item");
// // Delegate this message to the menu item
// if (menuItem != null)
// {
// menuItem.WmMeasureItem(ref m);
// }
//}
//private void WmDrawItemMenuItem(ref Message m)
//{
// // Obtain the menu item object
// UnmanagedMethods.DRAWITEMSTRUCT dis = (UnmanagedMethods.DRAWITEMSTRUCT)m.GetLParam(typeof(UnmanagedMethods.DRAWITEMSTRUCT));
// // A pointer to the correct MenuItem is stored in the draw item
// // information sent with the message.
// // (See MenuItem.CreateMenuItemInfo)
// MenuItem menuItem = MenuItem.GetMenuItemFromItemData(dis.itemData);
// // Delegate this message to the menu item
// if (menuItem != null)
// {
// menuItem.WmDrawItem(ref m);
// }
//}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.NotifyIconNativeWindow"]/*' />
/// <devdoc>
/// Defines a placeholder window that the NotifyIcon is attached to.
/// </devdoc>
/// <internalonly/>
private class NotifyIconNativeWindow : NativeWindow
{
internal NotifyIcon reference;
private GCHandle rootRef; // We will root the control when we do not want to be elligible for garbage collection.
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.NotifyIconNativeWindow.NotifyIconNativeWindow"]/*' />
/// <devdoc>
/// Create a new NotifyIcon, and bind the window to the NotifyIcon component.
/// </devdoc>
/// <internalonly/>
internal NotifyIconNativeWindow(NotifyIcon component)
{
reference = component;
}
~NotifyIconNativeWindow()
{
// This same post is done in Control's Dispose method, so if you change
// it, change it there too.
//
if (Handle != IntPtr.Zero)
{
UnmanagedMethods.PostMessage(Handle, (uint)UnmanagedMethods.WindowsMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
// This releases the handle from our window proc, re-routing it back to
// the system.
}
public void LockReference(bool locked)
{
if (locked)
{
if (!rootRef.IsAllocated)
{
rootRef = GCHandle.Alloc(reference, GCHandleType.Normal);
}
}
else
{
if (rootRef.IsAllocated)
{
rootRef.Free();
}
}
}
/// <include file='doc\TrayIcon.uex' path='docs/doc[@for="NotifyIcon.NotifyIconNativeWindow.WndProc"]/*' />
/// <devdoc>
/// Pass messages on to the NotifyIcon object's wndproc handler.
/// </devdoc>
/// <internalonly/>
protected override void WndProc(ref Message m)
{
Debug.Assert(reference != null, "NotifyIcon was garbage collected while it was still visible. How did we let that happen?");
reference.WndProc(ref m);
}
}
}
/// <include file='doc\ToolTipIcon.uex' path='docs/doc[@for="ToolTipIcon"]/*' />
public enum ToolTipIcon : byte
{
/// <include file='doc\ToolTipIcon.uex' path='docs/doc[@for="ToolTipIcon.None"]/*' />
/// <devdoc>
/// <para>
/// No Icon.
/// </para>
/// </devdoc>
None = 0,
/// <include file='doc\ToolTipIcon.uex' path='docs/doc[@for="ToolTipIcon.InfoIcon"]/*' />
/// <devdoc>
/// <para>
/// A Information Icon.
/// </para>
/// </devdoc>
Info = 1,
/// <include file='doc\ToolTipIcon.uex' path='docs/doc[@for="ToolTipIcon.WarningIcon"]/*' />
/// <devdoc>
/// <para>
/// A Warning Icon.
/// </para>
/// </devdoc>
Warning = 2,
/// <include file='doc\ToolTipIcon.uex' path='docs/doc[@for="ToolTipIcon.ErrorIcon"]/*' />
/// <devdoc>
/// <para>
/// A Error Icon.
/// </para>
/// </devdoc>
Error = 3
}
public class NotifyIconMouseEventArgs : EventArgs
{
public NotifyIconMouseEventArgs(MouseButton button, int clicks)
{
Button = button;
Clicks = clicks;
}
public MouseButton Button { get; set; }
public int Clicks { get; set; }
}
}