Shell 托盘窗口(或任务栏)及其子窗口的位置和大小可以使用GetWindowRect() 检索,传递相关窗口的Handle。
窗口Handle 由FindWindowEx() (FindWindowExW) 返回,使用窗口类名来识别它。 (请注意,此函数执行不区分大小写的搜索)。
正如 Hans Passant 在评论中指出的那样,在执行此类措施时需要考虑一些重要的细节。
这个操作不是框架或系统需要支持的。类名将来可能会更改。这不是托管任务。
最重要的是,应用程序必须支持 DPI。如果没有,应用程序将受到虚拟化的影响。
这意味着当使用非 DPI-Aware API 函数时,其度量/结果也可以虚拟化。
例如,GetWindowRect() 不是 DPI-Aware 函数。
来自 MSDN:
Mixed-Mode DPI Scaling and DPI-aware APIs
来自 SO 问题的一些注释:
Getting a DPI aware correct RECT from GetWindowRect
关于 DPI 意识,我写了一些笔记here。
此外,Hans Passant 的这个(经典)回答:
How to configure an app to run correctly on a machine with a high DPI setting (e.g. 150%)?
来自 Raymond Chen 的博客:
How can I update my WinForms app to behave better at high DPI, or at normal DPI on very large screens?
来自 MSDN:
High DPI Desktop Application Development on Windows
Shell 托盘窗口的类名称为 Shell_TrayWnd。它的位置和相对大小可以由用户定义。这是默认位置的类 Windows 范围。
托盘通知区域是Shell_TrayWnd 的子窗口。它的类名是TrayNotifyWnd
(Shell_TrayWnd → TrayNotifyWnd)
其他几个子类:
任务栏,类名MSTaskSwWClass:
(Shell_TrayWnd → ReBarWindow32 → MSTaskSwWClass → MSTaskListWClass)
托盘时钟,类名TrayClockWClass:
(Shell_TrayWnd → TrayNotifyWnd → TrayClockWClass)
这些类名适用于 Windows 7 和 Windows 10 中的这些系统组件
这里有一些关于命名约定的注意事项:
Raymond Chen Why do some people call the taskbar the "tray"?
Shell_TrayWnd 父级是 Desktop,因此我们将 IntPtr.Zero 作为父句柄传递。
可以使用GetDesktopWindow() 代替。
TrayNotifyWnd 是Shell_TrayWnd 的子窗口。我们正在使用它的句柄来加快搜索速度。
using System.Drawing;
using System.Runtime.InteropServices;
//Shell Tray rectangle
IntPtr hWnd = FindWindowByClassName(IntPtr.Zero, "Shell_TrayWnd");
Rectangle shellTrayArea = GetWindowRectangle(hWnd);
//Notification area rectangle
hWnd = FindWindowByClassName(hWnd, "TrayNotifyWnd");
Rectangle trayNotifyArea = GetWindowRectangle(hWnd);
Windows API 声明:
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
[SuppressUnmanagedCodeSecurity, SecurityCritical]
internal static class SafeNativeMethods
{
[DllImport("User32.dll", SetLastError = true)]
internal static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
}
//Helper methods
[SecuritySafeCritical]
public static IntPtr FindWindowByClassName(IntPtr hwndParent, string className)
{
return SafeNativeMethods.FindWindowEx(hwndParent, IntPtr.Zero, className, null);
}
[SecuritySafeCritical]
public static Rectangle GetWindowRectangle(IntPtr windowHandle)
{
RECT rect;
new UIPermission(UIPermissionWindow.AllWindows).Demand();
SafeNativeMethods.GetWindowRect(windowHandle, out rect);
return rect.ToRectangle();
}