gpt4 book ai didi

c# - 如何在C#程序中获取任务栏通知区域宽度?

转载 作者:行者123 更新时间:2023-12-03 00:19:38 27 4
gpt4 key购买 nike

我正在 C# Winforms 应用程序中开发一项功能,该功能需要确定任务栏的 Windows“通知区域”的宽度(特别是当停靠在屏幕底部的默认位置时)。

为了提供更好的上下文,程序显示小的、 transient 的、无边框的窗口(类似工具提示),我们希望确保通知区域“系统托盘”图标和时钟永远不会被这些窗口之一覆盖。

下面是我想要获取的宽度的屏幕截图(来自 Windows 10),以及它的用途:

Width dimension needed from Notification Area of Task Bar, and explanation of use

到目前为止,我已经探索了 .Net 框架,并研究了 Win32 API 调用,但是我无法确定任何潜在的解决方案(也无法确定这是否确实可行)。

如有任何建议,我们将不胜感激。理想情况下,解决方案应兼容 Windows 7,但这不是绝对要求。

最佳答案

可以使用 GetWindowRect() 检索 Shell 托盘窗口(或任务栏)及其子窗口的位置和大小。 ,传递相关窗口的Handle
FindWindowEx() 返回 Windows Handle (FindWindowExW),使用窗口类名来识别它。 (请注意,此函数执行不区分大小写搜索)。

正如 Hans Passant 在评论中指出的那样,在执行此类措施时需要考虑一些重要的细节。

这个操作不是框架或系统需要支持的。类名称将来可能会发生变化。这不是托管任务。

最重要的是,应用程序必须支持 DPI。如果不是,则应用程序将受到虚拟化的影响。
这意味着当使用非 DPI-Aware API 函数时,其测量/结果也可以虚拟化。
例如,GetWindowRect() 不是 DPI 感知函数。

来自 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

托盘通知区域是Shell_TrayWnd的子窗口。它的类名为TrayNotifyWnd
(Shell_TrayWnd → TrayNotifyWnd)

TrayNotifyWnd

其他几个子类:

任务栏,类名MSTaskSwWClass:
(Shell_TrayWnd → ReBarWindow32 → MSTaskSwWClass → MSTaskListWClass)

MSTaskSwWClass

托盘时钟,类名TrayClockWClass:
(Shell_TrayWnd → TrayNotifyWnd → TrayClockWClass)

TrayClockWClass

这些类名称适用于 Windows 7 和 Windows 10 中的这些系统组件

关于命名约定的一些注意事项:
雷蒙德·陈上 Why do some people call the taskbar the "tray"?

<小时/>

Shell_TrayWnd 父级是 Desktop,因此我们将 IntPtr.Zero 作为父句柄传递。
GetDesktopWindow()可以用它代替。

TrayNotifyWndShell_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();
}

关于c# - 如何在C#程序中获取任务栏通知区域宽度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52554111/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com