Someone posted a question in Q&A recently, asking how to create the semi-transparent "blackout" window on the screen in the same way
that Windows does when it asks you whether to allow a program to proceed or not. I responded by saying that all you need is another window on top of the original, and a dialog box
with the question. Having thought a bit more about the problem I wondered whether that would actually work or not. After some investigation I found the answer was actually fairly simple,
once I had figured out how to create and manage the secondary window.
Using the code
The code below is fairly self-explanatory but a few notes may help:
- First we need to register a new
Windows class with the following attributes:
- No special class styles, this window does nothing much.
DefWindowProc as its message handler, as our code will not deal with any messages.
- Set the backgound colour to the system colour value
COLOR_DESKTOP, which is black on my system.
- Get the dimensions of the caller's window (see note below) and create a Window of our new class with the following attributes:
- Extended style of
WS_EX_LAYERED, this is a layered window with no frame borders.
- Styles of
WS_VISIBLE | WS_POPUP, this is a visible popup.
- The same size and position as the caller's window.
- Its parent must be the caller's Window, to make the parent inaccessible.
- Next we call
SetLayeredWindowAttributes to make the overlay completely obscure the parent window.
- Sleep for half a second. Yes, this is fluff.
SetLayeredWindowAttributes again to make the overlay semi-transparent.
- Show a dialog: I have used the system
TaskDialog to display the user's message text.
- When complete, destroy the window, unregister the class and return the response to the caller.
In my code, if the caller does not provide a Window handle then we get the handle of the Desktop Window and completely cover the screen.
BOOL StopDialog(HWND hParentWnd,
WNDCLASSEX wndClass; HWND hStopWnd; RECT rectParent; int nButton = IDNO; wndClass.cbSize = sizeof wndClass; wndClass.style = 0; wndClass.lpfnWndProc = DefWindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = GetModuleHandle(NULL); wndClass.hIcon = NULL; wndClass.hCursor = NULL; wndClass.hbrBackground = GetSysColorBrush(COLOR_DESKTOP); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = _T("Blackout"); wndClass.hIconSm = NULL; if (RegisterClassEx(&wndClass))
if (hParentWnd == NULL)
hParentWnd = GetDesktopWindow(); GetWindowRect(hParentWnd, &rectParent); int nWidth = rectParent.right - rectParent.left;
int nHeight = rectParent.bottom - rectParent.top;
hStopWnd = CreateWindowEx( WS_EX_LAYERED, wndClass.lpszClassName, NULL, WS_VISIBLE | WS_POPUP, rectParent.left, rectParent.top, nWidth, nHeight, hParentWnd, NULL, wndClass.hInstance, NULL );
SetLayeredWindowAttributes(hStopWnd, 0, 255, ULW_ALPHA);
SetLayeredWindowAttributes(hStopWnd, 0, 196, ULW_ALPHA);
HRESULT hResult = TaskDialog(hStopWnd,
NULL, szTitle, szMain, szContent, TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, TD_SHIELD_ICON, &nButton );
if (hResult != S_OK) nButton = IDNO;
UnregisterClass(wndClass.lpszClassName, wndClass.hInstance); }
return nButton == IDYES ? TRUE : FALSE; }
- Initial post 27 October 2013
- Cosmetic changes: 20 November 2013
- Added sample image: 20 November 2013.
I was a Software Engineer for 40+ years starting with mainframes, and moving down in scale through midi, UNIX and Windows PCs. I started as an operator in the 1960s, learning assembler programming, before switching to development and graduating to COBOL, Fortran and PLUS (a proprietary language for Univac systems). Later years were a mix of software support and development, using mainly C, C++ and Java on UNIX and Windows systems.
Since retiring I have been learning some of the newer (to me) technologies (C#, .NET, WPF, LINQ, SQL, Python ...) that I never used in my professional life, and am actually able to understand some of them.
I still hope one day to become a real programmer.