.NET: How to place my window near the notification area (systray)?
Asked Answered
O

2

10

I'd like to display a little popup window next to the notification area. It's similar to what Outlook/Skype/Live! Messenger/etc does when it displays the notification about a new message. In my case it will have some input controls (textbox, datetimepicker, buttons...) so a simple bubble won't do.

The trick is doing this correctly when the user has multiple monitors and/or the taskbar is not located at the bottom of the screen. I could not find any functions that would let me determine the position and orientation of the taskbar/notification area.

Overlay answered 26/4, 2010 at 9:12 Comment(2)
any all complete source code sample ?Boob
@alhambraeidos - I think the accepted answer contains all the information you need. I don't have the source code online, but it's not very difficult to make something like that. Do you have any specific problems?Overlay
B
9

Use WinAPI calls to find the TaskBar position, and position your window according to it

C# Example

class Program
{
    static void Main(string[] args)
    {
        Taskbar taskbar = new Taskbar();
        Console.WriteLine("Position: {0}, AlwaysOnTop: {1}; AutoHide: {2}; Bounds: {3}", taskbar.Position, taskbar.AlwaysOnTop, taskbar.AutoHide, taskbar.Bounds);

        Console.ReadLine();
    }
}

public enum TaskbarPosition
{
    Unknown = -1,
    Left,
    Top,
    Right,
    Bottom,
}

public sealed class Taskbar
{
    private const string ClassName = "Shell_TrayWnd";

    public Rectangle Bounds
    {
        get;
        private set;
    }
    public TaskbarPosition Position
    {
        get;
        private set;
    }
    public Point Location
    {
        get
        {
            return this.Bounds.Location;
        }
    }
    public Size Size
    {
        get
        {
            return this.Bounds.Size;
        }
    }
    //Always returns false under Windows 7
    public bool AlwaysOnTop
    {
        get;
        private set;
    }
    public bool AutoHide
    {
        get;
        private set;
    }

    public Taskbar()
    {
        IntPtr taskbarHandle = User32.FindWindow(Taskbar.ClassName, null);

        APPBARDATA data = new APPBARDATA();
        data.cbSize = (uint) Marshal.SizeOf(typeof(APPBARDATA));
        data.hWnd = taskbarHandle;
        IntPtr result = Shell32.SHAppBarMessage(ABM.GetTaskbarPos, ref data);
        if (result == IntPtr.Zero)
            throw new InvalidOperationException();

        this.Position = (TaskbarPosition) data.uEdge;
        this.Bounds = Rectangle.FromLTRB(data.rc.left, data.rc.top, data.rc.right, data.rc.bottom);

        data.cbSize = (uint) Marshal.SizeOf(typeof(APPBARDATA));
        result = Shell32.SHAppBarMessage(ABM.GetState, ref data);
        int state = result.ToInt32();
        this.AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop;
        this.AutoHide = (state & ABS.Autohide) == ABS.Autohide;
    }
}

public enum ABM : uint
{
    New = 0x00000000,
    Remove = 0x00000001,
    QueryPos = 0x00000002,
    SetPos = 0x00000003,
    GetState = 0x00000004,
    GetTaskbarPos = 0x00000005,
    Activate = 0x00000006,
    GetAutoHideBar = 0x00000007,
    SetAutoHideBar = 0x00000008,
    WindowPosChanged = 0x00000009,
    SetState = 0x0000000A,
}

public enum ABE : uint
{
    Left = 0,
    Top = 1,
    Right = 2,
    Bottom = 3
}

public static class ABS
{
    public const int Autohide = 0x0000001;
    public const int AlwaysOnTop = 0x0000002;
}

public static class Shell32
{
    [DllImport("shell32.dll", SetLastError = true)]
    public static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
}

public static class User32
{
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}

[StructLayout(LayoutKind.Sequential)]
public struct APPBARDATA
{
    public uint cbSize;
    public IntPtr hWnd;
    public uint uCallbackMessage;
    public ABE uEdge;
    public RECT rc;
    public int lParam;
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}
Berezina answered 26/4, 2010 at 9:22 Comment(3)
Hard-codes the taskbar class name, though, which isn't a contract but an implementation detail. And what about people using another shell?Hemicycle
codeproject.com/KB/shell/trayposition.aspx Another approach consinder the comment from johannes rössel, simple to port to C# imoBerezina
@Johannes: I haven't seen custom shells since Windows 98 went extinct. And if you're using a custom shell then there are no guarantees that there is a notification area at all, so all this becomes meaningless. But you do have a point, so I'll put a check in the code. If the window will not be found, my window will be displayed at the bottom right of the primary monitor.Overlay
H
0

You need to get the actual location of your notification icon, and place your pop-up window near that (or wherever you like).

You need to translate your XY locations relative to desktop(s). AFAIK, there are no direct function, even in Win32 API which can directly give you the answer.

These sites will help you-
1. http://forum.codecall.net/managed-c/262-dual-monitors-window-position.html
2. http://msdn.microsoft.com/en-us/magazine/cc188759.aspx

Hards answered 26/4, 2010 at 9:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.