Using Timer Callbacks

This section describes how an application might use the timer services. First, the application calls the timeGetDevCaps function to determine the minimum and maximum resolution supported by the timer services. Before setting up any timer events, the application uses timeBeginPeriod to establish the minimum timer resolution it will use, as shown in the following code fragment:

#define TARGET_RESOLUTION 1         // Try for 1-millisecond accuracy

TIMECAPS tc;
WORD     wTimerRes;

if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
{
    // Error; application can't continue
}

wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
timeBeginPeriod(wTimerRes);

To start the timer event, the application specifies the amount of time before the callback occurs, the required resolution, the address of the callback function, and user data to supply with the callback. The application might use a function like the following to start a one-time timer event:

WORD SetTimerCallback(NPSEQ npSeq,          // Sequencer data
                      WORD msInterval)      // Event interval
{
    npSeq->wTimerID = timeSetEvent(
         msInterval,                        // Delay
         wTimerRes,                         // Resolution (global variable)
         OneShotCallback,                   // Callback function
         (DWORD)npSeq,                      // User data
         TIME_ONESHOT );                    // Event type (one-time)

    if(! npSeq->wTimerID)
        return ERR_TIMER;
    else
        return ERR_NOERROR;
}

The following callback function resides in a fixed code segment in a DLL. It is limited to calling those functions that are interrupt-callable. The TimerIntRoutine procedure it calls also resides in a fixed code segment.

void FAR PASCAL
OneShotTimer(WORD wId, WORD msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
    NPSEQ npSeq;              // Pointer to sequencer data

    npSeq = (NPSEQ)dwUser;
    npSeq->wTimerID = 0;      // Invalidate timer id, since no longer in use

    TimerIntRoutine(npSeq);   // Handle interrupt-time tasks
}

Before freeing the DLL that contains the callback function, the application cancels any outstanding timers. To cancel one timer event, it might call the following function:

void DestroyTimer(NPSEQ npSeq)
{
    if(npSeq->wTimerID)                     // If timer event is pending
    {
        timeKillEvent(npSeq->wTimerID);     // Cancel the event
        npSeq->wTimerID = 0;
    }
}

Finally, to cancel the minimum timer resolution it established, the application calls timeEndPeriod as follows:

timeEndPeriod(wTimerRes);