在Windows 7上GetWindowRect太小

问题描述:

我试图解决的实际问题是,我想自动找出窗口边缘的大小。如果你能找到更好的办法,请尽一切办法回答这个问题,而不是这个。在Windows 7上GetWindowRect太小

为此,我决定截取测试窗口并测量边距。这很简单,因为我预计没有利润率会变成明亮的粉红色,但我承认这是一种黑客行为。我使用GetWindowRectpy)获取边界框,并使用PIL获取屏幕截图并剪裁到边界框。问题是,当作物正常运行时,边界框是not accurate。 Windows 7“截取工具”获取correct dimensions。我怎么能这样做?

我的第一个想法是列举如下,但如果像你的状态,你肯定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 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)); 

而且应该给你正确的边框。

+0

那么,它返回1. 1不是该窗口上任何边界的宽度。我很确定我想要的那个窗口的值是8和30. – 2010-07-07 06:04:29

+0

你怎样得到8和30?正确的外观框架似乎在底部具有与侧面相同的宽度。 – paxdiablo 2010-07-07 06:25:24

+0

我也关心顶部。 – 2010-07-07 06:43:04

第一,调用GetClientRect以检索客户端矩形R1, 然后调用AdjustWindowRectEx根据R1来计算准确的边界。

GetWindowRect返回正确的值,但用于显式处理窗口。使用GetParent function得到父窗口的句柄,而GetWindowWRect返回给你的最大RECT或GetParent返回值为NULL。

+3

OP已经*在这里讨论顶层窗口。 – BrendanMcK 2012-08-20 20:35:00

我知道这是一个有点老话题。但是它花费了大量的搜索时间,并且我通过ctypes痛苦地解决了paxdiablo的解决方案。只是想分享工作代码样本的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() 

在Windows 7 GetWindowRect似乎不包括如果窗口创建右侧和底部窗框边缘(至少Aero主题据我所知),没有 WS_SIZEBOX风格(即,你想要一个不可调整大小的窗口)。

问题是,WS_SIZEBOX与WS_THICKFRAME相同,并且在Aero上,无论窗口是否可以调整大小,窗口都有厚框。但GetWindowRect函数认为不可调整大小的窗口更薄。

修复?您可以使用WS_SIZEBOX创建窗口,调用GetWindowRect,然后使用SetWindowLongPtr(GWL_STYLE,...)关闭WS_SIZEBOX,但这会在客户区域内创建一个丑陋的白色边框。

取而代之的是,保持WS_SIZEBOX启用,并在响应WM_GETMINMAXINFO消息时,简单地为MINMAXINFO结构中的ptMinTrackSize和ptMaxTraceSize返回相同的值。 这将使窗口不能调整大小,GetWindowRect将返回适当的数据。唯一的缺点是,当鼠标指针移到窗口框架上时,鼠标光标仍然会变成一个调整大小的光标,但它是目前为止的恶意中较小的一个。