How do I get the taskbar's position and size?

Solution 1:

    private enum TaskBarLocation { TOP, BOTTOM, LEFT, RIGHT}

    private TaskBarLocation GetTaskBarLocation()
    {
        TaskBarLocation taskBarLocation = TaskBarLocation.BOTTOM;
        bool taskBarOnTopOrBottom = (Screen.PrimaryScreen.WorkingArea.Width == Screen.PrimaryScreen.Bounds.Width);
        if (taskBarOnTopOrBottom)
        {
            if (Screen.PrimaryScreen.WorkingArea.Top > 0) taskBarLocation = TaskBarLocation.TOP;
        }
        else
        {
            if (Screen.PrimaryScreen.WorkingArea.Left > 0)
            {
                taskBarLocation = TaskBarLocation.LEFT;
            }
            else
            {
                taskBarLocation = TaskBarLocation.RIGHT;
            }
        }
        return taskBarLocation;
    }

Solution 2:

It's actually way more complicated than is shown above. For one thing, the task bar doesn't have to be on the primary screen, it can be dragged to any screen. For another, in theory there could be something docked on each edge of each given screen. The code above incorrectly assumes that finding something docked to one edge excludes all other edges.

The only way the location of the task bar could be definitively derived from bounds vs workingarea, would be if only one edge out of all screens had something docked to it.

The following function returns an array of Rectangles, each representing a docked task bar, and writes the count to its byref parameter. If that count is 1, element 0 of the returned array is the Rectangle occupied by the task bar. If greater than 1, time to guess?

Public Function FindDockedTaskBars(ByRef DockedRectCounter As Integer) As Rectangle()
    Dim TmpScrn As Screen = Nothing
    Dim LeftDockedWidth As Integer = 0
    Dim TopDockedHeight As Integer = 0
    Dim RightDockedWidth As Integer = 0
    Dim BottomDockedHeight As Integer = 0
    Dim DockedRects(Screen.AllScreens.Count * 4) As Rectangle

    DockedRectCounter = 0

    For Each TmpScrn In Screen.AllScreens
        If Not TmpScrn.Bounds.Equals(TmpScrn.WorkingArea) Then
            LeftDockedWidth = Math.Abs(Math.Abs(TmpScrn.Bounds.Left) - Math.Abs(TmpScrn.WorkingArea.Left))
            TopDockedHeight = Math.Abs(Math.Abs(TmpScrn.Bounds.Top) - Math.Abs(TmpScrn.WorkingArea.Top))
            RightDockedWidth = (TmpScrn.Bounds.Width - LeftDockedWidth) - TmpScrn.WorkingArea.Width
            BottomDockedHeight = (TmpScrn.Bounds.Height - TopDockedHeight) - TmpScrn.WorkingArea.Height

            If LeftDockedWidth > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.Bounds.Left
                DockedRects(DockedRectCounter).Y = TmpScrn.Bounds.Top
                DockedRects(DockedRectCounter).Width = LeftDockedWidth
                DockedRects(DockedRectCounter).Height = TmpScrn.Bounds.Height
                DockedRectCounter += 1
            End If
            If RightDockedWidth > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.WorkingArea.Right
                DockedRects(DockedRectCounter).Y = TmpScrn.Bounds.Top
                DockedRects(DockedRectCounter).Width = RightDockedWidth
                DockedRects(DockedRectCounter).Height = TmpScrn.Bounds.Height
                DockedRectCounter += 1
            End If
            If TopDockedHeight > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.WorkingArea.Left
                DockedRects(DockedRectCounter).Y = TmpScrn.Bounds.Top
                DockedRects(DockedRectCounter).Width = TmpScrn.WorkingArea.Width
                DockedRects(DockedRectCounter).Height = TopDockedHeight
                DockedRectCounter += 1
            End If
            If BottomDockedHeight > 0 Then
                DockedRects(DockedRectCounter).X = TmpScrn.WorkingArea.Left
                DockedRects(DockedRectCounter).Y = TmpScrn.WorkingArea.Bottom
                DockedRects(DockedRectCounter).Width = TmpScrn.WorkingArea.Width
                DockedRects(DockedRectCounter).Height = BottomDockedHeight
                DockedRectCounter += 1
            End If
        End If
    Next
    Return DockedRects
End Function

Or for those of you who prefer C#... (Note: this ported code is untested)

using System.Drawing;
using System.Windows.Forms;

public Rectangle[] FindDockedTaskBars(ref int DockedRectCounter)
{
    int LeftDockedWidth = 0;
    int TopDockedHeight = 0;
    int RightDockedWidth = 0;
    int BottomDockedHeight = 0;
    Rectangle[] DockedRects = new Rectangle[Screen.AllScreens.Count() * 4]; 

    DockedRectCounter = 0;
    foreach (Screen TmpScrn in Screen.AllScreens)
    {
        if (!TmpScrn.Bounds.Equals(TmpScrn.WorkingArea))
        {
            LeftDockedWidth = Math.Abs(Math.Abs(TmpScrn.Bounds.Left) - Math.Abs(TmpScrn.WorkingArea.Left));
            TopDockedHeight = Math.Abs(Math.Abs(TmpScrn.Bounds.Top) - Math.Abs(TmpScrn.WorkingArea.Top));
            RightDockedWidth = (TmpScrn.Bounds.Width - LeftDockedWidth) - TmpScrn.WorkingArea.Width;
            BottomDockedHeight = (TmpScrn.Bounds.Height - TopDockedHeight) - TmpScrn.WorkingArea.Height;

            if (LeftDockedWidth > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.Bounds.Left;
                DockedRects[DockedRectCounter].Y = TmpScrn.Bounds.Top;
                DockedRects[DockedRectCounter].Width = LeftDockedWidth;
                DockedRects[DockedRectCounter].Height = TmpScrn.Bounds.Height;
                DockedRectCounter += 1;
            }

            if (RightDockedWidth > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.WorkingArea.Right;
                DockedRects[DockedRectCounter].Y = TmpScrn.Bounds.Top;
                DockedRects[DockedRectCounter].Width = RightDockedWidth;
                DockedRects[DockedRectCounter].Height = TmpScrn.Bounds.Height;
                DockedRectCounter += 1;
            }
            if (TopDockedHeight > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.WorkingArea.Left;
                DockedRects[DockedRectCounter].Y = TmpScrn.Bounds.Top;
                DockedRects[DockedRectCounter].Width = TmpScrn.WorkingArea.Width;
                DockedRects[DockedRectCounter].Height = TopDockedHeight;
                DockedRectCounter += 1;
            }
            if (BottomDockedHeight > 0)
            {
                DockedRects[DockedRectCounter].X = TmpScrn.WorkingArea.Left;
                DockedRects[DockedRectCounter].Y = TmpScrn.WorkingArea.Bottom;
                DockedRects[DockedRectCounter].Width = TmpScrn.WorkingArea.Width;
                DockedRects[DockedRectCounter].Height = BottomDockedHeight;
                DockedRectCounter += 1;
            }
        }
    }
    return DockedRects;
}

Solution 3:

Based on David's answer, here is a better implementation that uses P/Invoke to correctly determine the placement and size of the taskbar. The only limitation I know of so far is that it does not return the correct bounds when multiple monitors are set to display in extended mode.

The code with all subsequent updates is available as a gist at https://git.io/v9bCx.

/******************************************************************************
 * Name:        Taskbar.cs
 * Description: Class to get the taskbar's position, size and other properties.
 * Author:      Franz Alex Gaisie-Essilfie
 *              based on code from https://winsharp93.wordpress.com/2009/06/29/find-out-size-and-position-of-the-taskbar/
 *
 * Change Log:
 *  Date        | Description
 * -------------|--------------------------------------------------------------
 *  2017-05-16  | Initial design
 */

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

namespace System.Windows.Forms
{
    public enum TaskbarPosition
    {
        Unknown = -1,
        Left,
        Top,
        Right,
        Bottom,
    }

    public static class Taskbar
    {
        private enum ABS
        {
            AutoHide = 0x01,
            AlwaysOnTop = 0x02,
        }

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

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

        private const string ClassName = "Shell_TrayWnd";
        private static APPBARDATA _appBarData;

        /// <summary>Static initializer of the <see cref="Taskbar" /> class.</summary>
        static Taskbar()
        {
            _appBarData = new APPBARDATA
            {
                cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)),
                hWnd = FindWindow(Taskbar.ClassName, null)
            };
        }

        /// <summary>
        ///   Gets a value indicating whether the taskbar is always on top of other windows.
        /// </summary>
        /// <value><c>true</c> if the taskbar is always on top of other windows; otherwise, <c>false</c>.</value>
        /// <remarks>This property always returns <c>false</c> on Windows 7 and newer.</remarks>
        public static bool AlwaysOnTop
        {
            get
            {
                int state = SHAppBarMessage(AppBarMessage.GetState, ref _appBarData).ToInt32();
                return ((ABS)state).HasFlag(ABS.AlwaysOnTop);
            }
        }

        /// <summary>
        ///   Gets a value indicating whether the taskbar is automatically hidden when inactive.
        /// </summary>
        /// <value><c>true</c> if the taskbar is set to auto-hide is enabled; otherwise, <c>false</c>.</value>
        public static bool AutoHide
        {
            get
            {
                int state = SHAppBarMessage(AppBarMessage.GetState, ref _appBarData).ToInt32();
                return ((ABS)state).HasFlag(ABS.AutoHide);
            }
        }

        /// <summary>Gets the current display bounds of the taskbar.</summary>
        public static Rectangle CurrentBounds
        {
            get
            {
                var rect = new RECT();
                if (GetWindowRect(Handle, ref rect))
                    return Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);

                return Rectangle.Empty;
            }
        }

        /// <summary>Gets the display bounds when the taskbar is fully visible.</summary>
        public static Rectangle DisplayBounds
        {
            get
            {
                if (RefreshBoundsAndPosition())
                    return Rectangle.FromLTRB(_appBarData.rect.Left,
                                              _appBarData.rect.Top,
                                              _appBarData.rect.Right,
                                              _appBarData.rect.Bottom);

                return CurrentBounds;
            }
        }

        /// <summary>Gets the taskbar's window handle.</summary>
        public static IntPtr Handle
        {
            get { return _appBarData.hWnd; }
        }

        /// <summary>Gets the taskbar's position on the screen.</summary>
        public static TaskbarPosition Position
        {
            get
            {
                if (RefreshBoundsAndPosition())
                    return (TaskbarPosition)_appBarData.uEdge;

                return TaskbarPosition.Unknown;
            }
        }

        /// <summary>Hides the taskbar.</summary>
        public static void Hide()
        {
            const int SW_HIDE = 0;
            ShowWindow(Handle, SW_HIDE);
        }

        /// <summary>Shows the taskbar.</summary>
        public static void Show()
        {
            const int SW_SHOW = 1;
            ShowWindow(Handle, SW_SHOW);
        }

        private static bool RefreshBoundsAndPosition()
        {
            //! SHAppBarMessage returns IntPtr.Zero **if it fails**
            return SHAppBarMessage(AppBarMessage.GetTaskbarPos, ref _appBarData) != IntPtr.Zero;
        }

        #region DllImports

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

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

        [DllImport("shell32.dll", SetLastError = true)]
        private static extern IntPtr SHAppBarMessage(AppBarMessage dwMessage, [In] ref APPBARDATA pData);

        [DllImport("user32.dll")]
        private static extern int ShowWindow(IntPtr hwnd, int command);

        #endregion DllImports

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

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
    }
}

Solution 4:

private enum TaskBarLocation { TOP, BOTTOM, LEFT, RIGHT } 

private TaskBarLocation GetTaskBarLocation()
{
  //System.Windows.SystemParameters....
  if (SystemParameters.WorkArea.Left > 0) 
    return TaskBarLocation.LEFT;
  if (SystemParameters.WorkArea.Top > 0)
    return TaskBarLocation.TOP;
  if (SystemParameters.WorkArea.Left == 0 
    && SystemParameters.WorkArea.Width < SystemParameters.PrimaryScreenWidth) 
      return TaskBarLocation.RIGHT;
  return TaskBarLocation.BOTTOM;
}

Solution 5:

This is the answer from Mark McGinty in C#.

This code brings back all of the task bars as a list of rectanges:

  • 0 rectangles means the taskbar is hidden;
  • 1 rectangle is the position of the taskbar;
  • 2+ is very rare, it means that we have multiple monitors, and we are not using Extend these displays to create a single virtual desktop.

Works in every situation

It works well with:

  • Windows 7 (will almost certainly work on Windows 8.1 and Windows 10).
  • All combinations of settings.

enter image description here

C# Code

public static List<Rectangle> FindDockedTaskBars()
{
    List<Rectangle> dockedRects = new List<Rectangle>();
    foreach (var tmpScrn in Screen.AllScreens)
    {
        if (!tmpScrn.Bounds.Equals(tmpScrn.WorkingArea))
        {
            Rectangle rect = new Rectangle();

            var leftDockedWidth = Math.Abs((Math.Abs(tmpScrn.Bounds.Left) - Math.Abs(tmpScrn.WorkingArea.Left)));
            var topDockedHeight = Math.Abs((Math.Abs(tmpScrn.Bounds.Top) - Math.Abs(tmpScrn.WorkingArea.Top)));
            var rightDockedWidth = ((tmpScrn.Bounds.Width - leftDockedWidth) - tmpScrn.WorkingArea.Width);
            var bottomDockedHeight = ((tmpScrn.Bounds.Height - topDockedHeight) - tmpScrn.WorkingArea.Height);
            if ((leftDockedWidth > 0))
            {
                rect.X = tmpScrn.Bounds.Left;
                rect.Y = tmpScrn.Bounds.Top;
                rect.Width = leftDockedWidth;
                rect.Height = tmpScrn.Bounds.Height;
            }
            else if ((rightDockedWidth > 0))
            {
                rect.X = tmpScrn.WorkingArea.Right;
                rect.Y = tmpScrn.Bounds.Top;
                rect.Width = rightDockedWidth;
                rect.Height = tmpScrn.Bounds.Height;
            }
            else if ((topDockedHeight > 0))
            {
                rect.X = tmpScrn.WorkingArea.Left;
                rect.Y = tmpScrn.Bounds.Top;
                rect.Width = tmpScrn.WorkingArea.Width;
                rect.Height = topDockedHeight;
            }
            else if ((bottomDockedHeight > 0))
            {
                rect.X = tmpScrn.WorkingArea.Left;
                rect.Y = tmpScrn.WorkingArea.Bottom;
                rect.Width = tmpScrn.WorkingArea.Width;
                rect.Height = bottomDockedHeight;
            }
            else
            {
                // Nothing found!
            }

            dockedRects.Add(rect);
        }
    }

    if (dockedRects.Count == 0)
    {
        // Taskbar is set to "Auto-Hide".
    }

    return dockedRects;
}