6

So I'm trying to create a window that only shows its borders and have the rest of the body be see through. I've created a mockup of what that would look like in my head:

Transparent window, only displaying a border and showing whatever would be underneath it

I tried blitting in a buffer with transparent pixels but that did not have the desired effect.

Any ideas ?

asked Mar 20, 2018 at 9:31
3
  • 3
    WS_EX_LAYERED with a color key: msdn.microsoft.com/en-us/library/ms997507.aspx Commented Mar 20, 2018 at 9:39
  • 1
    @HansPassant: This is really only half a solution. It doesn't explain, how to solve the hard part: Which key color do you use, so as to prevent parts of the non-client area from turning transparent? And given the requirements spelled out, a layered window needlessly wastes resources here. Commented Mar 20, 2018 at 9:48
  • You choose the colors your window uses. So you pick the color you want to be transparent. Fuschia is a common choice, for example. And Layered windows are designed for performance and efficiency, they will not "waste resources". Commented Jan 22, 2025 at 15:38

1 Answer 1

14

This is possible by passing the WS_EX_NOREDIRECTIONBITMAP 1 extended window style to a call to CreateWindowEx. This prevents the system from allocating a render surface for the window's client area, leaving the client area completely transparent.

Note, that this does not make the window transparent to mouse clicks. Hit testing is still governed by the window, even if it doesn't have a visible client area.

The following code provides a minimal code sample that showcases the use:

#define UNICODE
#include <Windows.h>
#pragma comment(lib, "user32.lib")
int CALLBACK wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int) {
 WNDCLASSW wc{};
 wc.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
 wc.hInstance = hInstance;
 wc.lpszClassName = L"TransparentWindow";
 wc.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT
 {
 switch (message) {
 case WM_DESTROY:
 ::PostQuitMessage(0);
 return 0;
 default:
 return ::DefWindowProcW(hWnd, message, wParam, lParam);
 }
 };
 ::RegisterClassW(&wc);
 ::CreateWindowExW(WS_EX_NOREDIRECTIONBITMAP, wc.lpszClassName, L"Transparent window",
 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
 nullptr, nullptr, hInstance, nullptr);
 MSG msg{};
 while (::GetMessageW(&msg, nullptr, 0, 0) > 0) {
 ::DispatchMessageW(&msg);
 }
 return msg.wParam;
}

This produces output similar to the following screenshot:

Screenshot of sample application


More information on the internals, as well as a common use case can be found in Kenny Kerr's excellent June 2014 MSDN Magazine article Windows with C++ : High-Performance Window Layering Using the Windows Composition Engine.


1 This requires desktop composition to be enabled. Desktop composition is available in all supported versions of Windows, but can be disabled by the user/system administrator prior to Windows 8.

answered Mar 20, 2018 at 9:36
Sign up to request clarification or add additional context in comments.

12 Comments

@JonathanPotter: I believe that is true. Starting with Windows 8, you cannot turn off desktop composition. And given that Windows 7 SP1 has been on extended support for more than 3 years, I didn't think of spelling this out explicitly. It still warrants a note, though.
@IInspectable Thanks for the notes, it won't be a problem for me since I use the Desktop Duplication API, which doesn't run on anything lower than Windows 8.
Is CS_HREDRAW | CS_VREDRAW necessary? I removed it and didn't notice any adverse effect. IMO it just generates needless WM_PAINT messages.
I see that Kenny Kerr has used CS_HREDRAW | CS_VREDRAW in his example, but he doesn't explain why.
@zett42: Those class styles are indeed not necessary. When there is nothing to draw, requesting WM_PAINT messages on resize doesn't make sense. The reason I used those class styles is, because I didn't put any thought into a line of code I must have written a few million times. Kenny Kerr is using those styles presumably because his code eventually is rendering to a Direct3D swap chain. I updated the code in this answer, though, and removed the unnecessary class styles.
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.