I'm trying to achieve something like Visual Studio installer does with borderless window and drop shadow:
I tried various options like CS_DROPSHADOW
and DWM API, but as soon as I apply the WS_THICKFRAME
style the shadow disappears.
This is my code for creating and centering a window:
RECT R = {0, 0, _clientWidth, _clientHeight};
AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
_mainWnd = CreateWindow(L"D3DWndClassName", _mainWndCaption.c_str(), WS_OVERLAPPEDWINDOW, 100, 100, R.right, R.bottom, nullptr, nullptr, _appInst, nullptr);
if(!_mainWnd){
MessageBox(nullptr, L"CreateWindow FAILED", nullptr, 0);
PostQuitMessage(0);
}
RECT rc;
GetWindowRect(_mainWnd, &rc);
LONG lStyle = GetWindowLong(_mainWnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU );
SetWindowLong(_mainWnd, GWL_STYLE, lStyle);
int xPos = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2;
int yPos = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2;
SetWindowPos(_mainWnd, 0, xPos, yPos, _clientWidth, _clientHeight, SWP_NOZORDER);
ShowWindow(_mainWnd, SW_SHOW);
UpdateWindow(_mainWnd);
You can create this effect by using a combination of
DwmExtendFrameIntoClientArea()
and returning0
fromWM_NCCALCSIZE
if wParam isTRUE
. Detailed steps below.WS_CAPTION|WS_POPUP
works well for me), but don't include any ofWS_MINIMIZE
,WS_MAXIMIZE
,WS_SYSMENU
.DwmExtendFrameIntoClientArea()
withMARGINS{0,0,0,1}
. We don't really want a transparent frame, so setting the bottom margin only is enough.SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)
to let the system recalculate NC area.WM_NCCALCSIZE
if wParam isTRUE
. This has the effect of extending the client area to the window size including frame, but excluding the shadow. See remarks section of the documentation.WM_PAINT
draw your frame and content area as you like but make sure to use an opaque alpha channel (value of 255) for the margin area defined by theDwmExtendFrameIntoClientArea()
call. Otherwise part of regular frame would be visible in this area. You may use GDI+ for that as most regular GDI functions ignore alpha channel.BitBlt()
with a 32bpp source bitmap containing an opaque alpha channel also works.WM_NCHITTEST
if you want a resizable window.The effect of all this is, that you paint "over" the regular window frame which is now inside the client area due to the DWM calls, but keep the regular window shadow. Don't worry the "paint over" doesn't create any flickering, even if you make the window resizable.
You can put any standard or user-defined controls into this window. Just make sure child controls don't overlap the margin defined by the
DwmExtendFrameIntoClientArea()
call because most GDI-based controls ignore the alpha channel.Here is a minimal, self-contained example application: