5,696,038 members and growing! (18,277 online)
Email Password   helpLost your password?
Multimedia » GDI » General     Beginner License: The Code Project Open License (CPOL)

Falling Snow on Your Desktop! Part II

By Igor Tolmachev

This article explains how to create an application that makes it snow on the desktop.
C#, Windows, Visual Studio (VS2005, VS6, Visual Studio)

Posted: 15 Dec 2007
Updated: 16 Dec 2007
Views: 11,710
Bookmarked: 28 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
7 votes for this Article.
Popularity: 3.80 Rating: 4.50 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
1 vote, 14.3%
3
2 votes, 28.6%
4
4 votes, 57.1%
5
Screenshot - FallingSnow

Introduction

Since my previous article was published, I received many user inquiries about how to improve the program. This article demonstrates how to create snow flakes that fall on your desktop, by using the draw functions directly in the desktop context. When the application starts, it creates an array of snow flakes and starts the timers for each flake. Manipulation of the RedrawWindow function allows the drawing of flakes behind and over the desktop icons, making the application more impressive.

General Steps

For better randomizing, the start coordinate, timer interval, flake position (over or behind the desktop icons) and size should be pre-defined as shown below:

 srand((unsigned)time(NULL));
 for(int i=0; i<nArray; i++)
 {
    // the snow flake movement timer
    nTimer = rand()*70/RAND_MAX+10;
    arTimers.Add(nTimer);

    // snow flake start position
    nPosX = rand()*rcWorkArea.Width()/RAND_MAX;
    arPositions.Add(nPosX);

    // draw the flake over or behind the icons
    nOver = rand()*100/RAND_MAX;
    if(nOver>50)
        arOverIcons.Add(1);
    else
        arOverIcons.Add(0);

    // draw a big or small flake
    nBig = rand()*100/RAND_MAX;
    if(nBig<50)
        arBigFlakes.Add(1);
    else
        arBigFlakes.Add(0);
 }

Then, create the flake and start the timer:

 ...
 CFlake* pFlake = new CFlake(nPosX, nBig, nOver);
 m_arFlakes.Add(pFlake);

 SetTimer(i+1,nTimer,0);
 ...

When the timer event occurs, move the appropriate flake on the desktop:

 void CMainFrame::OnTimer(UINT nIDEvent)
 {
    if(nIDEvent >= 0 && nIDEvent <= (UINT)m_arFlakes.GetSize())
    {
        CFlake* pFlake = m_arFlakes.GetAt(nIDEvent-1);
        if(pFlake)
            pFlake->Move();
    }
 }

As shown above, class CFlake (Flake in C# code) is responsible for the desktop drawing.
Unfortunately, Windows Vista does not allow the use of the RedrawWindow function with the RDW_NOERASE flag for the desktop Window correctly. So, you cannot draw the flakes behind the icons in this case.

Most of the snow fall algorithm was taken from my previous article, except the drawing functions:

 HDC hDC = GetDC(m_hWndDesktop);
 if(hDC)
 {
    RECT rc;
    rc.left = m_nCurrentX;
    rc.top = m_nCurrentY;
    rc.right = m_nCurrentX+15;
    rc.bottom = m_nCurrentY+15;

    // 15 is for a little drift at the bottom of the desktop
    int nTestHeight = m_nScreenHeight - 15; 
    
    // redraw the desktop window right away
    if(m_nCurrentY<nTestHeight) // snow drift here
        RedrawWindow(m_hWndDesktop, &rc, NULL, RDW_INVALIDATE 
            | RDW_ERASE | RDW_UPDATENOW );

    m_nCurrentY += 3;
    m_nCounter++;

    if(m_nCounter == 15)
    {
        if((rand()*10/RAND_MAX)>5) m_nIncrement = 1;
        else m_nIncrement = -1;

        m_nCounter = 0;
    }

    m_nCurrentX += m_nIncrement;

    if(m_nCurrentY>m_nScreenHeight)
    {
        m_nCurrentY = 0;
        m_nCurrentX = abs(rand()*m_nScreenWidth/RAND_MAX);
        if(abs(rand()*100/RAND_MAX)>50)
            m_bIsBigFlake = TRUE;
        else
            m_bIsBigFlake = FALSE;
    }

    // Store DC settings
    int storedDC = SaveDC(hDC);

    rc.left = m_nCurrentX;
    rc.top = m_nCurrentY;
    rc.right = m_nCurrentX+15;
    rc.bottom = m_nCurrentY+15;

    HPEN pOldPen = (HPEN)SelectObject(hDC, m_hFlakePen);

    if(m_bIsBigFlake) // draw big flake here
    {
        MoveToEx(hDC, m_nCurrentX+7, m_nCurrentY, 0);
        LineTo(hDC, m_nCurrentX+7, m_nCurrentY+15);
        ...
    }
    else // draw small flake here
    {
        ...
    }

    // specify RDW_NOERASE to keep the desktop from drawing the background
    if(!m_bIsVista)
    {
        if(!m_bOverIcons && m_nCurrentY<m_nScreenHeight)
            RedrawWindow(m_hWndDesktop, &rc, NULL, RDW_INVALIDATE 
                | RDW_NOERASE | RDW_UPDATENOW);
    }

    SelectObject(hDC, pOldPen);

    // Restore DC settings to their original values
    RestoreDC(hDC, storedDC);

    // Release the DC
    ReleaseDC(m_hWndDesktop, hDC);
 }

Finally, when the application closes, clean up the desktop in the CFlake destructor (the current flake on screen position), and in the CMainFrame::OnClose function (snow drift at the bottom of the desktop):

 CFlake::~CFlake()
 {
    ...
    RedrawWindow(m_hWndDesktop, &rc, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
 }

 void CMainFrame::OnClose()
 {
    ...
    // redraw the snow drifts area
    if(hWndDesktop)
    {
        CRect rcWorkArea;
        SystemParametersInfo(SPI_GETWORKAREA,0,(LPVOID)&rcWorkArea,0);

        rcWorkArea.top = rcWorkArea.bottom - 16;
        ::RedrawWindow(hWndDesktop, &rcWorkArea, NULL, RDW_INVALIDATE | RDW_ERASE | 
            RDW_UPDATENOW );
    }
 }

Known Problems

  • Application does not work properly when the Active Desktop is enabled.
  • Drawing the snowflakes behind the icons with this code under Windows Vista is not implemented.

Any improvements, comments or suggestions to this code are welcome.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Igor Tolmachev



Occupation: Software Developer (Senior)
Location: Ukraine Ukraine

Other popular GDI articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Search Search Messages 
 Layout  Per page   
 Msgs 1 to 12 of 12 (Total in Forum: 12) (Refresh)FirstPrevNext
GeneralIt doesn't work on XP !membergndnet5:20 27 Apr '08  
GeneralVery festivemember_awatts23:29 17 Dec '07  
GeneralRe: Very festive, can flakes be randomly drawn in front of active windowsmemberIgor Tolmachev23:29 18 Dec '07  
QuestionNeatmemberHard Coder12:19 16 Dec '07  
GeneralRe: Neat, would it be hard to fix it so that the snow falls onto windows topsmemberIgor Tolmachev23:20 18 Dec '07  
GeneralCool - but it hates 4 monitors :)memberRay Cassick19:50 15 Dec '07  
GeneralRe: Cool - but it hates 4 monitors :)memberDave Cross5:29 16 Dec '07  
GeneralRe: Cool - I have got it working with 3 monitors [modified]memberMikeWilliams23:40 17 Dec '07  
GeneralRe: Cool - I have got it working with 3 monitorsmemberIgor Tolmachev23:25 18 Dec '07  
GeneralRe: Cool - I have got it working with 3 monitorsmemberMikeWilliams0:16 19 Dec '07  
GeneralRe: Cool - but it hates 4 monitors :)memberMikeWilliams0:19 19 Dec '07  
GeneralRe: Cool - but it hates 4 monitors :)memberRay Cassick3:12 19 Dec '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 16 Dec 2007
Editor: Deeksha Shenoy
Copyright 2007 by Igor Tolmachev
Everything else Copyright © CodeProject, 1999-2008
Web13 | Advertise on the Code Project