Position form above the clicked notify icon
Asked Answered
S

2

4

Is there a way to position a form just above the clicked Notify Icon in windows 7 and windows Vista?

Sketch answered 3/9, 2011 at 18:0 Comment(6)
does this help u? codetechnic.blogspot.com/2009/03/…Evolve
no that positions the form in the right bottom corner above the taskbar. I need to position it above the notify icon.Sketch
Possible duplicate: #273278Cripple
You can't, as explained in the dup. There is one thing you do know: where the mouse is located. It won't be far from the icon. Don't forget that the taskbar could be on any of the 4 sides of the screen.Obliterate
aha ok thanks, how could i know how is the taskbar positioned?Sketch
The right click message tells you the mouse location. You just need to click that to the work area and make sure that your form doesn't span multiple monitors.Tavish
P
1

Regarding your comment: "how could i know how is the taskbar positioned?"

Check out the following article which contains a class which exposes a method for retrieving a Rectangle Structure for the tray: [c#] NotifyIcon - Detect MouseOut

Using this class you can retrieve the Rectangle Structure for the tray like so:

Rectangle trayRectangle = WinAPI.GetTrayRectangle();

Which will provide you with the Top, Left, Right and Bottom coordinates for the tray along with its width and height.

I have included the class below:

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.ComponentModel;

public class WinAPI
{
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public override string ToString()
        {
            return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")";
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string strClassName, string strWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);


    public static IntPtr GetTrayHandle()
    {
        IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null);
        if (!taskBarHandle.Equals(IntPtr.Zero))
        {
            return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
        }
        return IntPtr.Zero;
    }

    public static Rectangle GetTrayRectangle()
    {
        WinAPI.RECT rect;
        WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect);
        return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1));
    }
}

Hope this helps.

Plywood answered 3/9, 2011 at 18:33 Comment(6)
That is a grotesque hack. Why on earth would you do that rather than read out the cursor pos from the right click event? Why resort to hacks when you can do it properly?Tavish
@David Heffernan what would be the proper way to get how the taskbar is positioned? i just need to know if it's on the left/right/top/bottom.Sketch
@Sketch Hans already explained that you can't locate your icon. What you can do is get the cursor pos of the event that invoked your icons context menu. From that you can work out which corner.Tavish
Either method would work. The code I posted would retrieve the coordinates for the tray, the mouse cursor position will give you the approx position of the tray icon. The way I see it, you could combine the two to position your form. Determining the location of the task bar could be inferred from the coordinates or mouse position.Plywood
@Plywood the difference is that your method relies on undocumented implementation details which is why I turned my nose up at it.Tavish
For what it is worth, I am trying to locate a tray icon not during a click event, so for me this hack would work. I agree that hanging on undocumented implementation details is very fishy, but it is a close solution to my problem.Dizzy
W
8

Here is an easier way.

You can get X,Y position of the mouse when the OnClick event is fired. You can also get the taskbar position with somes checks from these objects Screen.PrimaryScreen.Bounds, Screen.PrimaryScreen.WorkingArea.

    private void OnTrayClick(object sender, EventArgs e)
    {
        _frmMain.Left = Cursor.Position.X;
        _frmMain.Top = Screen.PrimaryScreen.WorkingArea.Bottom -_frmMain.Height;
        _frmMain.Show();        
    }
Welloff answered 6/7, 2014 at 20:45 Comment(2)
This is bar far the nicest solution I saw, apart from the case when tray is located on the right side on the screen, not at the bottom...Sucrase
This made my day! :) Small enhancement for multiple screens: trayIcon.ContextMenuStrip.Show(Cursor.Position); // should be first as height is initially not correct... trayIcon.ContextMenuStrip.Left = Math.Min(Cursor.Position.X, Screen.PrimaryScreen.WorkingArea.Right - trayIcon.ContextMenuStrip.Width); // for multiple monitors and different placements of task bar trayIcon.ContextMenuStrip.Top = Screen.PrimaryScreen.WorkingArea.Bottom - trayIcon.ContextMenuStrip.Height;Tirade
P
1

Regarding your comment: "how could i know how is the taskbar positioned?"

Check out the following article which contains a class which exposes a method for retrieving a Rectangle Structure for the tray: [c#] NotifyIcon - Detect MouseOut

Using this class you can retrieve the Rectangle Structure for the tray like so:

Rectangle trayRectangle = WinAPI.GetTrayRectangle();

Which will provide you with the Top, Left, Right and Bottom coordinates for the tray along with its width and height.

I have included the class below:

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.ComponentModel;

public class WinAPI
{
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public override string ToString()
        {
            return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")";
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string strClassName, string strWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);


    public static IntPtr GetTrayHandle()
    {
        IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null);
        if (!taskBarHandle.Equals(IntPtr.Zero))
        {
            return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
        }
        return IntPtr.Zero;
    }

    public static Rectangle GetTrayRectangle()
    {
        WinAPI.RECT rect;
        WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect);
        return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1));
    }
}

Hope this helps.

Plywood answered 3/9, 2011 at 18:33 Comment(6)
That is a grotesque hack. Why on earth would you do that rather than read out the cursor pos from the right click event? Why resort to hacks when you can do it properly?Tavish
@David Heffernan what would be the proper way to get how the taskbar is positioned? i just need to know if it's on the left/right/top/bottom.Sketch
@Sketch Hans already explained that you can't locate your icon. What you can do is get the cursor pos of the event that invoked your icons context menu. From that you can work out which corner.Tavish
Either method would work. The code I posted would retrieve the coordinates for the tray, the mouse cursor position will give you the approx position of the tray icon. The way I see it, you could combine the two to position your form. Determining the location of the task bar could be inferred from the coordinates or mouse position.Plywood
@Plywood the difference is that your method relies on undocumented implementation details which is why I turned my nose up at it.Tavish
For what it is worth, I am trying to locate a tray icon not during a click event, so for me this hack would work. I agree that hanging on undocumented implementation details is very fishy, but it is a close solution to my problem.Dizzy

© 2022 - 2025 — McMap. All rights reserved.