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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM