Security Blackout Window

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>//////<paramname="hParentWnd">Handle to the parent window to be obscured</param>///<paramname="szTitle">optional title of the dialog box</param>///<paramname="szMain">Main line of text</param>///<paramname="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 windowint 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 iconif (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 windowint 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
}

Share

About the Author

I was a Software Support Engineer for many years using various legacy enterprise systems before learning UNIX and Windows programming - the latter largely in my own time. In my last few years of employment I spent more time in actual development.

Since retiring I have been learning some of the newer technologies (C#, .NET, WPF, LINQ, SQL ...) that I never used in my professional life, and am actually able to understand some of it.

As a small point of information, what Windows effectively does is take a snapshot of the current desktop and it uses this a semi-transparent bitmap behind the dialog. This is achieved through the use of the Security Desktop[^].