Tricks of the Windows Game Programming Gurus:Windows GDI, Controls, and Last-Minute Gift Ideas

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

#### The WM_TIMER Message

The PC has a built-in timer that can be very accurate (in the microsecond range), but because we’re programming in Windows, it’s not a good idea to muck with the timer ourselves. Instead, we’ll use the timing functions built into Windows (which are built upon the actual hardware timer). The cool thing about this approach is that Windows virtualizes the timer into an almost infinite number of virtual timers. Thus, from your point of view, you can start and receive many messages from a number of timers, even though there’s only one physical timer on most PCs.

When you create a timer you set the ID of the timer along with the delay. The timer will begin to send messages to your `WinProc()` at the specified interval. Take a look at Figure 4.10 to see the data flow of some timers. Each timer sends `WM_TIMER` messages when its elapsed time has passed. You tell one timer from another when processing the `WM_TIMER` message with the timer ID (which you set when you create the timer). With that in mind, let’s take a look at the function to create a timer—`SetTimer()`:

    UNIT SetTimer(HWND hWnd,     // handle to parent window

                  UINT nIDevent, // timer id

                  UINT nElapse,  // time delay in milliseconds

                  TIMERPROC lpTimerFunc); // timer callback

Figure 4.10 Message flow for the `WM_TIMER` message.

To create a timer you need:

  • The window handle
  • ID of choice
  • The time delay in milliseconds

With these three things, you’re in business. However, the last parameter takes a little explanation. `lpTimerFunc()` is a callback function just like `WinProc()` is, hence, you can create a timer that calls a function at some specified interval instead of processing it in the `WinProc()` via `WM_TIMER` messages. It’s up to you, but I usually use the `WM_TIMER` messages and leave the `TIMERPROC` set to`NULL`.

You can create as many timers as you wish, but remember that they all take up resources. If the function fails, it will return 0. Otherwise, `SetTimer()` returns the timer ID you sent to create the timer with.

The next question is how to tell one timer from another. The answer is that you interrogate the `wparam` when the `WM_TIMER` message is sent; it contains the timer ID that you originally created the timer with. As an example, here’s how you would create two timers, one with a 1.0 second delay and the other with a 3.0-second delay:

    #define TIMER_ID_1SEC   1

    #define TIMER_ID_3SEC   2

    // maybe do this in WM_CREATE

    SetTimer(hwnd, TIMER_ID_1SEC, 1000,NULL);

    SetTimer(hwnd, TIMER_ID_3SEC, 3000,NULL);

Notice that the delays are in milliseconds. In other words, 1000 milliseconds equals 1.0 seconds and so forth. Moving on, here’s the code you would need to add to your `WinProc()` to process the timer messages:

    case WM_TIMER:

         {

         // what timer fired?

         switch(wparam)

                {

                case TIMER_ID_1SEC:

                     {

                     // do processing here

                     } break;

                case TIMER_ID_3SEC:

                     {

                     // do processing here

                     } break;

                default:break;

                } // end switch

          // let windows know we handled the message

          return(0);

         } break;

Finally, when you’re done with a timer, you can kill it with `KillTimer()`:

    BOOL KillTimer(HWND hWnd,       // handle of window

                   UINT uIDEvent ); // timer id

Continuing with the example, you might want to kill all the timers in the `WM_DESTROY` message, as shown here:

    case WM_DESTROY:

         {

          // kill timers

         KillTimer(hwnd, TIMER_ID_1SEC);

         KillTimer(hwnd, TIMER_ID_3SEC);

         // terminate application or whatever…

         PostQuitMessage(0);

         } break;

> Note: Even though timers may seem free and abundant, PCs aren’t Star Trek computers. Timers use resources and should be used sparingly. Make sure to kill any timer that you don’t need anymore during run-time.

As a working example of using timers, take a look at `DEMO4_6.CPP` on the CD. It creates three timers with different times and then prints out when each timer changes. Finally, although timers take time delays in milliseconds, they are hardly millisecond-accurate. Don’t expect your timers to be more accurate than 10–20 milliseconds. If you need more accuracy, there are methods, such as using the Win32 High Performance timers or using the Pentium Real-Time hardware counters based on the RDTSC assembly language instruction.

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.