Using callback functions in API calls from Visual Basic


This page shows how to use a callback function with API calls from Visual Basic.

Example code

The example below detects all available windows on your desktop.

Using a callback function in API calls:
' Declarations

Private Declare Function EnumWindows Lib "user32.dll" _
  (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

' Main starts the enumeration, pass the address of the callback function
Public Sub Main()
  Debug.Print "============================="
  Debug.Print " Start of enumeration:"

  If EnumWindows(AddressOf EnumWindows_CallBack, 0) = 0 Then _
    Err.Raise 12345, , "Could not enumerate all windows!"

  Debug.Print "============================="
End Sub

' This function is called from the EnumWindows API
Private Function EnumWindows_CallBack(ByVal hWnd As Long, _
                                      ByVal lParam As Long) As Long
  Debug.Print "hWnd Found: " & hWnd
  EnumWindows_CallBack = 1  ' The API ends if we return false
End Function

The EnumWindows() accepts two parameters. The first parameter contains the address of your callback function in the system memory. The second parameter will be passed literally to the lParam variable of the callback function. It can be used to supply a custom value to your function. Only use the specific function declaratin dictated by the API, using a different declaration causes the application to crash.

The Main() function starts the window enumeration, and tells the EnumWindows() API to call the function EnumWindows_CallBack() each time a window is found.

The EnumWindows() API aborts it the callback function returns false.

Just to let you know...
With an API function, you shouldn't use the keywords True and False. Visual Basic uses the value -1 for true, and 0 for false. API functions expect to receive the value 1 for true, and 0 for false.

Visual Basic magic

Never close the Visual Basic application while a callback function is active. Closing the application removes the callback function from the system memory, but the API function still keeps calling your function again. As a little service, Visual Basic does overwrite the callback function with an empty function returning zero. This prevents a crash in most cases.

Modifying the callback function at run-time also doesn't do much good. Visual Basic stores the modified function at a different memory location, and the callback will fail.

AddressOf trick

The AddressOf operator can only be used in the argument list of a function. There is a little trick to store the address of the function in a variable:

Storying the AddressOf result:
' Get the value of the AddressOf operator
Public Function GetAddress(AddressOf_FunctionName As Long) As Long
  GetAddress = AddressOf_FunctionName
End Function

Public Sub Main()
  MsgBox "The address of MyFunction is: " _
       & GetAddress(AddressOf MyFunction)
End Sub

Public Function MyFunction() As Long
  ' Statements here...
  MyFunction = 0
End Function

blog comments powered by Disqus