13

I want to calculate the full size of a window before opening it. I'm using AdjustWindowRectEx() to achieve this. My code looks like this for a window with a client size of 640x480:

    wrect.left = 0;
    wrect.top = 0;
    wrect.right = 640;
    wrect.bottom = 480;
    AdjustWindowRectEx(&wrect, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, FALSE, 0);

This returns the following values:

    left: -3
    top: -22
    right: 643
    bottom: 483

However, when opening the window using CreateWindowEx() and passing

    wrect.right - wrect.left
    wrect.bottom - wrect.top

as the window size, the window's size physical size actually turns out to be 656x515 pixels. Still, GetWindowRect() returns 646x505, i.e. the same dimensions as returned by AdjustWindowRectEx() but as I said, when I take a screenshot of the desktop and measure the window's size using a paint program, its physical size is actually 656x515 pixels. Does anybody have an explanation for this?

The client size is alright, it's 640x480 but it looks like the border size is calculated wrongly because the border uses more pixels than calculated by AdjustWindowRectEx() and GetWindowRect().

I'm on Windows 7.

EDIT:

Is this downvoted because the title of the question is misleading? As stated in the MSDN autodocs, WS_OVERLAPPED is not supported by AdjustWindowRectEx(). So is there any other way to calculate the dimensions of a WS_OVERLAPPED window? Using WS_OVERLAPPEDWINDOW instead is not a solution because it sets the WS_THICKFRAME and WS_MAXIMIZEBOX which I don't want.

Here is some test code now which shows the problem. You can see that the client size is alright but the window's physical size is larger than what is returned by GetWindowRect().

#include <stdio.h>

#include <windows.h>

#define CLASSNAME "Test"

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{  
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wcx;
    RECT wrect;
    HWND hWnd;
    char tmpstr[256];

    memset(&wcx, 0, sizeof(WNDCLASSEX));

    wcx.cbSize = sizeof(WNDCLASSEX);
    wcx.style = CS_HREDRAW|CS_VREDRAW;  
    wcx.lpfnWndProc = WindowProc;
    wcx.hInstance = hInstance;
    wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcx.hbrBackground = GetStockObject(BLACK_BRUSH);  // important! otherwise a borderless window resize will not be drawn correctly        
    wcx.lpszClassName = CLASSNAME;

    RegisterClassEx(&wcx);

    wrect.left = 0;
    wrect.top = 0;
    wrect.right = 640;
    wrect.bottom = 480;     
    AdjustWindowRectEx(&wrect, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, FALSE, 0); 

    hWnd = CreateWindowEx(0, CLASSNAME, "Test", WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, 0, 0, wrect.right - wrect.left, wrect.bottom - wrect.top, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, SW_SHOWNORMAL);

    GetWindowRect(hWnd, &wrect);
    sprintf(tmpstr, "%d %d %d %d\n", wrect.left, wrect.top, wrect.right, wrect.bottom);

    AllocConsole();
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), tmpstr, strlen(tmpstr), NULL, NULL);

    GetClientRect(hWnd, &wrect);
    sprintf(tmpstr, "%d %d %d %d\n", wrect.left, wrect.top, wrect.right, wrect.bottom);
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), tmpstr, strlen(tmpstr), NULL, NULL);

    Sleep(10000);

    DestroyWindow(hWnd);        
    UnregisterClass(CLASSNAME, hInstance);          

    return 0;
}   
Andreas
  • 9,245
  • 9
  • 49
  • 97
  • 2
    Perhaps you could you make a complete program to demonstrate the issue – David Heffernan Jan 13 '15 at 17:53
  • You seem to be unsure about whether to make this a child window or not. Provide a `WS_CHILD` or `WS_POPUP` window style. – IInspectable Jan 13 '15 at 17:55
  • @DavidHeffernan: see above. Example code is now there. – Andreas Jan 13 '15 at 18:53
  • The window's reported size excludes OS chrome like dropshadows etc. – Jonathan Potter Jan 13 '15 at 19:53
  • Yes, that's what I assumed but I didn't count the drop shadows at all. The size returned by AdjustWindowRectEx() is really *way off* the real size. If you take a look at the physical size of the window opened by the code above, you'll notice that the left window border is 8 pixels and the right window border is 8 pixels, the drop shadow not included of course. Makes 16 pixels in total. Still, AdjustWindowRectEx() just gives 6 pixels on the x-axis, i.e. 3 pixels per side. That's a completely useless result then because it's 10 pixels off. – Andreas Jan 13 '15 at 20:08
  • Since *WS_OVERLAPPEDWINDOW* does the trick, remove the *WS_MAXIMIZEBOX* with `WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)`. – γηράσκω δ' αεί πολλά διδασκόμε Jan 13 '15 at 22:01
  • 1
    See my comments above. WS_OVERLAPPEDWINDOW also sets WS_THICKFRAME which I don't want. The window should not get a sizing border. – Andreas Jan 13 '15 at 22:14

2 Answers2

7

GetWindowRect api doesn't give the correct size:

Due to compatability requirements, certain metrics are reported in such a way that they're not consistent with what is actually drawn on the screen when Aero Glass (more accurately, "Windows Vista Aero") is enabled. This sort of approach is needed in order to change the look of the system for the vast majority of apps for which this isn't an issue.However, there's been a recent change in the system which will be coming out in Vista RC1 that will return the correct rendered value from GetWindowRect() for executables that are linked with "winver = 6.0". This allows new and newly-linked applications to get the "correct" values from GetWindowRect().

GetWindowRect on non-resizable windows under Aero Glass

Use instead DwmGetWindowAttribute to get the correct size:

DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &wrect, sizeof(wrect));
  • Thanks, I'm indeed compiling with WINVER set to 0x500 so this explains the wrong values. But still: DwmGetWindowAttribute() requires a window handle. Is there also a function that can be used to calculate the size *without* a window handle? I'd need something like AdjustWindowRectEx() that is compatible with Aero Glass. – Andreas Jan 15 '15 at 21:49
0

If AdjustWindowRect doesn't work, just try to create the Window and adjust the size after the window is created.

// Create the window with a nearly correct size
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 640;
rect.bottom = 480;  
AdjustWindowRectEx(&rect, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, FALSE, 0); 

// try
hWnd = CreateWindowEx(0, CLASSNAME, "Test", WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);

// Get the size that is really required and adjust
RECT rectCreated;
GetWindowRect(hWnd, &rectCreated);
rect.right += rectCreated.right-rectcreated.left;
rect.bottom += rectCreated.bottom-rectcreated.top;

// Resize to let the window fir the inner client aea
SetWindowPos(hWnd,NULL,0,0,rect.right-rect.left,rect.bottom-rect.top,SWP_NOMOVE|SWP_NOZORDER);

// Show it.
ShowWindow(hWnd, SW_SHOWNORMAL);

Code is not tested. Hopefully I have no bugs or syntax errors in it.

xMRi
  • 14,982
  • 3
  • 26
  • 59
  • 2
    But GetWindowRect() gives the wrong size as well. See my example code above. GetWindowRect() returns the same size as AdjustWindowRectEx() but they're both wrong. – Andreas Jan 14 '15 at 15:46