Constructing Your Screen Saver

Preview Window

This page shows the C++ code you need for the screen saver preview window.


I've had enough! I want to go home

I want to see the previous page

Take me to the next page


The Preview Window

The Preview Window is a small scale version of the full-screen window, that gets displayed in the Control Panel "Display Properties" window. I prefer to create it as a separate class, firstly because that avoids a lot of code to test whether it is a full-screen or preview window, and secondly because I usually get the preview window to do something different from the full-screen window.

I won’t go into too much detail in describing the various bits of code you need to insert, because most of that has been covered in describing the full-screen window.

The preview window has much less work to do than the full-screen window does. It does not have to respond at all to user input, it does not need to change the cursor, it does not need to know which version of Windows is being used, and it does not need to display any password screens.


Creating the Class

Use Class Wizard to add a new class, based on ‘generic CWnd’.


Preview Window Creation

The preview window needs to be a child of the window associated with the handle passed as a command line parameter. The preview window needs to be of the same size and occupy the same position as the parent window.

The ‘OnCreate’ code should look like this :

BOOL PreviewWnd::Create(HWND hParentWnd) 
{
    BOOL bRes ;

    RECT parentRect ;

    // Register a class 

    const char* pszClassName 
         = AfxRegisterWndClass(CS_SAVEBITS, 0 , 0 , 0 );

    // Create the window
#ifdef _DEBUG
    bRes = CWnd::CreateEx(0 , 
                          pszClassName,
                          "",
                          WS_POPUP | WS_VISIBLE,
                          0 , 0 , 
                          300 , 200 ,
                          NULL,
                          0);
#else
    ::GetClientRect(hParentWnd , &parentRect);

    bRes = CWnd::CreateEx(0 , 
                          pszClassName,
                          "",
                          WS_CHILD | WS_VISIBLE,
                          0 , 0 , 
                          parentRect.right , parentRect.bottom ,
                          hParentWnd,
                          0);
#endif

    if ( bRes ) 
    {
        m_iTimer = SetTimer(1, 50 , NULL);
    }

    return bRes ;
}

This creates a borderless, childless window.

Note that I only create a child window if I am compiling the Release version, because Control Panel will supply the parent window. But for debugging, there is no readily available parent window. For the Debug version, I just create a small window in the top left corner of the screen. You will need to press Alt-F4 to close it. This lets me test the preview window code.

Note that you will need to change the parameters expected for the ‘Create’ function. This version of ‘Create’ expects a handle to the parent window as the only parameter.


OnCreate ( WM_CREATE)

The code is much the same as for the full-screen window :

int PreviewWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1 ;

    CDC * pDC = GetDC() ;

    // set up images, palettes, image buffers, etc.

    ReleaseDC(pDC) ;

    return 0;
}


OnEraseBkGnd (WM_ERASEBKGND)

The code is the same as for the full-screen window :

BOOL PreviewWnd::OnEraseBkgnd(CDC* pDC) 
{
    RECT winSize ;

    pDC->GetClipBox( &winSize) ;

    pDC->FillSolidRect ( &winSize , RGB(0,0,0) ) ;	

    return TRUE ;
}


OnPaint ( WM_PAINT)

Code is much the same as for the full-screen window :

void PreviewWnd::OnPaint() 
{
    CPaintDC dc(this); // device context for painting
	
    CRect paintRect ( &dc.m_ps.rcPaint ) ;

    // add code to repaint the area within paintRect
}


OnTimer (WM_TIMER)

Code is the same as for the full-screen window :

void PreviewWnd::OnTimer(UINT nIDEvent) 
{
    CDC * pDC = GetDC() ;

    // update the screen

    ReleaseDC (pDC) ;
	
    CWnd::OnTimer(nIDEvent);
}


DestroyWindow

Code is the same :

BOOL PreviewWnd::DestroyWindow() 
{
    if (m_iTimer != 0 ) 
	KillTimer(1);
    
    return CWnd::DestroyWindow();
}


PostNcDestroy

void PreviewWnd::PostNcDestroy() 
{
    delete this ;
}


Palettes

The preview window does need to be concerned about palettes if the screen is running in 256-colour mode, because it is not going to be the foreground window all the time. Therefore, you will need to have the palette handling code in place.

The actual code is the same as for the full-screen window :

void PreviewWnd::OnPaletteChanged(CWnd* pFocusWnd) 
{
    // System palette has changed

    CWnd::OnPaletteChanged(pFocusWnd);

    // only a concern if it was not us that changed it

    if ( pFocusWnd != this ) 
    {
        if ( m_iScreenBpp == 8 )
        {
            CDC * pDC = GetDC() ;
            pDC->SelectPalette(m_MasterPalette,FALSE);
            int i = pDC->RealizePalette() ;        // returns number of colours
                                                   // that were remapped
            if ( i > 0 )
            {
                // redraw the screen, so that colours are mapped properly

                InvalidateRect ( NULL , TRUE ) ; // cause OnPaint to be called
           }
           ReleaseDC(pDC);
        }
    }
}

BOOL PreviewWnd::OnQueryNewPalette() 
{
    if ( m_iSscreenBpp == 8)
    {
        CDC * pDC = GetDC() ;
        pDC->SelectPalette(m_MasterPalette,FALSE);
        int i = pDC->RealizePalette() ;        // returns number of colours
                                              // that were remapped
        if ( i > 0 )
        {
            // redraw the screen, so that colours are mapped properly

           InvalidateRect ( NULL , TRUE ) ; // cause OnPaint to be called
        }
        ReleaseDC(pDC);

        return i ;
    }
    else	
        return CWnd::OnQueryNewPalette();
}


Constructor

Not much code needed here :

PreviewWnd::PreviewWnd()
{
    m_iTimer = 0 ;
    srand(::GetTickCount()) ;
}


Destructor

The only code needed is to clean up any memory you may have allocated.


The next page discusses the screen saver configuration dialog box.


Next | Previous | Home

1