Creating a Callback Function

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

You can determine whether a DLL function requires a callback function by looking at its arguments and reading the documentation for the function. An argument that takes a pointer to a callback function is a long pointer, usually prefaced with the prefix "lp". Also, the name of the argument usually ends in "Func", indicating that it takes a pointer to a function. For example, take a look at the Declare statement for the EnumWindows function. The lpEnumFunc argument indicates that the function requires a callback function.

Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, _
              ByVal lngParam As Long) As Long

How do you know what the callback function should look like? The answer is in the documentation for the function. Each callback function has different arguments. Unfortunately, although information about DLL functions requiring callbacks is available in Win32API.txt, information about creating the callback functions themselves is not.

The Microsoft Platform SDK, available on the Microsoft® Developer Network (MSDN®) Web site at http://msdn.microsoft.com, contains information about all DLL functions that require callbacks and their corresponding callback functions and is probably the best source for this information. However, to use it, you must be able to interpret C and C++ documentation and translate it to Microsoft® Visual Basic® for Applications (VBA).

You can name the callback function whatever you want to; the suggested name is usually the name of the DLL function followed by "Proc". For example, the suggested name for the callback function of the EnumWindows function is EnumWindowsProc.

NoteYou can have more than one callback function for the same DLL function.

Here is the C/C++ definition for the EnumWindowsProc function, as described in the Platform SDK:

BOOL CALLBACK EnumWindowsProc( 
   HWND hwnd, // handle to parent window 
   LPARAM lParam // application-defined value
);

Translated to VBA, this function becomes:

Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
End Function

The hwnd argument is a handle to a window. The lParam argument is an application-defined argument that can be any data type. The value you pass to the lParam argument for the EnumWindows function is also the value passed to the lParam argument of the EnumWindowsProc function. You do not have to define lParam as a Long; you can define it as another type if you know you will be passing in, say, a ListBox control or an array. Also, you do not have to pass any value to lParam at all.

Callback functions usually return a Long value — nonzero for success, zero for failure. To continue enumerating, a callback function must return True, so you must explicitly set the return value to True within the function. Setting it to False halts the enumeration. The function will run until it either finishes enumerating or returns False.

Caution Be careful when defining the callback function. You must include the ByVal keyword where necessary, and you must include the return value for the function. In addition, the function must be declared exactly according to the documentation. If you do not define the function correctly, your application most likely will cause an application error when you try to run it.

When you call the EnumWindows function, this function calls the EnumWindowsProc function in your VBA project for each existing window, passing in the window's handle and whatever value is contained in the lParam argument. You can add whatever code you want within the callback function.

The following example shows a callback function for the EnumWindows function. This callback function, EnumWindowsProc, adds each visible parent window to the ParentWindows collection — a custom collection of ParentWindow objects. To add windows to the collection, the collection object is passed into the callback function in the lParam argument. The procedure calls two other functions: the IsWindowVisible API function, which determines whether a given window is visible, and the GetWindowCaption procedure, which in turn calls the GetWindowText API function to return the window's caption.

Note Parent windows are primary application windows; child windows are windows that exist within parent windows. A separate DLL function, EnumChildWindows, exists for enumerating child windows within parent windows.

Function EnumWindowsProc(ByVal hWnd As Long, ByVal lParam As Object) As Long
   ' Add all visible windows to ParentWindows collection.
   ' This is the callback function called by EnumWindows.
   '
   ' The hWnd argument provides a handle to a specific window each time
   ' the callback function runs.
   ' The lParam argument can take any data that the user wants to pass to
   ' the function. In this case, it is defined as type Object, so
   ' the EnumWindows function can pass in a reference to the ParentWindows
   ' collection.
   '
   ' You could use this function to return both visible and non-visible
   ' windows by removing the code that calls the IsWindowVisible function.
   
   Dim strCaption As String
   Dim pwnNew As ParentWindow
   
   ' Check whether this window is visible.
   If IsWindowVisible(hWnd) Then
      ' Add new ParentWindow object to ParentWindows collection.
      Set pwnNew = lParam.Add(hWnd)
      ' Call function to enumerate child windows.
      EnumChildWindows hWnd, AddressOf EnumChildWindowsProc, _
         pwnNew.ChildWindows
   End If
  
   ' Return True to continue enumerating windows.
   ' Function will stop running when all windows have been
   ' enumerated.
   EnumWindowsProc = True
End Function

This procedure is used to create objects in a small custom object model. The ParentWindows collection contains ParentWindow objects, which refer to individual visible windows. The address of the EnumWindowsProc function is passed to the EnumWindows function, which is called from the Class_Initialize event procedure for the ParentWindows collection, so the existing windows are added to the collection immediately.

When the ParentWindows collection has been initialized, you can refer to a ParentWindow object within the collection by its index or by its key, which is the window's handle. Use the Item property of the ParentWindows collection to refer to a member of the collection. For example, the following code fragment prints the caption of the third ParentWindow object in the ParentWindows collection:

Debug.Print ParentWindows.Item(3).Caption

See Also

Wrapping DLL Functions | Encapsulating the DLL | What Is a Callback Function? | Calling a Callback Function