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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值