GetWindowRect too small on Windows 7

前端 未结 6 1002
灰色年华
灰色年华 2020-11-28 11:41

The actual problem I\'m trying to solve is, I want to automatically find out the size of the margins around windows. If you can find a better way, please by all means answer

相关标签:
6条回答
  • 2020-11-28 11:52

    DwmGetWindowAttribute

    http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx

    0 讨论(0)
  • 2020-11-28 11:58

    My first thoughts were listed below but if, as you state, you're certain that GetWindowRect is returning incorrect values, see RESOLUTION further down.


    "What's wrong with GetSystemMetrics(SM_CXBORDER) and GetSystemMetrics(SM_CYBORDER)?

    The method you're using seems a very roundabout way of doing it and, if you can call GetWindowRect(), I'm pretty certain you can call GetSystemMetrics() as well.

    One other possibility is to use GetWindowRect to get the entire bounding rectangle for the window and GetClientRect to get the bounding rectangle for the client (non-border) area.

    This should give you something like (100,200),(1000,900) and (112,227),(988,888) respectively and you can work out the top border as 227-200, bottom as 900-888, left as 112-100 and right as 900-888 (27,12,12,12).


    RESOLUTION:

    A bit of investigation turns up this. It's a thread from 2006 stating that you might not get the correct values from GetWindowsRect. The thread that pointed me to this stated:

    Apps under Vista that are not linked with WINVER=6 will receive a misleading set of values here, that do not account for the extra padding of "glass" pixels Vista Aero applies to the window. This appears to happen even in Aero Basic (without Glass) to retain sizing consistency. The workaround (if you don't want to set WINVER=6) seems to be to dynamically bind to dwmapi.dll and use GetProcAddress() to obtain the DwmGetWindowAttribute() function, and call it with the DWMWA_EXTENDED_FRAME_BOUNDS argument to request the genuine window frame dimensions.

    So basically, use something like (you may have to use ctypes to do this from Python):

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

    and that should give you the correct bounding rectangle.

    0 讨论(0)
  • 2020-11-28 11:59

    GetWindowRect return correct values, but for explicit handle to the window. Use GetParent function to get handle of the parent window, while GetWindoWRect return for you maximum RECT or GetParent return value is NULL.

    0 讨论(0)
  • 2020-11-28 12:10

    I know it is a bit old topic. But it took quite a bit of searching and I went through the ctypes pain myself to get paxdiablo's solution working in Python. Just wanted to share working code sample for 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()
    
    0 讨论(0)
  • 2020-11-28 12:10

    first, you call GetClientRect to retrive the client rectangle R1, then call AdjustWindowRectEx to calculate the accurate bounds according to R1.

    0 讨论(0)
  • 2020-11-28 12:12

    GetWindowRect on Windows 7 appears to not include the right and bottom window frame edges (at least with the Aero theme afaik), if the window was created without the WS_SIZEBOX style (i.e, you want a non-sizable window).

    The problem is, WS_SIZEBOX is the same as WS_THICKFRAME, and on Aero, windows have the thickframe whether they can be resized or not. But the GetWindowRect function thinks that a non-resizable window is thinner.

    The fix? You can create the window with WS_SIZEBOX, call GetWindowRect, then use SetWindowLongPtr(GWL_STYLE, ...) to turn off WS_SIZEBOX, but this will create an ugly white border inside the client area.

    Instead, leave WS_SIZEBOX enabled, and simply return the same value for ptMinTrackSize and ptMaxTraceSize in the MINMAXINFO structure when responding to the WM_GETMINMAXINFO message. This will keep the window from being resizable and GetWindowRect will return proper data. The only downside is that the mouse cursor will still change to a resizing cursor when the mouse pointer goes over the window frame, but it's the lesser of the evils so far.

    0 讨论(0)
提交回复
热议问题