32
      ::GetSystemMetrics (SM_CYBORDER)

...comes back with 1 and I know the title bar is taller than ONE pixel :/

I also tried:

     RECT r;
      r.left = r.top = 0;   r.right = r.bottom = 400;
      ::AdjustWindowRect (& r, WS_OVERLAPPED, FALSE);
      _bdW = (uword)(r.right - r.left - 400);
      _bdH = (uword)(r.bottom - r.top - 400);

But border w,h came back as 0.

In my WM_SIZE handler, I need to make sure the window's height changes in "steps" so, for example a whole new line of text could fit in the window with no "junky partial line space" at the bottom.

But ::MoveWindow needs the dimensions WITH the border space added in.

SOMEbody must have done this before... Thanks for any help :)

Stephen Hazel
  • 859
  • 2
  • 12
  • 27
  • The docs for `AdjustWindowRect` say, rather unhelpfully, that you cannot use `WS_OVERLAPPED` with it. – JWWalker Feb 01 '12 at 20:31
  • @JWWalker: Actually, that's rather helpful. Now if you also know that `WS_OVERLAPPED` is defined as `0x0`, it should be obvious, why, too. – IInspectable Nov 15 '17 at 22:34
  • 1
    @IInspectable, no, I have no idea why it's relevant that `WS_OVERLAPPED` is 0. – JWWalker Nov 16 '17 at 16:19

7 Answers7

43

The GetWindowRect and GetClientRect functions can be used calculate the size of all the window borders.

Suite101 has a article on resizing a window and the keeping client area at a know size.

Here is their sample code:

void ClientResize(HWND hWnd, int nWidth, int nHeight)
{
  RECT rcClient, rcWind;
  POINT ptDiff;
  GetClientRect(hWnd, &rcClient);
  GetWindowRect(hWnd, &rcWind);
  ptDiff.x = (rcWind.right - rcWind.left) - rcClient.right;
  ptDiff.y = (rcWind.bottom - rcWind.top) - rcClient.bottom;
  MoveWindow(hWnd,rcWind.left, rcWind.top, nWidth + ptDiff.x, nHeight + ptDiff.y, TRUE);
}
Weak to Enuma Elish
  • 4,622
  • 3
  • 24
  • 36
stukelly
  • 4,257
  • 3
  • 37
  • 44
  • 5
    There's a WinAPI function to resize the window to have a given client area size: AdjustWindowRectEx() – Zebra North Jan 10 '09 at 20:32
  • 2
    I think I'll stick with the GetWindowRect() - GetClientRect() method. That way I don't have to mess with window styles from heck. Which is the same problem I'll have with GetSystemMetrics(whatever)... Thanks everyone - this place rocks :) – Stephen Hazel Jan 11 '09 at 05:29
  • This solution won't work if the window is minimized due to the adjustments made to the window size – Thomas M Dec 06 '12 at 16:59
  • 3
    I don't think that this method works with Windows 10, because of the transparent 8px border that allows the resizing of the window. – Nicke Manarin May 21 '17 at 01:41
16
int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);

In fact, the above result might be equal to:

GetClientRect(hWnd, &rcClient); 
GetWindowRect(hWnd, &rcWind); 
int border_thickness = ((rcWind.right - rcWind.left) - rcClient.right) / 2; 

but GetSystemMetrics(SM_CXSIZEFRAME) is easier to be used.

BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
Tody.Lu
  • 161
  • 1
  • 2
  • 2
    Without passing in hWnd how would GetSystemMetrics know what window you are referring to? Different windows can have different border thicknesses. I think your function retrieves a system-wide setting. – Billkamm Dec 13 '18 at 18:47
11

I think what you're looking for is SM_CYCAPTION -- that's the height of the title bar. SM_CYBORDER is the height of the horizontal edges of a window.

Head Geek
  • 38,128
  • 22
  • 77
  • 87
5

The method suggested by stukelly will work unless the window is minimized or not fully initialzied. An alternate approach that will give you the border size in these conditions is to use the AdjustWindowRectEx function. Here is an example:

CSize GetBorderSize(const CWnd& window)
{
   // Determine the border size by asking windows to calculate the window rect
   // required for a client rect with a width and height of 0
   CRect rect;
   AdjustWindowRectEx(&rect, window.GetStyle(), FALSE, window.GetExStyle());
   return rect.Size();
}

Depending on the application, it may be necessary to combine this approach with stukelly's if the current visible border size is necessary:

CSize GetBorderSize(const CWnd& window)
{
   if (window.IsZoomed())
   {
      // The total border size is found by subtracting the size of the client rect
      // from the size of the window rect. Note that when the window is zoomed, the
      // borders are hidden, but the title bar is not.
      CRect wndRect, clientRect;
      window.GetWindowRect(&wndRect);
      window.GetClientRect(&clientRect);
      return wndRect.Size() - clientRect.Size();
   }
   else
   {
      // Determine the border size by asking windows to calculate the window rect
      // required for a client rect with a width and height of 0. This method will
      // work before the window is fully initialized and when the window is minimized.
      CRect rect;
      AdjustWindowRectEx(&rect, window.GetStyle(), FALSE, window.GetExStyle());
      return rect.Size();
   }
}
Thomas M
  • 939
  • 7
  • 10
2

Head Geek gives the detailed answer: use GetSystemMetrics to add up the caption and border bits. You can also do a difference on width/height between the GetWindowRect and GetClientRect. This will give you the total of all captions/borders/etc.

1

The GetWindowInfo function is able to return the border width and height of a given window.
The cxWindowBorders member gets the vertical border width, and cyWindowBorders gets the horizontal border height.
This also provides values of the resizing borders mentioned in the comments of this answer, the value on this machine is 7px, it might be different in others. Thus in further testing, it appears the retrieved member values accord to just one border of the window, not both.

Laurie Stearn
  • 959
  • 1
  • 13
  • 34
0

You have another solution... You can pre calculate the border by calling a dedicated function while in WM_CREATE and WM_INITDIALOG messages. And refresh the values when you change your window style or when menu split in two rows.

RECT cRect, wRect, oRect;
GetWindowRect(hWnd, &wRect);
GetClientRect(hWnd, &cRect);
MapWindowPoints(hWnd, NULL, (LPPOINT)&cRect, 2);

oRect.left = cRect.left - wRect.left;
oRect.top = cRect.top - wRect.top;
oRect.right = wRect.right - cRect.right;
oRect.bottom = wRect.bottom - cRect.bottom;