Constructing Your Screen SaverPreview 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
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.
Use Class Wizard to add a new class, based on ‘generic CWnd’.
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.
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; } |
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 ; } |
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 } |
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); } |
Code is the same :
BOOL PreviewWnd::DestroyWindow() { if (m_iTimer != 0 ) KillTimer(1); return CWnd::DestroyWindow(); } |
void PreviewWnd::PostNcDestroy() { delete this ; } |
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(); } |
Not much code needed here :
PreviewWnd::PreviewWnd() { m_iTimer = 0 ; srand(::GetTickCount()) ; } |
The only code needed is to clean up any memory you may have allocated.
The next page discusses the screen saver configuration dialog box.