Подтвердить что ты не робот

GetWindowRect слишком мал для Windows 7

Фактическая проблема, которую я пытаюсь решить, - это автоматическое определение размера полей вокруг окон. Если вы можете найти лучший способ, пожалуйста, обязательно ответьте, что вместо этого.

Для этого я решил снять скриншот тестового окна и измерить его. Это достаточно просто, так как я ожидаю, что никакие поля никогда не будут ярко-розовыми, но я признаю это взломом. Я использую GetWindowRect (py), чтобы получить ограничивающий и PIL, чтобы захватить скриншот и обрезать рамку. Проблема в том, что пока растение работает правильно, ограничивающий прямоугольник нечетный. Windows 7 "Snipping Tool" получает правильные размеры. Как я могу сделать то же самое?

4b9b3361

Ответ 1

Мои первые мысли были перечислены ниже, но если, как вы заявляете, вы уверены, что GetWindowRect возвращает неверные значения, см. РАЗРЕШЕНИЕ далее.


"Что случилось с GetSystemMetrics(SM_CXBORDER) и GetSystemMetrics(SM_CYBORDER)?

Метод, который вы используете, кажется очень окольным способом его выполнения, и если вы можете вызвать GetWindowRect(), я вполне уверен, что вы можете вызвать GetSystemMetrics().

Еще одна возможность заключается в использовании GetWindowRect, чтобы получить весь ограничивающий прямоугольник для окна и GetClientRect, чтобы получить ограничивающий прямоугольник для клиентской (безграничной) области.

Это даст вам что-то вроде (100,200),(1000,900) и (112,227),(988,888) соответственно, и вы можете определить верхнюю границу как 227-200, внизу как 900-888, оставить как 112-100 и вправо как 900-888 (27, 12,12,12).


Решение:

Немного исследований появляется this. Это поток от 2006 года, в котором указано, что вы не можете получить правильные значения из GetWindowsRect. Поток, который указал мне на это, сказал:

Приложения под Vista, которые не связаны с WINVER = 6, получат вводящий в заблуждение набор значений, которые не учитывают дополнительное дополнение "стеклянных" пикселей Vista Aero к окну. Это, похоже, происходит даже в Aero Basic (без стекла), чтобы сохранить согласованность размеров. Обходной путь (если вы не хотите устанавливать WINVER = 6), похоже, должен динамически связываться с dwmapi.dll и использовать GetProcAddress() для получения функции DwmGetWindowAttribute() и вызвать его с помощью аргумента DWMWA_EXTENDED_FRAME_BOUNDS, чтобы запросить подлинное окно размеры рамы.

В принципе, используйте что-то вроде (вам, возможно, придется использовать ctypes для этого с Python):

RECT r;
HRESULT stat = DwmGetWindowAttribute (
    hwnd,
    DWMWA_EXTENDED_FRAME_BOUNDS,
    &r,
    sizeof(r));

и это должно дать вам правильный ограничивающий прямоугольник.

Ответ 2

Я знаю, что это немного старая тема. Но это заняло немало времени, и я сам стал страдать от ctypes, чтобы получить решение paxdiablo, работающее на Python. Просто хотел поделиться примером рабочего кода для wxPython:

try:
    f = ctypes.windll.dwmapi.DwmGetWindowAttribute
except WindowsError:
    f = None
if f: # Vista & 7 stuff
    rect = ctypes.wintypes.RECT()
    DWMWA_EXTENDED_FRAME_BOUNDS = 9
    f(ctypes.wintypes.HWND(self.GetHandle()),
      ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS),
      ctypes.byref(rect),
      ctypes.sizeof(rect)
      )
    size = (rect.right - rect.left, rect.bottom - rect.top)        
else:      
    size = self.GetSize()

Ответ 4

сначала вы вызываете GetClientRect для извлечения клиентского прямоугольника R1, затем вызовите функцию AdjustWindowRectEx для вычисления точных границ в соответствии с R1.

Ответ 5

GetWindowRect в Windows 7 не включает в себя правые и нижние границы фрейма окна (по крайней мере, с темой Aero afaik), если окно было создано без стиля WS_SIZEBOX (т.е. вы хотите незаменимое окно).

Проблема заключается в том, что WS_SIZEBOX совпадает с WS_THICKFRAME, а на Aero окна имеют толщину, независимо от того, могут ли они быть изменены или нет. Но функция GetWindowRect считает, что окно без изменения размеров становится тоньше.

Исправить? Вы можете создать окно с WS_SIZEBOX, вызвать GetWindowRect, а затем использовать SetWindowLongPtr (GWL_STYLE,...), чтобы отключить WS_SIZEBOX, но это создаст уродливую белую границу внутри клиентской области.

Вместо этого оставьте WS_SIZEBOX включенным и просто верните одно и то же значение для ptMinTrackSize и ptMaxTraceSize в структуре MINMAXINFO при ответе на сообщение WM_GETMINMAXINFO. Это приведет к изменению размера окна, и GetWindowRect вернет правильные данные. Единственный недостаток заключается в том, что курсор мыши по-прежнему будет меняться на курсор изменения размера, когда указатель мыши перейдет через оконный фрейм, но это пока что меньше зла.

Ответ 6

GetWindowRect возвращает правильные значения, но для явного дескриптора окна. Используйте функцию GetParent, чтобы получить дескриптор родительского окна, в то время как GetWindoWRect возвращает для вас максимальное значение RECT или GetParent - значение NULL.