Layered windows and UpdateLayeredWindow

Recently I was playing with transparent (layered) windows in Windows XP.
The basic information about layered windows is available from MSDN,
however the lack of information and examples for UpdateLayeredWindow() inspired me
to write this article.

To create a layered window flag WS_EX_LAYERED must be used.

	//here we create a layered window 
	HWND hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED, WNDCLASSNAME,  \
                                         WNDCAPTION, WS_POPUP ,  \
                                         WINDOW_X, WINDOW_Y,  \
                                         WINDOW_WIDTH, WINDOW_HEIGHT,  \
                                         NULL, NULL, hInstance, NULL); 


It is also possible to set layered flag after creation of a regular window.

	//setting extended style flag WS_EX_LAYERED);
	SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);


In short, there are two different methods to work with layered windows under Window 2000 and XP.

Scheme for working with layered windows

Using SetLayeredWindowAttributes()

The idea behind this is that you can easy create a semi transparent window and draw on this window
as you used to draw in a regular Win 32 API applications.

Application processes all regular window messages such as WM_PAINT and WM_ERASEBKGND.
SetLayeredWindowAttributes() can be used in order to change window transparency.
The function works in two alternative modes.
First mode allows to set transparency of pixels of a given color but all other pixels will be absolutely opaque.

The following code makes all white pixels on window 100% transparent

SetLayeredWindowAttributes(hWnd, RGB(0xff, 0xff, 0xff), 0, LWA_COLORKEY);
//                                                                  ^                      ^
//                                                                  |                      |
//                                                             color key          NOT USED with LWA_COLORKEY


Another mode allows to set whole window transparency for all differently colored pixels.
This example makes window 50% transparent.

SetLayeredWindowAttributes(hWnd, RGB(0xff, 0xff, 0xff), 0x7F, LWA_ALPHA);
//                                                            ^                               ^
//                                                            |                               |
//                                  not used with LWA_ALPHA     opacity level (0 to 255)


What is good and bad about this method?

+ It is easy and intuitive

- It does not allow to set per pixel transparency for complex windows.

- The performance of window drawing with SetLayeredWindowAttributes() is relatively low

Using UpdateLayeredWindow()

This is another method of drawing transparent windows which works relatively faster and it
offers more power for programmer.
This function does anything you want for a layered window.
You can change position, size, look and transparency all in one function call.
Also this function can use per pixel Alpha information stored in a bitmap to maintain pixel level transparency.

Note a few moments before using UpdateLayeredWindow().

  1. If you first call SetLayeredWindowAttributes() before UpdateLayeredWindow() you will get errors (0×06).
  2. Since MSDN unclearly says that hdcDst parameter is a “Handle to a device context (DC) for the screen” this actually means a window DC. I got error (number 6) trying to use screen DC.

So the basic scheme is the following.
In a timer message handler I draw the window contents on a memory DC.
Then I update window surface using this function.

	//
	// this function is called when hdcBackBuffer bitmap
	// contains a fresh look of the window
	//
	void __fastcall UpdateMemoWindow(HWND hWnd){
		HDC hRealDC = GetDC(hWnd);
	
			BLENDFUNCTION bfunc;
			bfunc.AlphaFormat = 0;
			bfunc.BlendFlags = 0;
			bfunc.BlendOp = AC_SRC_OVER;
			bfunc.SourceConstantAlpha = ActiveSettings.Opacity;
	
			if (ActiveSettings.TextOnly){

				//
				// BLENDFUNCTION &bfunc is not used in this case  
				// because we need to maintain color level opacity
				//
				if (!UpdateLayeredWindow(hWnd, hRealDC, &gWindowPosition, &gWindowSize, \
					 hdcBackBuffer, &PointZero, RGB(255,255,255), &bfunc, ULW_COLORKEY \
					)){
					HandleError(L"Failed to update layered window");
				}
			}else{

				//
				// the color key RGB(255,255,255) is not used in this case
				// because transparency will be based on pixels of the bitmap
				// selected for hdcBackBuffer
				//
				if (!UpdateLayeredWindow(hWnd, hRealDC, &gWindowPosition, &gWindowSize, \
					 hdcBackBuffer, &PointZero, RGB(255,255,255), &bfunc, ULW_ALPHA \
					)){
					HandleError(L"Failed to update layered window");
				}
			}
	
		ReleaseDC(hWnd, hRealDC);
	}

2 Responses to “Layered windows and UpdateLayeredWindow”

  1. Eric Layne says:

    Good article, thanks for posting this information.

RSS feed for comments on this post. And trackBack URL.

Leave a Reply