Developing a Windows Screen saver

Written by:Obscurity
Published by:Nightscript
Published on:2004-07-01 05:41:16
Topic:c

In this article you'll see how to code a Windows screen saver through the predefined screen saver library. You'll also see some basic GDI code.

In Windows there is a predefined library and header file especially for developing screen savers. This allows less coding time (and less of a mess) when developing screen savers.

So we will start off with looking at some skeleton code to start developing a screen saver. This skeleton code can qualify as a screen saver, it has everything you need; it will produce a black screen saver. Not very lively, if you ask me.

#include <windows.h>
#include <scrnsave.h>

#pragma comment(lib, "scrnsave.lib")
/*
If using Dev-C++ in the pragma comment change 'scrnsave.lib'
to 'libscrnsave.a' without the quotes.
*/

LRESULT WINAPI ScreenSaverProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
       case WM_CREATE:
         break;
       case WM_DESTROY:
         PostQuitMessage(0);
         break;
       case WM_PAINT:
         break;
       default:
         return DefScreenSaverProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    return FALSE;
}

BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
    return TRUE;
}


As you can see, the code is not very big, or excessively advanced with Win32 API. As you can see you need to link the scrnsave library and add the scrnsave header file. There is a true beauty about the scrnsave library, it already has the WinMain function there so you don't need to code that into your screen saver, it registers basically a black background and that's it. That is what our skeleton code does, it's a fully functioning screen saver, but it doesn't have any the razzle dazzle you would usually see.

Let's take a look at ScreenSaverProc, in a lamen term it's the equivalent of WndProc in standard Windows applications.

LRESULT WINAPI ScreenSaverProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
       case WM_CREATE:
         break;
       case WM_DESTROY:
         PostQuitMessage(0);
         break;
       case WM_PAINT:
         break;
       default:
         return DefScreenSaverProc(hwnd, message, wParam, lParam);
    }
    return 0;
}


As I said previously ScreenSaverProc is just another Windows procedure, but instead of using the return function DefWindowProc, we use DefScreenSaverProc. I've heard that some people use DefWindowProc as a return for ScreenSaverProc, but I've had runtime errors with it.

You can see there are 3 messages there (WM_CREATE, WM_DESTROY & WM_PAINT), those are specifically for the next example; usually you will see WM_CREATE, WM_DESTROY, WM_TIMER, and WM_ERASEBKGND used when developing screen savers.

I would imagine you are asking yourself what is with the other two procedures, those are formalities when developing a screen saver. They are both used when developing a dialog for screen saver adjustment. We're not going to go into that here, so the return values will suffice.

Well, here's the semi-reasonable example of a screen saver, it has some GDI basics, but that is a whole different article. I've put some comments in there so you can get the jist of what is going on.

#include <windows.h>
#include <scrnsave.h>

#pragma comment(lib, "scrnsave.lib")

HBITMAP p_bmp = NULL;

LRESULT WINAPI ScreenSaverProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_CREATE:
         /* Uploading a bitmap from our hard disk */
         p_bmp = LoadImage(NULL, "C:untitled.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
         if(p_bmp == NULL){
           MessageBox(hwnd, "Fatal Error: 101", "Error", MB_OK | MB_ICONEXCLAMATION);
         break;
       case WM_DESTROY:
         DeleteObject(p_bmp); /* Deleting the bitmap when Screen saver is done */
         PostQuitMessage(0);
         break;
       case WM_PAINT:
       {
         BITMAP bm; /* Bitmap structure as seen in bmWidth & bmHeight */
         PAINTSTRUCT ps;

         HDC hdc = BeginPaint(hwnd, &ps);
         HDC hdcMem = CreateCompatibleDC(hdc);
         HBITMAP hbmOld = SelectObject(hdcMem, p_bmp);

         GetObject(p_bmp, sizeof(bm), &bm);

         bm.bmWidth = 1000;
         bm.bmHeight = 700;

         BitBlt(hdc, 5, 5, bm.bmWidth, bm.bmHeight, hdcMem, 5, 5, SRCCOPY);

         SelectObject(hdcMem, hbmOld);
         /* Deleting memory so we don't have any resource leaks */
         DeleteDC(hdcMem);

         EndPaint(hwnd, &ps);
       }
         break;
       default:
         return DefScreenSaverProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    return FALSE;
}

BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
    return TRUE;
}



NOTE: I haven't double checked all the GDI stuff, but it does compile and display a bmp.

One last thing, after you compile a screen saver, it saves automatically as an executable. You need to change the file extension to scr. eg: screensaver.scr.

As well, you need to put the screen saver in C:WinntSystem32 if you're on NT/2k. And if you're on Win9x/ME put it into C:WindowsSystem.

Can you count how many times I've said screen saver in this article?


This is an article from http://www.osix.net - view the original at: http://www.osix.net/modules/article/?id=538