c# 任务栏托盘图标鼠标进入MouseEnter和鼠标离开MouseLeave实现

c#的任务栏托盘图标控件NotifyIcon只有MouseMove事件,MouseMove事件刷新很快,很不好用,而且我们有时需要鼠标进入和离开的事件,但是不知道c#怎么回事,没有提供,那么就只能自己来处理了。

解决鼠标进入和离开的思路是:

1.通过MouseMove事件确定当前鼠标已经进入托盘图标的范围

2.进入后启动检测timer

3.定时检测托盘图标的位置和当前鼠标的位置,判断鼠标是否在托盘图标的范围内

主要难点:获取当前托盘图标的位置

获取托盘图标位置的思路:

1.查找到托盘图标所在的窗口

private IntPtr FindTrayToolbarWindow()
        {
            IntPtr hWnd = FindWindow("Shell_TrayWnd", null);
            if (hWnd != IntPtr.Zero)
            {
                hWnd = FindWindowEx(hWnd, IntPtr.Zero, "TrayNotifyWnd", null);
                if (hWnd != IntPtr.Zero)
                {

                    hWnd = FindWindowEx(hWnd, IntPtr.Zero, "SysPager", null);
                    if (hWnd != IntPtr.Zero)
                    {
                        hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);

                    }
                }
            }
            return hWnd;
        }
View Code

2.遍历窗口内的托盘图标

3.获取当前托盘图标的句柄,通过句柄得到这个托盘图标所关联的进程id

4.通过进程id比较获取到当前程序的托盘图标

5.拖过api获取当前托盘图标相对于它所在窗口的位置

6.获取窗口在整个屏幕中的位置,在计算出托盘图标相对于屏幕的位置

   2-6代码:

private bool FindNotifyIcon(IntPtr hTrayWnd, ref Rect rectNotify)
        {
            UInt32 trayPid = 0;
            Rect rectTray = new Rect();
            GetWindowRect(hTrayWnd, out rectTray);
            int count = (int) SendMessage(hTrayWnd, TB_BUTTONCOUNT, 0, IntPtr.Zero); //给托盘窗口发消息,得到托盘里图标

            bool isFind = false;
            if (count > 0)
            {
                GetWindowThreadProcessId(hTrayWnd, out trayPid); //取得托盘窗口对应的进程id
                //获取托盘图标的位置


                IntPtr hProcess = OpenProcess(ProcessAccess.VMOperation | ProcessAccess.VMRead | ProcessAccess.VMWrite,
                    false, trayPid); //打开进程,取得进程句柄

                IntPtr address = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
                    IntPtr.Zero,
                    1024,
                    AllocationType.Commit,
                    MemoryProtection.ReadWrite);


                TBBUTTON btnData = new TBBUTTON();
                TRAYDATA trayData = new TRAYDATA();

                //  Console.WriteLine("Count:"+count);

                var handel = Process.GetCurrentProcess().Id;
                //  Console.WriteLine("curHandel:" + handel);
                for (uint j = 0; j < count; j++)
                {
                    //   Console.WriteLine("j:"+j);
                    var i = j;
                    SendMessage(hTrayWnd, TB_GETBUTTON, i, address); //取得TBBUTTON结构到本地
                    int iTmp = 0;
                    var isTrue = ReadProcessMemory(hProcess,
                        address,
                        out btnData,
                        Marshal.SizeOf(btnData),
                        out iTmp);
                    if (isTrue == false) continue;
                    //这一步至关重要,不能省略
                    //主要解决64位系统电脑运行的是x86的程序
                    if (btnData.dwData == IntPtr.Zero)
                    {
                        btnData.dwData = btnData.iString;
                    }
                    ReadProcessMemory(hProcess, //从目标进程address处存放的是TBBUTTON
                        btnData.dwData, //取dwData字段指向的TRAYDATA结构
                        out trayData,
                        Marshal.SizeOf(trayData),
                        out iTmp);

                    UInt32 dwProcessId = 0;
                    GetWindowThreadProcessId(trayData.hwnd, //通过TRAYDATA里的hwnd字段取得本图标的进程id
                        out dwProcessId);
                    //获取当前进程id
                    //  StringBuilder sb = new StringBuilder(256);
                    //  GetModuleFileNameEx(OpenProcess(ProcessAccess.AllAccess, false, dwProcessId), IntPtr.Zero, sb, 256);
                    //  Console.WriteLine(sb.ToString());
                    if (dwProcessId == (UInt32) handel)
                    {

                        Rect rect = new Rect();
                        IntPtr lngRect = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
                            IntPtr.Zero,
                            Marshal.SizeOf(typeof (Rect)),
                            AllocationType.Commit,
                            MemoryProtection.ReadWrite);
                        i = j;
                        SendMessage(hTrayWnd, TB_GETITEMRECT, i, lngRect);
                        isTrue = ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out iTmp);

                        //释放内存
                        VirtualFreeEx(hProcess, lngRect, Marshal.SizeOf(rect), FreeType.Decommit);
                        VirtualFreeEx(hProcess, lngRect, 0, FreeType.Release);

                        int left = rectTray.Left + rect.Left;
                        int top = rectTray.Top + rect.Top;
                        int botton = rectTray.Top + rect.Bottom;
                        int right = rectTray.Left + rect.Right;
                        rectNotify = new Rect();
                        rectNotify.Left = left;
                        rectNotify.Right = right;
                        rectNotify.Top = top;
                        rectNotify.Bottom = botton;
                        isFind = true;
                        break;
                    } 
                }
                VirtualFreeEx(hProcess, address, 0x4096, FreeType.Decommit);
                VirtualFreeEx(hProcess, address, 0, FreeType.Release);
                CloseHandle(hProcess);
            }
            return isFind;
        }
View Code

7.如果没有找到,那么需要用相同的方法在托盘溢出区域内查找

   private IntPtr FindTrayToolbarOverFlowWindow()
        {
            IntPtr hWnd = FindWindow("NotifyIconOverflowWindow", null);
            if (hWnd != IntPtr.Zero)
            {
                hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
            }
            return hWnd;
        }
View Code

在查找中的难点:

1.对于32位操作系统和64位操作系统,系统内部处理方式不一样,所以许多时候当去取TBBUTTON结构到本地的时候得到的地址为0,这里查询了一些资料,网上一些资料TBBUTTON的结构体如下:

  [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct TBBUTTON
        {
            public int iBitmap;
            public int idCommand;
            public byte fsState;
            public byte fsStyle;
            public byte bReserved0;
            public byte bReserved1;
            public IntPtr dwData;
            public IntPtr iString;
        }
View Code

这个在32位下面没有问题,但是在64位系统下就出现了问题,后面参考网上一些资料,原来问题出在中间4个byte中,由于32位系统中4个byte刚好32位,但是在64位中这里就不对,所以就修改为如下:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct TBBUTTON
        {
            public int iBitmap;
            public int idCommand;
            public IntPtr fsStateStylePadding;
            public IntPtr dwData;
            public IntPtr iString;
        }
View Code

修改过后在64位系统中运行通过了,在这样一位问题解决了,但是当我将解决方案迁移到程序当中的时候,却出了问题,一直不能得到地址,查找了很多原因,原来是在我程序编译的时候,生成的平台是X86,那么就造成了64位系统中使用32位平台时出现问题:

到这里我就猜想是不是 public IntPtr fsStateStylePadding;这一句出了问题,当时x86平台的时候,这个只占用了32位,但是实际64位系统这个位置应该要占用64位,造成地址不对,出错了。

那么接下来我就证实了下这个问题,在我获取地址的时候在public IntPtr dwData;字段中没有获取到,但是在public IntPtr iString;字段中获取到了,那么证明我的猜想是对的(真正是否正确还需要指正),

那么解决方案就来了,为了更好的兼容性,结构体不变,当获取dwData地址没有获取到的时候,我们查找iString字段就好了,方法在这里:

//这一步至关重要,不能省略
                    //主要解决64位系统电脑运行的是x86的程序
                    if (btnData.dwData == IntPtr.Zero)
                    {
                        btnData.dwData = btnData.iString;
                    }
View Code

把这个主要的解决了,后面就是查找当前托盘图标相对于父窗体的位置了,使用了很多方法:

GetWindowRect

ScreenToClient

GetClientRect

这些方法都没有成功,最后发现网上有这么一种方法。

 SendMessage(hTrayWnd, TB_GETITEMRECT, i, lngRect);
                        isTrue = ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out iTmp);
View Code

在这里真正感受到c++的强大。

在解决这个问题的过程中,参考了很多方案,通过整合才解决了这个问题,如下:

http://blog.163.com/zjlovety@126/blog/static/22418624201142763542917/

http://blog.csdn.net/wzsy/article/details/47980317

http://www.cnblogs.com/hanf/archive/2011/08/09/2131641.html

等。

以下是调用方法:

  private void Load()
        {
            this._notifyIcon.MouseDoubleClick += notifyIcon_MouseDoubleClick;
            _notifyIcon.MouseMove += new MouseEventHandler(notifyIcon_MouseMove);
            CreateNotifyMouseHelper();
        }

 private NotifyIconMouseHelper notifyHelper;
        private Timer timer = null;
 private void CreateNotifyMouseHelper()
        {
            notifyHelper=new NotifyIconMouseHelper();
            notifyHelper.MouseEnterNotifyStatusChanged+= MouseEnterNotifyStatusChanged;
        }
 private void MouseEnterNotifyStatusChanged(object sender, bool isEnter)
        {
           
            if (isEnter)
            {
              Console.WriteLine("鼠标进入");
            }
            else
            {
              Console.WriteLine("鼠标离开");
            }
        }
View Code

以下是检测的源代码:

using System;
using System.Collections.Generic;
using System.Data.Entity.Core.Metadata.Edm;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Timers;
using System.Windows;

namespace NotifyTest
{
    /*托盘图标鼠标进入离开事件
     */

    public delegate void MouseEnterNotifyStatusChangedHandel(object sender, bool isEnter);

    public class NotifyIconMouseHelper
    {
        #region win32类库 

        [Flags()]
        public enum ProcessAccess : int
        {
            /// <summary>Specifies all possible access flags for the process object.</summary>
            AllAccess =
                CreateThread | DuplicateHandle | QueryInformation | SetInformation | Terminate | VMOperation | VMRead |
                VMWrite | Synchronize,

            /// <summary>Enables usage of the process handle in the CreateRemoteThread function to create a thread in the process.</summary>
            CreateThread = 0x2,

            /// <summary>Enables usage of the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.</summary>
            DuplicateHandle = 0x40,

            /// <summary>Enables usage of the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.</summary>
            QueryInformation = 0x400,

            /// <summary>Enables usage of the process handle in the SetPriorityClass function to set the priority class of the process.</summary>
            SetInformation = 0x200,

            /// <summary>Enables usage of the process handle in the TerminateProcess function to terminate the process.</summary>
            Terminate = 0x1,

            /// <summary>Enables usage of the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.</summary>
            VMOperation = 0x8,

            /// <summary>Enables usage of the process handle in the ReadProcessMemory function to' read from the virtual memory of the process.</summary>
            VMRead = 0x10,

            /// <summary>Enables usage of the process handle in the WriteProcessMemory function to write to the virtual memory of the process.</summary>
            VMWrite = 0x20,

            /// <summary>Enables usage of the process handle in any of the wait functions to wait for the process to terminate.</summary>
            Synchronize = 0x100000
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct TRAYDATA
        {
            public IntPtr hwnd;
            public UInt32 uID;
            public UInt32 uCallbackMessage;
            public UInt32 bReserved0;
            public UInt32 bReserved1;
            public IntPtr hIcon;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct TBBUTTON
        {
            public int iBitmap;
            public int idCommand;
            public IntPtr fsStateStylePadding;
            public IntPtr dwData;
            public IntPtr iString;
        }

        [Flags]
        public enum AllocationType
        {
            Commit = 0x1000,
            Reserve = 0x2000,
            Decommit = 0x4000,
            Release = 0x8000,
            Reset = 0x80000,
            Physical = 0x400000,
            TopDown = 0x100000,
            WriteWatch = 0x200000,
            LargePages = 0x20000000
        }

        [Flags]
        public enum MemoryProtection
        {
            Execute = 0x10,
            ExecuteRead = 0x20,
            ExecuteReadWrite = 0x40,
            ExecuteWriteCopy = 0x80,
            NoAccess = 0x01,
            ReadOnly = 0x02,
            ReadWrite = 0x04,
            WriteCopy = 0x08,
            GuardModifierflag = 0x100,
            NoCacheModifierflag = 0x200,
            WriteCombineModifierflag = 0x400
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
            string lpszWindow);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        [DllImport("kernel32.dll")]
        private static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess,
            [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg, UInt32 wParam, IntPtr lParam);

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
            int dwSize, AllocationType flAllocationType, MemoryProtection flProtect);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool ReadProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            out TBBUTTON lpBuffer,
            int dwSize,
            out int lpNumberOfBytesRead
            );

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool ReadProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            out Rect lpBuffer,
            int dwSize,
            out int lpNumberOfBytesRead
            );

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool ReadProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            out TRAYDATA lpBuffer,
            int dwSize,
            out int lpNumberOfBytesRead
            );

        [DllImport("psapi.dll")]
        private static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName,
            [In] [MarshalAs(UnmanagedType.U4)] int nSize);

        [Flags]
        public enum FreeType
        {
            Decommit = 0x4000,
            Release = 0x8000,
        }

        [DllImport("kernel32.dll")]
        private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, FreeType dwFreeType);

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr hObject);

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public override string ToString()
            {
                return ("X:" + X + ", Y:" + Y);
            }
        }

        [DllImport("user32")]
        public static extern bool GetClientRect(
            IntPtr hwnd,
            out Rect lpRect
            );

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool GetCursorPos(out POINT pt);


        [StructLayout(LayoutKind.Sequential)]
        public struct Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [DllImport("user32.dll")]
        private static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);

        public const int WM_USER = 0x0400;
        public const int TB_BUTTONCOUNT = WM_USER + 24;
        public const int TB_GETBUTTON = WM_USER + 23;
        public const int TB_GETBUTTONINFOW = WM_USER + 63;
        public const int TB_GETITEMRECT = WM_USER + 29;

        #endregion

        #region 检测托盘图标相对于屏幕位置

        private bool FindNotifyIcon(ref Rect rect)
        {
            Rect rectNotify = new Rect();
            IntPtr hTrayWnd = FindTrayToolbarWindow(); //找到托盘窗口句柄
            var isTrue = FindNotifyIcon(hTrayWnd, ref rectNotify);
            if (isTrue == false)
            {
                hTrayWnd = FindTrayToolbarOverFlowWindow(); //找到托盘窗口句柄
                isTrue = FindNotifyIcon(hTrayWnd, ref rectNotify);
            }
            rect = rectNotify;
            return isTrue;
        }

        private IntPtr FindTrayToolbarWindow()
        {
            IntPtr hWnd = FindWindow("Shell_TrayWnd", null);
            if (hWnd != IntPtr.Zero)
            {
                hWnd = FindWindowEx(hWnd, IntPtr.Zero, "TrayNotifyWnd", null);
                if (hWnd != IntPtr.Zero)
                {

                    hWnd = FindWindowEx(hWnd, IntPtr.Zero, "SysPager", null);
                    if (hWnd != IntPtr.Zero)
                    {
                        hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);

                    }
                }
            }
            return hWnd;
        }

        private IntPtr FindTrayToolbarOverFlowWindow()
        {
            IntPtr hWnd = FindWindow("NotifyIconOverflowWindow", null);
            if (hWnd != IntPtr.Zero)
            {
                hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
            }
            return hWnd;
        }

        private bool FindNotifyIcon(IntPtr hTrayWnd, ref Rect rectNotify)
        {
            UInt32 trayPid = 0;
            Rect rectTray = new Rect();
            GetWindowRect(hTrayWnd, out rectTray);
            int count = (int) SendMessage(hTrayWnd, TB_BUTTONCOUNT, 0, IntPtr.Zero); //给托盘窗口发消息,得到托盘里图标

            bool isFind = false;
            if (count > 0)
            {
                GetWindowThreadProcessId(hTrayWnd, out trayPid); //取得托盘窗口对应的进程id
                //获取托盘图标的位置


                IntPtr hProcess = OpenProcess(ProcessAccess.VMOperation | ProcessAccess.VMRead | ProcessAccess.VMWrite,
                    false, trayPid); //打开进程,取得进程句柄

                IntPtr address = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
                    IntPtr.Zero,
                    1024,
                    AllocationType.Commit,
                    MemoryProtection.ReadWrite);


                TBBUTTON btnData = new TBBUTTON();
                TRAYDATA trayData = new TRAYDATA();

                //  Console.WriteLine("Count:"+count);

                var handel = Process.GetCurrentProcess().Id;
                //  Console.WriteLine("curHandel:" + handel);
                for (uint j = 0; j < count; j++)
                {
                    //   Console.WriteLine("j:"+j);
                    var i = j;
                    SendMessage(hTrayWnd, TB_GETBUTTON, i, address); //取得TBBUTTON结构到本地
                    int iTmp = 0;
                    var isTrue = ReadProcessMemory(hProcess,
                        address,
                        out btnData,
                        Marshal.SizeOf(btnData),
                        out iTmp);
                    if (isTrue == false) continue;
                    //这一步至关重要,不能省略
                    //主要解决64位系统电脑运行的是x86的程序
                    if (btnData.dwData == IntPtr.Zero)
                    {
                        btnData.dwData = btnData.iString;
                    }
                    ReadProcessMemory(hProcess, //从目标进程address处存放的是TBBUTTON
                        btnData.dwData, //取dwData字段指向的TRAYDATA结构
                        out trayData,
                        Marshal.SizeOf(trayData),
                        out iTmp);

                    UInt32 dwProcessId = 0;
                    GetWindowThreadProcessId(trayData.hwnd, //通过TRAYDATA里的hwnd字段取得本图标的进程id
                        out dwProcessId);
                    //获取当前进程id
                    //  StringBuilder sb = new StringBuilder(256);
                    //  GetModuleFileNameEx(OpenProcess(ProcessAccess.AllAccess, false, dwProcessId), IntPtr.Zero, sb, 256);
                    //  Console.WriteLine(sb.ToString());
                    if (dwProcessId == (UInt32) handel)
                    {

                        Rect rect = new Rect();
                        IntPtr lngRect = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
                            IntPtr.Zero,
                            Marshal.SizeOf(typeof (Rect)),
                            AllocationType.Commit,
                            MemoryProtection.ReadWrite);
                        i = j;
                        SendMessage(hTrayWnd, TB_GETITEMRECT, i, lngRect);
                        isTrue = ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out iTmp);

                        //释放内存
                        VirtualFreeEx(hProcess, lngRect, Marshal.SizeOf(rect), FreeType.Decommit);
                        VirtualFreeEx(hProcess, lngRect, 0, FreeType.Release);

                        int left = rectTray.Left + rect.Left;
                        int top = rectTray.Top + rect.Top;
                        int botton = rectTray.Top + rect.Bottom;
                        int right = rectTray.Left + rect.Right;
                        rectNotify = new Rect();
                        rectNotify.Left = left;
                        rectNotify.Right = right;
                        rectNotify.Top = top;
                        rectNotify.Bottom = botton;
                        isFind = true;
                        break;
                    } 
                }
                VirtualFreeEx(hProcess, address, 0x4096, FreeType.Decommit);
                VirtualFreeEx(hProcess, address, 0, FreeType.Release);
                CloseHandle(hProcess);
            }
            return isFind;
        }

        #endregion


        public MouseEnterNotifyStatusChangedHandel MouseEnterNotifyStatusChanged;
        private object moveObject = new object();
        private bool isOver = false;
        private Timer timer = null;

        public void MouseEnter()
        {
            lock (moveObject)
            {
                if (isOver) return;

                //加载鼠标进入事件
                MouseEnter(true);
                CreateCheckTimer();
                timer.Enabled = true;
            }
        }

        private void CreateCheckTimer()
        {
            if (timer != null) return;
            timer = new Timer();
            timer.Interval = 120;
            timer.Elapsed += TimerOnElapsed;
        }

        private void TimerOnElapsed(object sender, ElapsedEventArgs arg)
        {
            //300毫秒检测一次
            //判断鼠标是否在托盘图标内
            //如果在,那么就不管
            //如果不在,就加载鼠标离开事件,同时停止timer
            var isEnter = CheckMouseIsEnter();
            if (isEnter) return;
            timer.Enabled = false;
            MouseEnter(false);
        }

        private void MouseEnter(bool isEnter)
        {
            isOver = isEnter;
            if (MouseEnterNotifyStatusChanged == null) return;
            MouseEnterNotifyStatusChanged(this, isEnter);
        }

        public Point Point { get; set; }

        private bool CheckMouseIsEnter()
        {
            //这里怎么检测呢
            //我很无语啊 
            //第一步:获取当前鼠标的坐标
            //第二步:获取托盘图标的坐标
            //   ???? 难难难难难难难难难难
            try
            {

                Rect rectNotify = new Rect();
                var isTrue = FindNotifyIcon(ref rectNotify);
                if (isTrue == false) return false;
                POINT point = new POINT();
                GetCursorPos(out point);
//            Console.WriteLine(string.Format(@"
//Left={0} Top={1} Right={2} Bottom={3}", rectNotify.Left, rectNotify.Top, rectNotify.Right, rectNotify.Bottom));
//            Console.WriteLine(point.X + "  " + point.Y);
                //第三步:比较鼠标图标是否在托盘图标的范围内
                if (point.X >= rectNotify.Left && point.X <= rectNotify.Right &&
                    point.Y >= rectNotify.Top && point.Y <= rectNotify.Bottom)
                {
                    Point = new Point(point.X, point.Y);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/sczmzx/p/5158127.html