Code Based Counting and Callback Timers

This example shows how to create code based timers that are more accurate and have better resolution, about 1 millisecond, than VB's Timer control. I have implemented these code based timers in ActiveX DLLs so they do not need to be sited on a form. This allows you to use them in applications that run unattended and that have no visual interfaces.

Two types of timers are illustrated. A counting timer which returns the number of milliseconds that have elapsed since Windows was started and a callback timer. The counting time is useful when you need stop watch type functionality - to time an operation and see how long it took.

The callback timer works better in an event driven application since it gives you a way to generate a single or periodic event in you application. All timer functions are based on the Multimedia DLL - winmm.dll.

Create a code based counting timer. Create a code based callback timer.
Download Source Code

Counting Timer

This sample consists of two apps: an ActiveX DLL which implements the timer and a small program to call the dll. First you must determine the time resolution range available on your PC. Resolution is the size of the slice time can be divided into. Finding the minimum and maximum resolution is done by a call to the timeGetDevCaps API passing it a TIMECAPS structure. This structure has two elements. One to hold the minimum resolution and one for the maximum.

A call to the timeBeginPeriod API sets the resolution to use while a call to timeEndPeriod clears it. To start timing an operation you issue a call to timeGetTime which returns the time in milliseconds since Windows started. Remember this time. When your operation stops you call timeGetTime again. The difference between the two times tells how long the operation took. In this program, the operation timed is the Sleep API. Sleep simply halts processing of your program for a specified duration in milliseconds.

All calls to the timer APIs are encapsulated in the DLL. The DLL exposes properties used to retrieve the minimum and maximum resolution as well as the return value from the timeGetTime function.

Be aware that the value returned by timeGetTime is an unsigned number and can hold a value of 2^32-1 milliseconds (approximately 49 days). However, VB cannot handle unsigned integers and will only hold a number half that size. If the computer has been running for a long time, the number may switch from a positive to a negative number. You should handle this event.

Callback Timer

Simply put, a callback is when Windows calls a procedure in your application. To use callback functions with certain APIs you pass the address of your procedure to be called back using VB's AddressOf operator. I'm not going to get into the details of callbacks here, you can see my Enumerate Windows sample for more information. As the name implies the callback timer calls a procedure in your application when it triggers. That procedure can then execute the necessary code.

The callback timer has a set of functions, timeSetEvent() and timeKillEvent(), for creating and killing a timer. As with the counting time, timeBeginPeriod and timeEndPeriod set the minimum timer period. timeSetEvent specifies the timer's operating mode and takes several arguments, two of which are the callback procedure's address and the delay period. When the delay period expires the timer calls the callback procedure. Another parameter is the flags argument which tells the timer to act as a one-shot timer or to fire repeatedly.

Much of the details of the callback timer are straightforward and are left to the code itself. One important issue is that the callback procedure runs in a separate thread from your application. This poses a problem. All statements needed to raise an event in the VB class are off limits because they are run on a different thread. To get around this, an invisible window is created and subclassed to capture a special message indicating that the timer has fired. The timer procedure then uses the PostMessage API to send the appropriate message. When the subclassing procedure receives the message, it executes on the main thread so you can use all the normal VB statements. There's more. Using the PostMessage API within a callback procedure is problematic. It must be placed inside a type library.

Once all that is done, the sample application is simple. The key is to declare the timer object using the WithEvents keyword so the timer event is available.

Installing and Running

Since the DLLs are ActiveX components, they must be registered on your PC. I have included .bat files which call Regsvr32.exe (available on your VB CD) to do this. You must first edit the .bat files and make sure the paths are correct. Then select Project | References in the calling app and insure that the DLL is correctly referenced. To unregister the DLLs when you are through, edit and run the uninstall batch program. Note that the path that follows regsvr32 must be in DOS 8.3 format.

To step through the DLL code in the development environment, start the DLL project and press Control F5 to run it. Then start the calling app in a second instance of VB. Go to Project | References and reference the correct timer project (StopWatch Timer or Multimedia Callback Timer). The correct reference is the one whose path points to the Visual Basic Project. Note that stepping through a callback procedure is sure to create GPFs.


Code based timers are still subject to the operating system's load and preemptive multitasking nature. For best results, close all unnecessary applications.


Register and reference the DLLs a stated above.

Run the counting timer and enter a duration. Click the Start Timer button to time the Sleep operation. Try this with various durations. Experiment with different resolutions to test the accuracy of the timer.

Do basically the same for the callback timer. Set the repeating and enable options and set the interval.

About TheScarms
About TheScarms

Sample code
version info

If you use this code, please mention ""

Email this page

© Copyright 2016 TheScarms
Goto top of page