Introduction
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.
- Use
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.
- Call
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.
#include <Windows.h>
#include <tchar.h>
#include <Commctrl.h>
BOOL StopDialog(HWND hParentWnd,
PTSTR szTitle,
PTSTR szMain,
PTSTR szContent
)
{
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 );
if (hStopWnd)
{
SetLayeredWindowAttributes(hStopWnd, 0, 255, ULW_ALPHA);
Sleep(500);
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;
DestroyWindow(hStopWnd); }
UnregisterClass(wndClass.lpszClassName, wndClass.hInstance); }
return nButton == IDYES ? TRUE : FALSE; }
History
- Initial post 27 October 2013
- Cosmetic changes: 20 November 2013
- Added sample image: 20 November 2013.