Find out Size (and position) of the taskbar

What size is the taskbar on this computer? And where is it at all? This post has the answer.

A common problem is to find out the size and the location of the taskbar.

Almost as common as the problem is the following solution:

public static int GetTaskbarHeight()
{
    return Screen.PrimaryScreen.Bounds.Height - Screen.PrimaryScreen.WorkingArea.Height;
}

At least, it is better than hardcoding the height in code. And it will work on lots of machines.

However, it has some really bad disadvantages:

  • If the taskbar is docked at the left screen side, the code will return a height of 0.
  • If the user has opened the screen magnifier, the height will also be wrong.
  • When using this code, its quite common that you want to show something above the taskbar. If it is docked at the top of the screen, your popup will be displayed at the wrong place
  • Windows 7 related: The user is now able to place the taskbar on a screen other than the primary one.

You see – there has to be a better solution.

Fortunately, there is one:

You can use the Windows API. With some help of pinvoke.net and the MSDN to SHAppBarMessage I was able to write the following helper class:

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;
}

This code works fine (at least on my system ;-) – Windows 7 Ultimate RC) except one little problem: AlwaysOnTop always is false. Maybe this problem is Windows 7 related – I have currently no other system available for testing.

About these ads

6 Responses to “Find out Size (and position) of the taskbar”

  1. Hilfsklasse zur Bestimmung der Position und Gre der Windows Taskbar - MrLeehs Blog Says:

    [...] public int top;    public int right;    public int bottom;} Quelle: Blog von winsharp93 Geschrieben von MrLeeh in Formularhandling, Windows Kommentare: (0) Trackbacks: (0) [...]

  2. EMC-DINESH Says:

    Hi everyone,
    I found a even better solution for only to hide the taskbar. It doesn’t matter where the taskbar is placed but the following code does the job for hiding it.

    public class TaskbarInfo
    {
        [DllImport("user32.dll")]
        private static extern int FindWindow(string className, string windowText);
        [DllImport("user32.dll")]
        private static extern int ShowWindow(int hwnd, int command);
    
        private const int SW_HIDE = 0;
        private const int SW_SHOW = 1;
    
        private int taskbarHeight;
        private int taskbarWidth;
    
        private int taskbarHandle;
    
        public TaskbarInfo()
        {
            taskbarHandle = FindWindow("Shell_TrayWnd", "");
        }
    
        public void Show()
        {
            ShowWindow(taskbarHandle, SW_SHOW);
        }
    
        public void Hide()
        {
            ShowWindow(taskbarHandle, SW_HIDE);
        }
        public int TaskbarHeight
        {
            get
            {
                return (Screen.PrimaryScreen.Bounds.Height - Screen.PrimaryScreen.WorkingArea.Height);
            }
    
        }
        public int TaskbarWidth
        {
            get
            {
                return (Screen.PrimaryScreen.Bounds.Width - Screen.PrimaryScreen.WorkingArea.Width);
            }  
        }
    }
    

    And use the follwing statement for setting the size of the window form.

    recWin = Screen.GetWorkingArea(recWin);
    this.Size = new Size(recWin.Width + tskbarhide.TaskbarWidth, recWin.Height + tskbarhide.TaskbarHeight);

    This will does the job.
    And I’d like to say thanks to the above code for giving me some insights about how to do this.
    Hope someone will get assisted with my code.

  3. winsharp93 Says:

    >> I found a even better solution for only to hide the taskbar
    Well – hiding the taskbar is something different: My code shows how to hide the taskbar automatically when the user moves the mouse away from it.
    I agree with you that using ShowWindow is the right way to permanently hide the taskbar.

    However, the TaskbarHeight and TaskbarWidth properties of your TaskbarInfo are misleading:
    I described the reasons at the beginning of my posting.

  4. Vladekk Says:

    Thank you a lot ;-)

  5. Adrian Says:

    Great code.
    One this I noticed though, you have converted the .rc field to .Bounds and inferred .Location from the .Bounds….

    This is only true if the task-bar is fixed. If the auto-hide is true, then it always gives the fully visible position.

    I wanted to keep a window floating just above the taskbar regardless of its animation state. I also thought I don’t need to query the position of the bar via SHAppBarMessage… a window is a window so plain old GetWindowRect will do the job:

    public sealed class WindowsTaskbar
    {
    private const string ClassName = “Shell_TrayWnd”;

    public static Rectangle TaskbarPostion
    {
    get
    {
    IntPtr taskbarHandle = User32.FindWindow(WindowsTaskbar.ClassName, null);

    RECT r = new RECT();
    User32.GetWindowRect(taskbarHandle, ref r);

    return Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom);
    }
    }
    }

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

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

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
    public int left;
    public int top;
    public int right;
    public int bottom;
    }

  6. Eric Says:

    I don’t know C# (mostly VB.Net and a little Cpp). Using Visual C# 2010 Express I tried to just paste the above code into a new console app, and got 17 compile errors. What am I missing?


Comments are closed.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: