Writing a Win32 Screen Saver

The following is a very brief description on how to write a screen saver for Windows. Certain assumptions are made; that you have a working knowledge of the Win32 API; that you're using C or at least that you can translate the c-ish statements into ML, Python or your language of choice; and that you don't mind reading articles with a less-than-perfect truth value.
A screen saver is an ordinary Windows executable (.exe) with the extension of .scr. There's some documentation on screen savers for Windows in the Win32 API, but unfortunately the documentation is pretty outdated and incomplete. Microsoft ships a library (scrnsave.lib) they suggest that you use. The library contains both a main() and a WinMain() function handling all the details of parsing parameters, creating full-screen window, starting the message loop, connecting to the password providers etc. On the downside, there is very little flexibility when it comes to writing non-standard screen-savers. The resource ID of the config dialog is fixed to 2003, you can't link your screen saver with MFC or with another C-run-time option than the scrnsave.lib, you cannot build a screen saver with MingW or CygWin. And also, for all serious graphics, you need to have your own message loop, something like this:
void DoMessageLoop(HWND hWnd, BOOL fPreview)
{
	MSG msg;

	while(TRUE){
		if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)){
			if(GetMessage(&msg, NULL, 0, 0) == 0)
				break;
			DispatchMessage(&msg);
				
		}
		else{
			UpdateScreen(hWnd, fPreview);
		}
	}
}
If you're not using your own message loop, you're left with two choices:
  1. Using a timer
  2. Creating a thread
Using a timer is slow. Even with a SetTimer with a zero millisecond delay, you still have go through the message queue of Windows, which takes for ever, more or less. (Multi-threaded applications should be avoided at all costs. Trust me.)
So, let's assume that we have decided to create a screen saver from scratch, without the library. The startup parameters is the only information available to the program. There a four obvious things a screen saver should do:
  1. Create a full-screen window and do the saving.
  2. Create a small preview window in the Control Panel.
  3. Open the Config dialog box (from the Control Panel).
  4. Open the Password dialog box (also from the Control Panel).
The different actions above is triggered by different parameters. The documentation says nothing about these parameters, since they are handled within scrnsave.lib, but since we want to do that on our own we need this information. The arguments to WinMain (or whatever your entry point function is called) are:
"/s"		start saving the screen (full size)
"/p wnd"		show a preview (with wnd as parent window)
"/a wnd"		change the password
"/c wnd"		do the config dialog
To make matters more interesting, there is also a default action with a NULL startup parameter. This happens when you right-click the file and select Test from the menu. The program should then start saving the screen full-size (same as "/s" parameter). The parent window parameter is a sprintf'ed version of the HWND (decimal representation), so you could just parse it out with:
wndParent = (HWND)atol(pszParam);
Next
Home