A timer without a timer control

One of the most powerful and yet one of the least understood new features introduced in Visual basic version 5 was the AddressOf keyword. What this keyword does is return the loaded memory address of a function which can then be passed to any API call which requires a pointer to a function as it's parameter call.

In itself this isn't very exciting, but it does allow the Visual Basic programmer to use one of the most powerful features in Win32 programming - the callback.
The following example introduces this and shows one of the most simple implementations: a timer without using the Visual basic timer control. The API calls used in this example are:

Public Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long


The last parameter to SetTimer is defined in the API documentation as "pointer to a TIMER PROC". This means that you need to use AddressOf to pass the pointer and the procedure argument that this takes must be compatible with a TIMERPROC. The C++ declaration of this is:

typedef VOID (CALLBACK* TIMERPROC)(HWND, UINT, UINT, DWORD);

Where hWnd is a LONG which uniquely identifies the window with which the timer proc is associated. You will notice that the other parameters are defined as UINT and DWORD - niether of which exist in Visual Basic. This is not a problem, however, as they are the same size as the Visual Basic LONG data type.

Public Sub VB_TIMERPROC(ByVal hwnd As Long, ByVal uint1 As Long, ByVal nEventId As Long, ByVal dwParam As Long)

Because the return from this procedure is defined as a VOID, it is implemented in visual basic as a subroutine. A word of warning - this procedure must return to the calling program even if an error occurs. For this reason, the first line of code is:

On Error Resume Next

I would not recommend this for any procedure which is not used in a callback, however.
In order to start the timer running, you need to call the SetTimer API call:

Dim lRet As Long
lret = SetTimer(Me.hwnd, 1, 100, AddressOf VB_TIMERPROC)


Typically I would do this in the Form_Load() code. The event id (1) uniquely identifies this timer, and the elapse (100) is the timer interval in milliseconds.
Before the form is unloaded, you need to unset the timer. This is done with the KillTimer call.

lret = KillTimer(Me.hwnd, 1)

And there you have it - a timer without using the timer control and a gentle introduction to callbacks.

You might also like...

Comments

 MerrionComputing

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The trouble with programmers is that you can never tell what a programmer is doing until it's too late.” - Seymour Cray