计算 windows 10 上第 3 方 window 的标题栏按钮的总宽度
Compute total width of title bar buttons for 3rd party window on windows 10
我最初的方法是使用 GetSystemMetrics
和 SystemMetric.SM_CXSIZE
以及一些基于可用按钮(时间 3 或时间 1)的简单数学运算,通过 WindowStyle
。
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(SystemMetric smIndex);
这在 Windows 10 上有一个问题,其中计算的宽度大约是实际宽度的 70%。所以宽度只覆盖两个按钮 - 最大化和关闭。 Windows 7 和 8.1 都可以,相同的 DPI 设置,覆盖所有按钮。
我检查了一些关于 Stack Overflow 的现有问题,并在 2011 年最成功地解决了这个问题:
- How do I compute the non-client window size in WPF?
不幸的是,虽然 suggested approach 在 windows 8.1 中有效,但它在 Windows 10(最新版本,所有推荐更新)上计算 0。有没有一种方法适用于从 7 到 10 的所有 OS?
代码取自上述答案并修改为计算 window 控制按钮的总宽度,由 window 句柄 (hwnd),并将编组从矩形更改为 RECT(然后我得到 left/right).
的正确值
public static int GetControlButtonsWidth(IntPtr hwnd)
{
// Create and initialize the structure
TITLEBARINFOEX tbi = new TITLEBARINFOEX();
tbi.cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX));
// Send the WM_GETTITLEBARINFOEX message
SendMessage(hwnd, WM_GETTITLEBARINFOEX, IntPtr.Zero, ref tbi);
int sum = tbi.rgrect.Sum(r => r.right - r.left);
// Return the filled-in structure
return sum;
}
internal const int WM_GETTITLEBARINFOEX = 0x033F;
internal const int CCHILDREN_TITLEBAR = 5;
[StructLayout(LayoutKind.Sequential)]
internal struct TITLEBARINFOEX
{
public int cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public int[] rgstate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public RECT[] rgrect;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
IntPtr hWnd,
int uMsg,
IntPtr wParam,
ref TITLEBARINFOEX lParam);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left, top, right, bottom;
}
您可以使用 DwmGetWindowAttribute
,这 3 个按钮的组合宽度在 Windows10 上应为 185 像素,DPI 为 125%。请注意,如果您的应用程序不支持 DPI,则结果仍然相同,例如 185。
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(
IntPtr hwnd, int attr, out RECT ptr, int size);
public void foo()
{
int DWMWA_CAPTION_BUTTON_BOUNDS = 5;
RECT rc;
if (0 != DwmGetWindowAttribute(this.Handle, DWMWA_CAPTION_BUTTON_BOUNDS,
out rc, Marshal.SizeOf(typeof(RECT))))
{
//error
}
int width = rc.right - rc.left;
}
我最初的方法是使用 GetSystemMetrics
和 SystemMetric.SM_CXSIZE
以及一些基于可用按钮(时间 3 或时间 1)的简单数学运算,通过 WindowStyle
。
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(SystemMetric smIndex);
这在 Windows 10 上有一个问题,其中计算的宽度大约是实际宽度的 70%。所以宽度只覆盖两个按钮 - 最大化和关闭。 Windows 7 和 8.1 都可以,相同的 DPI 设置,覆盖所有按钮。
我检查了一些关于 Stack Overflow 的现有问题,并在 2011 年最成功地解决了这个问题:
- How do I compute the non-client window size in WPF?
不幸的是,虽然 suggested approach 在 windows 8.1 中有效,但它在 Windows 10(最新版本,所有推荐更新)上计算 0。有没有一种方法适用于从 7 到 10 的所有 OS?
代码取自上述答案并修改为计算 window 控制按钮的总宽度,由 window 句柄 (hwnd),并将编组从矩形更改为 RECT(然后我得到 left/right).
的正确值public static int GetControlButtonsWidth(IntPtr hwnd)
{
// Create and initialize the structure
TITLEBARINFOEX tbi = new TITLEBARINFOEX();
tbi.cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX));
// Send the WM_GETTITLEBARINFOEX message
SendMessage(hwnd, WM_GETTITLEBARINFOEX, IntPtr.Zero, ref tbi);
int sum = tbi.rgrect.Sum(r => r.right - r.left);
// Return the filled-in structure
return sum;
}
internal const int WM_GETTITLEBARINFOEX = 0x033F;
internal const int CCHILDREN_TITLEBAR = 5;
[StructLayout(LayoutKind.Sequential)]
internal struct TITLEBARINFOEX
{
public int cbSize;
public RECT rcTitleBar;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public int[] rgstate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
public RECT[] rgrect;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
IntPtr hWnd,
int uMsg,
IntPtr wParam,
ref TITLEBARINFOEX lParam);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left, top, right, bottom;
}
您可以使用 DwmGetWindowAttribute
,这 3 个按钮的组合宽度在 Windows10 上应为 185 像素,DPI 为 125%。请注意,如果您的应用程序不支持 DPI,则结果仍然相同,例如 185。
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(
IntPtr hwnd, int attr, out RECT ptr, int size);
public void foo()
{
int DWMWA_CAPTION_BUTTON_BOUNDS = 5;
RECT rc;
if (0 != DwmGetWindowAttribute(this.Handle, DWMWA_CAPTION_BUTTON_BOUNDS,
out rc, Marshal.SizeOf(typeof(RECT))))
{
//error
}
int width = rc.right - rc.left;
}