GetWindowRect возвращает размер, включающий "невидимые" границы

Я работаю над приложением, которое позиционирует окна на экране в стиле сетки. При запуске на Windows 10, существует огромный разрыв между окнами. Дальнейшее исследование показывает, что GetWindowRect возвращает неожиданные значения, включая невидимую границу, но я не могу заставить его вернуть реальные значения с видимой границей.

1) этой теме предполагает, что это по дизайну, и вы можете "исправить" его, связав с winver=6. Мое окружение не позволяет этого, но Я пробовал изменить PE MajorOperatingSystemVersion и MajorSubsystemVersion до 6 без аффекта

2) тот же поток также предлагает использовать DwmGetWindowAttribute С DWMWA_EXTENDED_FRAME_BOUNDS чтобы получить реальные координаты из DWM, который работает, но означает изменение везде, что получает координаты окна. Он также не позволяет установить значение, оставляя нас для обратного процесса, чтобы иметь возможность установить размер окна.

3) этот вопрос предполагает, что это отсутствие осведомленности DPI в процессе. Ни установка флага осведомленности DPI в манифесте или вызов SetProcessDpiAwareness имели никакого результата.

4) по прихоти я также попытался добавить флаги совместимости Windows Vista, 7, 8, 8.1 и 10, а темы Windows манифестируются без изменений.

Screenshot of a "fullscreen" window with gaps all round Это окно перемещается в 0x0, 1280x1024, предположительно, чтобы заполнить весь экран, и при запросе координат мы получаем те же значения. Однако окна на самом деле 14 точек уже в учетная запись границы на более старых версиях Windows.

как я могу убедить Windows позволить мне работать с реальными координатами окна?

3 ответов


Windows 10 имеет тонкие невидимые границы слева, справа и снизу, он используется для захвата мыши для изменения размера. Границы могут выглядеть так:7,0,7,7 (слева, сверху, справа, снизу)

когда вы называете SetWindowPos чтобы поместить окно в эти координаты:
0, 0, 1280, 1024

окно выберет эти точные координаты, и GetWindowRect вернет те же координаты. Но визуально окно кажется здесь:
7, 0, 1273, 1017

вы можете обмануть окно и сказать ему идти сюда вместо этого:
-7, 0, 1287, 1031

для этого мы получаем толщину границы Windows 10:

RECT rect, frame;
GetWindowRect(hwnd, &rect);
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));

//rect should be `0, 0, 1280, 1024`
//frame should be `7, 0, 1273, 1017`

RECT border;
border.left = frame.left - rect.left;
border.top = frame.top - rect.top;
border.right = rect.right - frame.right;
border.bottom = rect.bottom - frame.bottom;

//border should be `7, 0, 7, 7`

затем сдвиньте прямоугольник так:

rect.left -= border.left;
rect.top -= border.top;
rect.right += border.left + border.right;
rect.bottom += border.top + border.bottom;

//new rect should be `-7, 0, 1287, 1031`

если нет более простого решения!


Как я могу убедить Windows разрешить мне работать с реальными координатами окна?

вы уже работаете с реальными координатами. Windows10 просто решил скрыть границы от ваших глаз. Но, тем не менее, они все еще там. Mousing за краями окна, ваш курсор изменится на изменение размера курсора, что означает, что его все еще на самом деле над окном.

Если вы хотите, чтобы ваши глаза соответствовали тому, что Windows говорит вам, вы могли бы попробуйте разоблачить эти границы, чтобы они снова были видны, используя тему Aero Lite:

http://winaero.com/blog/enable-the-hidden-aero-lite-theme-in-windows-10/


вы можете ответить на WM_NCCALCSIZE сообщение, изменить WndProcповедение по умолчанию для удаления невидимой границы.

As документ и документ объяснить, когда wParam > 0, по запросу wParam.Rgrc[0] содержит новые координаты окна, и когда процедура возвращается, Response wParam.Rgrc[0] содержит координаты нового прямоугольника клиента.

в golang код примера:

case win.WM_NCCALCSIZE:
    log.Println("----------------- WM_NCCALCSIZE:", wParam, lParam)

    if wParam > 0 {
        params := (*win.NCCALCSIZE_PARAMS)(unsafe.Pointer(lParam))
        params.Rgrc[0].Top = params.Rgrc[2].Top
        params.Rgrc[0].Left = params.Rgrc[0].Left + 1
        params.Rgrc[0].Bottom = params.Rgrc[0].Bottom - 1
        params.Rgrc[0].Right = params.Rgrc[0].Right - 1
        return 0x0300
    }