Security Blackout Window






4.98/5 (15 votes)
Obscure a window or the screen and show a dialog.
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>
/// <summary>
/// This function registers and creates a simple overlay Window
/// that is used to obscure the current window or the entire Desktop
/// until a dialog has been responded to.
/// </summary>
///
/// <param name="hParentWnd">Handle to the parent window to be obscured</param>
/// <param name="szTitle">optional title of the dialog box</param>
/// <param name="szMain">Main line of text</param>
/// <param name="szContent">supplementary dialog text</param>
///
/// <returns>TRUE or FALSE, depending on the user's response</returns>
///
BOOL StopDialog(HWND hParentWnd,
PTSTR szTitle,
PTSTR szMain,
PTSTR szContent
)
{
WNDCLASSEX wndClass; // class structure to register the obscuring window
HWND hStopWnd; // handle to the obscuring window
RECT rectParent; // to get the dimensions of the parent window
int nButton = IDNO; // default answer
// Register the window class
wndClass.cbSize = sizeof wndClass; //
wndClass.style = 0; // no styles for this class
wndClass.lpfnWndProc = DefWindowProc; // we will not handle any messages
wndClass.cbClsExtra = 0; // no extra space required
wndClass.cbWndExtra = 0; //
wndClass.hInstance = GetModuleHandle(NULL); // instance handle to the current process
wndClass.hIcon = NULL; // no icon
wndClass.hCursor = NULL; // or cursor
wndClass.hbrBackground = GetSysColorBrush(COLOR_DESKTOP); // a black brush
wndClass.lpszMenuName = NULL; // no menu
wndClass.lpszClassName = _T("Blackout"); // our class name
wndClass.hIconSm = NULL; // no small icon
if (RegisterClassEx(&wndClass))
{
if (hParentWnd == NULL)
hParentWnd = GetDesktopWindow(); // if no window given, then we will use the entire desktop
GetWindowRect(hParentWnd, &rectParent); // get the dimensions of the parent window
int nWidth = rectParent.right - rectParent.left;
int nHeight = rectParent.bottom - rectParent.top;
// create the overlay window
hStopWnd = CreateWindowEx( // create a new window same size and position as the parent
WS_EX_LAYERED, // this is a layered window
wndClass.lpszClassName, // registered class name
NULL, // no title necessary
WS_VISIBLE | WS_POPUP, // it's a popup and always visible
rectParent.left, // horizontal position of window
rectParent.top, // vertical position of window
nWidth, // window width
nHeight, // window height
hParentWnd, // handle to parent or owner window
NULL, // no menu handle
wndClass.hInstance, // handle to application instance
NULL // no create parameters
);
if (hStopWnd)
{
// we have our overlay window so set it to totally obscure its parent
SetLayeredWindowAttributes(hStopWnd, 0, 255, ULW_ALPHA);
// wait half a second
Sleep(500);
// now set it less opaque and show the response dialog
SetLayeredWindowAttributes(hStopWnd, 0, 196, ULW_ALPHA);
// We use a standard Windows TaskDialog control as it is far simpler
// than creating a custom dialog box, although that is still an option.
HRESULT hResult = TaskDialog(hStopWnd,
NULL, // no hInstance as we use system icons and buttons
szTitle, // title provided by the caller
szMain, // main message ditto
szContent, // secondary message ditto
TDCBF_YES_BUTTON | TDCBF_NO_BUTTON, // use the Yes and No buttons
TD_SHIELD_ICON, // and system shield icon
&nButton // response stored in here
);
if (hResult != S_OK) // if the dialog fails for any reason, we answer No
nButton = IDNO;
DestroyWindow(hStopWnd); // finished with our obscuring window
}
UnregisterClass(wndClass.lpszClassName, wndClass.hInstance); // and finished with our class
}
return nButton == IDYES ? TRUE : FALSE; // return TRUE if the user answers Yes, otherwis FALSE
}
History
- Initial post 27 October 2013
- Cosmetic changes: 20 November 2013
- Added sample image: 20 November 2013.