private static bool MouseInNotifyArea() { return(NotifyArea.GetRectangle().Contains(Cursor.Position)); }
private static Rectangle?GetNotifyIconRectangleLegacy(NotifyIcon notifyIcon, bool returnIfHidden) { Rectangle?nirect = null; NativeMethods.NOTIFYICONIDENTIFIER niidentifier; if (!CanGetNotifyIconIdentifier(notifyIcon, out niidentifier)) { return(null); } // find the handle of the task bar IntPtr taskbarparenthandle = NativeMethods.FindWindow("Shell_TrayWnd", null); if (taskbarparenthandle == IntPtr.Zero) { return(null); } // find the handle of the notification area IntPtr naparenthandle = NativeMethods.FindWindowEx(taskbarparenthandle, IntPtr.Zero, "TrayNotifyWnd", null); if (naparenthandle == IntPtr.Zero) { return(null); } // make a list of toolbars in the notification area (one of them should contain the icon) List <IntPtr> natoolbarwindows = NativeMethods.GetChildToolbarWindows(naparenthandle); bool found = false; for (int i = 0; !found && i < natoolbarwindows.Count; i++) { IntPtr natoolbarhandle = natoolbarwindows[i]; // retrieve the number of toolbar buttons (i.e. notify icons) int buttoncount = NativeMethods.SendMessage(natoolbarhandle, NativeMethods.TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32(); // get notification area's process id uint naprocessid; NativeMethods.GetWindowThreadProcessId(natoolbarhandle, out naprocessid); // get handle to notification area's process IntPtr naprocesshandle = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.All, false, naprocessid); if (naprocesshandle == IntPtr.Zero) { return(null); } // allocate enough memory within the notification area's process to store the button info we want IntPtr toolbarmemoryptr = NativeMethods.VirtualAllocEx(naprocesshandle, (IntPtr)null, (uint)Marshal.SizeOf(typeof(NativeMethods.TBBUTTON)), NativeMethods.AllocationType.Commit, NativeMethods.MemoryProtection.ReadWrite); if (toolbarmemoryptr == IntPtr.Zero) { return(null); } try { // loop through the toolbar's buttons until we find our notify icon for (int j = 0; !found && j < buttoncount; j++) { int bytesread = -1; // ask the notification area to give us information about the current button NativeMethods.SendMessage(natoolbarhandle, NativeMethods.TB_GETBUTTON, new IntPtr(j), toolbarmemoryptr); // retrieve that information from the notification area's process NativeMethods.TBBUTTON buttoninfo = new NativeMethods.TBBUTTON(); NativeMethods.ReadProcessMemory(naprocesshandle, toolbarmemoryptr, out buttoninfo, Marshal.SizeOf(buttoninfo), out bytesread); if (bytesread != Marshal.SizeOf(buttoninfo) || buttoninfo.dwData == IntPtr.Zero) { return(null); } // the dwData field contains a pointer to information about the notify icon: // the handle of the notify icon (an 4/8 bytes) and the id of the notify icon (4 bytes) IntPtr niinfopointer = buttoninfo.dwData; // read the notify icon handle IntPtr nihandlenew; NativeMethods.ReadProcessMemory(naprocesshandle, niinfopointer, out nihandlenew, Marshal.SizeOf(typeof(IntPtr)), out bytesread); if (bytesread != Marshal.SizeOf(typeof(IntPtr))) { return(null); } // read the notify icon id uint niidnew; NativeMethods.ReadProcessMemory(naprocesshandle, (IntPtr)((int)niinfopointer + (int)Marshal.SizeOf(typeof(IntPtr))), out niidnew, Marshal.SizeOf(typeof(uint)), out bytesread); if (bytesread != Marshal.SizeOf(typeof(uint))) { return(null); } // if we've found a match if (nihandlenew == niidentifier.hWnd && niidnew == niidentifier.uID) { // check if the button is hidden: if it is, return the rectangle of the 'show hidden icons' button if ((byte)(buttoninfo.fsState & NativeMethods.TBSTATE_HIDDEN) != 0) { if (returnIfHidden) { nirect = NotifyArea.GetButtonRectangle(); } else { return(null); } } else { NativeMethods.RECT result = new NativeMethods.RECT(); // get the relative rectangle of the toolbar button (notify icon) NativeMethods.SendMessage(natoolbarhandle, NativeMethods.TB_GETITEMRECT, new IntPtr(j), toolbarmemoryptr); NativeMethods.ReadProcessMemory(naprocesshandle, toolbarmemoryptr, out result, Marshal.SizeOf(result), out bytesread); if (bytesread != Marshal.SizeOf(result)) { return(null); } // find where the rectangle lies in relation to the screen NativeMethods.MapWindowPoints(natoolbarhandle, (IntPtr)null, ref result, 2); nirect = result; } found = true; } } } finally { // free memory within process NativeMethods.VirtualFreeEx(naprocesshandle, toolbarmemoryptr, 0, NativeMethods.FreeType.Release); // close handle to process NativeMethods.CloseHandle(naprocesshandle); } } return(nirect); }
private void Init() { // Does the owner have an icon set? if (_owner.Icon == null) { throw new InvalidOperationException("SuperNotifyIcon: Dropping cannot be initialised without an icon set!"); } // When the mouse is close MouseHook.MouseMove += MouseHook_MouseMove; // Cancel the drop refreshing below if we do an actual click on the NotifyIcon _owner.NotifyIcon.MouseUp += (sender, e) => { mouseWasInNotifyArea = false; }; // Refresh the drop position if we click in the notification area on Windows 7; we might've moved an icon! if (SysInfo.IsWindows7OrLater) { MouseHook.MouseDown += (sender, e) => { mouseWasInNotifyArea = MouseInNotifyArea(); // Shall we cancel, then? if (e.Button != MouseButtons.Left) { mouseWasInNotifyArea = false; } }; MouseHook.MouseUp += (sender, e) => { if (MouseInNotifyArea() && mouseWasInNotifyArea) { // We should wait for the icon to settle in before doing anything Timer wait = new Timer(); wait.Tick += (sender2, e2) => { if (mouseWasInNotifyArea) { ShowDrop(); } mouseWasInNotifyArea = false; wait.Dispose(); }; wait.Interval = 200; wait.Start(); } }; } // Refresh the drop position if the size of the notification area changes Size notifyAreaLastSize = NotifyArea.GetRectangle().Size; Timer notifyAreaTimer = new Timer(); notifyAreaTimer.Tick += (sender, e) => { if (NotifyArea.GetRectangle().Size != notifyAreaLastSize) { notifyAreaLastSize = NotifyArea.GetRectangle().Size; ShowDrop(); } }; notifyAreaTimer.Interval = 1000; notifyAreaTimer.Start(); // Is the drop even in the right place at all? int unsuccessfulRefreshes = 0; Timer dropPlaceTimer = new Timer(); dropPlaceTimer.Tick += (sender, e) => { if (!NotifyArea.GetRectangle().Contains(new Point(this.Location.X + 2, this.Location.Y + 2))) { ShowDrop(); unsuccessfulRefreshes++; // Don't keep refreshing every second if we can't find our icon! if (unsuccessfulRefreshes >= 3) { dropPlaceTimer.Interval = unsuccessfulRefreshes * 1000; } } else { unsuccessfulRefreshes = 0; dropPlaceTimer.Interval = 1000; } }; dropPlaceTimer.Interval = 1000; dropPlaceTimer.Start(); // Okay... still no success? Let's fall back to the mouse timer... //// TODO: See whether this should only be run on WinXP/Vista systems and whether this should //// run even if we have a valid drop position MouseHoldTimed mouseHold = new MouseHoldTimed(500); mouseHold.MouseDown += (sender, e) => { if (e.Button != MouseButtons.Left || OwnApplicationActive() || !lastNotifyIconPoint.HasValue) { mouseHold.Cancel(); } }; mouseHold.MouseHoldTimeout += (sender, e) => { if (lastNotifyIconPoint.HasValue) { ShowDrop(); } }; }