That's not a bug. In Windows 10 the borders on left/right/bottom are transparent. The top border is not transparent. You should leave it as is. Probably nobody will complain.
To change it, you must modify the non-client area. This is rather difficult in Windows Vista and above. See Custom Window Frame Using DWM for reference.
Windows 10 example:
(See the next example for compatibility with Windows Vista, 7, 8)
//requires Dwmapi.lib and UxTheme.lib
#include <Windows.h>
#include <Dwmapi.h>
void my_paint(HDC hdc, RECT rc)
{
HBRUSH brush = CreateSolidBrush(RGB(0, 128, 0));
FillRect(hdc, &rc, brush);
DeleteObject(brush);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static RECT border_thickness;
switch (uMsg)
{
case WM_CREATE:
{
//find border thickness
SetRectEmpty(&border_thickness);
if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME)
{
AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
border_thickness.left *= -1;
border_thickness.top *= -1;
}
else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER)
{
SetRect(&border_thickness, 1, 1, 1, 1);
}
MARGINS margins = { 0 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
HDC memdc;
HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, ¶ms, &memdc);
my_paint(memdc, rc);
BufferedPaintSetAlpha(hbuffer, &rc, 255);
EndBufferedPaint(hbuffer, TRUE);
EndPaint(hwnd, &ps);
return 0;
}
case WM_NCACTIVATE:
return 0;
case WM_NCCALCSIZE:
if (lParam)
{
NCCALCSIZE_PARAMS* sz = (NCCALCSIZE_PARAMS*)lParam;
sz->rgrc[0].left += border_thickness.left;
sz->rgrc[0].right -= border_thickness.right;
sz->rgrc[0].bottom -= border_thickness.bottom;
return 0;
}
break;
case WM_NCHITTEST:
{
//do default processing, but allow resizing from top-border
LRESULT result = DefWindowProc(hwnd, uMsg, wParam, lParam);
if (result == HTCLIENT)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hwnd, &pt);
if (pt.y < border_thickness.top) return HTTOP;
}
return result;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int)
{
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
CreateWindowEx(0, CLASS_NAME, NULL,
WS_VISIBLE | WS_THICKFRAME | WS_POPUP,
10, 10, 600, 400, NULL, NULL, hInstance, NULL);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
For compatibility with Windows Vista/7/8 use this procedure instead. This will paint over left/top/bottom borders as well as top border. This window will appear as a simple rectangle, with resizing borders:
//for Windows Vista, 7, 8, 10
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static RECT border_thickness;
switch (uMsg)
{
case WM_CREATE:
{
//find border thickness
SetRectEmpty(&border_thickness);
if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_THICKFRAME)
{
AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
border_thickness.left *= -1;
border_thickness.top *= -1;
}
else if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_BORDER)
{
SetRect(&border_thickness, 1, 1, 1, 1);
}
MARGINS margins = { 0 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
HDC memdc;
HPAINTBUFFER hbuffer = BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, ¶ms, &memdc);
my_paint(memdc, rc);
BufferedPaintSetAlpha(hbuffer, &rc, 255);
EndBufferedPaint(hbuffer, TRUE);
EndPaint(hwnd, &ps);
return 0;
}
case WM_NCACTIVATE:
return 0;
case WM_NCCALCSIZE:
if (lParam)
return 0;
case WM_NCHITTEST:
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hwnd, &pt);
RECT rc;
GetClientRect(hwnd, &rc);
enum {left=1, top=2, right=4, bottom=8};
int hit = 0;
if (pt.x < border_thickness.left) hit |= left;
if (pt.x > rc.right - border_thickness.right) hit |= right;
if (pt.y < border_thickness.top) hit |= top;
if (pt.y > rc.bottom - border_thickness.bottom) hit |= bottom;
if (hit & top && hit & left) return HTTOPLEFT;
if (hit & top && hit & right) return HTTOPRIGHT;
if (hit & bottom && hit & left) return HTBOTTOMLEFT;
if (hit & bottom && hit & right) return HTBOTTOMRIGHT;
if (hit & left) return HTLEFT;
if (hit & top) return HTTOP;
if (hit & right) return HTRIGHT;
if (hit & bottom) return HTBOTTOM;
return HTCLIENT;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Best Answer
The programs remove the non-client area (the title bar) and have a bunch of custom handling for reproducing the window buttons, icons, system menu etc. The benefit of this is that they can draw to the new "title bar", which is actually part of the standard client area, adding tabs or other custom controls.
The following two articles will show you how to do this on Vista and above (using the DWM):
This is very complex to do and get right, so the above two articles are invaluable. The author must have put a lot of work into them! Both links have example code written in Delphi, but it should be easy enough to translate it to C++ - the concepts are identical, it's just syntax.
You might also be interested in general resources on Glass and DWM, since it's all closely related. You'll spot the above two links included in that list :)