C# 如何获取任务栏的位置和大小?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1264406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:24:07  来源:igfitidea点击:

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

c#

提问by Ravi Naik

I want to know how to get the rectangle (bottom, top, left, and right) that the taskbar occupies. How do I go about doing this in C#?

我想知道如何获取任务栏占据的矩形(底部、顶部、左侧和右侧)。我如何在 C# 中做到这一点?

回答by Mike

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

回答by Vanden

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

回答by Mark McGinty

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?

以下函数返回一个矩形数组,每个矩形代表一个停靠的任务栏,并将计数写入其 byref 参数。如果该计数为 1,则返回数组的元素 0 是任务栏占用的 Rectangle。如果大于 1,是时候猜测了?

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)

或者对于那些喜欢 C# 的人......(注意:此移植代码未经测试)

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

回答by Contango

This is the answer from Mark McGintyin C#.

这是Mark McGintyC# 中的答案。

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 notusing Extend these displaysto create a single virtual desktop.
  • 0 个矩形表示隐藏任务栏;
  • 1个矩形是任务栏的位置;
  • 2+是非常罕见的,这意味着我们有多个显示器,并且我们使用Extend these displays以创建单个虚拟桌面。

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.
  • Windows 7(几乎肯定可以在 Windows 8.1 和 Windows 10 上运行)。
  • 设置的所有组合。

enter image description here

在此处输入图片说明

C# Code

C# 代码

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

回答by Luca Ziegler

This is a simple example using winforms with wpf and multi screen support:

这是一个使用带有 wpf 和多屏幕支持的 winforms 的简单示例:

Screen sc = Screen.FromHandle(new WindowInteropHelper(this).Handle);
            if (sc.WorkingArea.Top > 0)
            {
                // TASKBAR TOP
            }
            else if (sc.WorkingArea.Left != sc.Bounds.X)
            {
                // TASKBAR LEFT
            }
            else if ((sc.Bounds.Height - sc.WorkingArea.Height) > 0)
            {
                // TASKBAR BOTTOM
            }
            else if (sc.WorkingArea.Right != 0)
            {
                // TASKBAR RIGHT
            }
            else
            {
                // TASKBAR NOT FOUND
            }

回答by Alex Essilfie

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.

根据David 的回答,这里有一个更好的实现,它使用 P/Invoke 来正确确定任务栏的位置和大小。到目前为止,我所知道的唯一限制是,当多个显示器设置为以扩展模式显示时,它不会返回正确的边界。

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

带有所有后续更新的代码可在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;
        }
    }
}

回答by Eli

This is how to get the Taskbar's Height (using WPF)

这是获取任务栏高度的方法(使用 WPF)

int PSBH = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
int TaskBarHeight = PSBH - System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;

If you want to account for dpi

如果要考虑 dpi

int PSH = SystemParameters.PrimaryScreenHeight;
int PSBH = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
double ratio = PSH / PSBH;
int TaskBarHeight = PSBH - System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
TaskBarHeight *= ratio;

回答by user13624124

This will work on Windows and macOS. It will also work with multiple monitors. As is, it is for electron applications, but you can easily understand what's going on.

这将适用于 Windows 和 macOS。它也适用于多台显示器。照原样,它适用于电子应用,但您可以轻松了解发生了什么。

type TaskBarPos int

const (
    UNKNOWN TaskBarPos = -1
    LEFT    TaskBarPos = 0
    RIGHT   TaskBarPos = 1
    TOP     TaskBarPos = 2
    BOTTOM  TaskBarPos = 3
)

type Rect struct {
    top    int
    bottom int
    width  int
    height int
    left   int
    right  int
}

func (r Rect) centerX() int {
    return r.left + ((r.right - r.left) / 2)
}

func (r Rect) centerY() int {
    return r.top + ((r.bottom - r.top) / 2)
}

func taskbar(tray *js.Object) TaskBarPos {

    // Step 1 - Get relevant display
    display := screen.Call("getDisplayNearestPoint", screen.Call("getCursorScreenPoint")) // Replace with primary monitor or a secondary monitor. This line as is grabs the monitor that the mouse cursor is on.

    // Step 2 - Determine taskbar bounds relative to the display
    bounds := display.Get("bounds")
    workArea := display.Get("workArea")
    var tb *Rect

    d := Rect{
        top:    bounds.Get("y").Int(),
        bottom: bounds.Get("y").Int() + bounds.Get("height").Int(),
        width:  bounds.Get("width").Int(),
        height: bounds.Get("height").Int(),
        left:   bounds.Get("x").Int(),
        right:  bounds.Get("x").Int() + bounds.Get("width").Int(),
    }

    wa := Rect{
        top:    workArea.Get("y").Int(),
        bottom: workArea.Get("y").Int() + workArea.Get("height").Int(),
        width:  workArea.Get("width").Int(),
        height: workArea.Get("height").Int(),
        left:   workArea.Get("x").Int(),
        right:  workArea.Get("x").Int() + workArea.Get("width").Int(),
    }

    if tray != nil {
        tBounds := tray.Call("getBounds")
        tb = &Rect{
            top:    tBounds.Get("y").Int(),
            bottom: tBounds.Get("y").Int() + tBounds.Get("height").Int(),
            width:  tBounds.Get("width").Int(),
            height: tBounds.Get("height").Int(),
            left:   tBounds.Get("x").Int(),
            right:  tBounds.Get("x").Int() + tBounds.Get("width").Int(),
        }
    }

    // Step 3 - Determine Position of Taskbar
    if wa.top > d.top {
        return TOP
    } else if wa.bottom < d.bottom {
        return BOTTOM
    } else if wa.left > d.left {
        return LEFT
    } else if wa.right < d.right {
        return RIGHT
    }
    if tb == nil {
        return UNKNOWN
    }

    // Check which corner tray is closest to
    if ((*tb).top - d.top) < (d.bottom - (*tb).bottom) {
        return TOP
    }
    if ((*tb).left - d.left) < (d.right - (*tb).right) {
        return LEFT
    }
    if d.bottom-(*tb).centerY() < d.right-(*tb).centerX() {
        return BOTTOM
    }
    return RIGHT
}