Вычислить общую ширину кнопок строки заголовка для стороннего окна на windows 10 - PullRequest
2 голосов
/ 23 марта 2020

enter image description here

Мой первоначальный подход к этому заключался в использовании 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, где он охватывает все кнопки.

Я проверил несколько существующих вопросов о переполнении стека, и больше всего с этим справился в 2011 году:

К сожалению, хотя предлагаемый подход *1023* работает в windows 8.1 рассчитывает 0 на Windows 10 (последняя версия, все рекомендуемые обновления). Есть ли способ, который работает на всех ОС от 7 до 10?

Код был взят из приведенного выше ответа и изменен для вычисления общей ширины кнопок управления окном, с помощью дескриптора окна (hwnd), и изменил маршаллинг на RECT из Rectangle (тогда я получаю правильные значения влево / вправо).

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

1 Ответ

2 голосов
/ 23 марта 2020

Вы можете использовать DwmGetWindowAttribute, объединенная ширина для этих 3 кнопок должна составлять 185 пикселей при Windows 10, при 125% DPI. Обратите внимание, что если ваше приложение не поддерживает 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...