Home All Groups Group Topic Archive Search About
Author
19 Mar 2006 1:30 AM
arno
Hi all,

Sorry if this is very newbie. Despite a lot of info on the net I am
having great difficulty with the following:

I want to get a list of the open windows that are part of an
application I am talking to. There seems to be no shortage of ways
thru the WinAPI to do so, notably FindWindowEx and EnumChildWindows.
So far, I have successful in retrieving the window handle of the main
application. Being a relative novice to VB and esp. winAPI stuff, I
got stuck when it comes to the listing the 'child' windows part. There
is a lot of talk on 'callback' functions that I don't really
understand. Any suggestions are appreciated.

kind regards,
arno

Author
19 Mar 2006 5:56 PM
Randy Birch
To use an API function that provides callback functionality, you provide -
as one of the parameters to the callback-capable API call - the memory
address of a function that you have defined in your application. Windows
then uses this memory address (and thus, your provided function) to "call
back" to your app to provide the information you requested. A callback
function can be thought of as "here's what I want" (the type of data the API
returns), and "here's where I want it put" (the address of the callback
function).

The memory address of your application-defined callback function is passed
to the API using the AddressOf function introduced in VB5 and VB6 (note that
VBA - the version of VB used by MS Office and some other commercial apps
does not natively provide AddressOf, though this can be worked around).

With real VB, your application-defined callback function must reside in a
bas module. Furthermore, as Windows is passing data to the function the
definition of your callback must adhere to the specifications expected by
windows. You can name the callback anything you want as to Windows this is
nothing more than a memory address. It is customary to use the name
identified in the MSDN as this makes it clear to most what the purpose of a
particular function is.

In the case of EnumWindows, two pieces of data are passed back to the
callback: the hwnd of the window being enumerated and an application-defined
value that you assign when making the initial API call (more on this later).
Because Windows may be calling this repeatedly (and very very rapidly), it
is also customary to do a minimal amount of processing of the data Windows
returns while inside the callback procedure.

It is important to note that a callback function does not exist within
Windows; that is, there is no API named EnumWindowsProc. Rather, The MSDN
refers to the callback to EnumWindows as "EnumWindowsProc" in order to
provide the required definition of the callback procedure that it expects
when passing data to your app.

The MSDN definition of EnumWindowsProc is:

BOOL EnumWindows(

    WNDENUMPROC lpEnumFunc,
    LPARAM lParam
);

.... which translates to VB code as:

Public Function EnumWindowProc(ByVal hwnd As Long, _
                                                  ByVal lParam As Long) As
Long


The API (EnumWindows) is defined as:

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

.... and the calling syntax would be:

   Call EnumWindows(AddressOf EnumWindowProc, &H0)


Call EnumWindows(AddressOf EnumWindowProc, &H0)

Most callbacks have a short-circuit mechanism that allows you to stop the
callback before all data has been received. This could be used, for example,
when the data you've been expecting finally is provided and you don't need
Windows to continue sending the callback further data. This short-circuiting
is affected by setting the return value to the callback procedure. In the
case of EnumWindowsProc, your application returns True to continue
enumeration, or False to stop. (Remember that in C, True in defined as 1,
not -1 - the value of VB's True constant. This may or may not make a
difference to a call). So, to enumerate everything (all top-level windows)
EnumWindowsProc returns 1...

Public Function EnumWindowProc(ByVal hwnd As Long, _
                                                  ByVal lParam As Long) As
Long

   <your code to handle the data returned to this function>

   EnumWindowProc = 1

End Function


A function related to EnumWindows (the one you want) is called
EnumChildWindows.  EnumChildWindows also provides callback functionality
through a callback defined and identified in the MSDN as "EnumChildProc":

BOOL CALLBACK EnumChildProc(

    HWND hwnd,
    LPARAM lParam
);


You'll see this definition matches the definition for EnumWindowsProc (the
actual variable names are irrelevant to the code). So technically the
callback you defined for EnumWindows could also be reused for
EnumChildWindows. But personally, because you normally perform different
actions on the data returned through callbacks depending on the API called,
I find it easier to one define callback function for each individual API I
use, rather than try to utilize the same callback function for multiple APIs
(when all use the same definition, of course!) even when the definitions are
identical.

You can find an example of using both EnumWindows and EnumChildWindows in
the demo at http://vbnet.mvps.org/code/enums/enumwindowsdemo.htm.  There are
a number of different APIs providing callback functionality on the parent
index page http://vbnet.mvps.org/code/enums/.  Or you could search for
AddressOf on my site to see the list of 70 examples using this
functionality.

One caveat -- just because an API includes Enum in its name does not
necessarily mean that API provides a callback. An example of this is
EnumDisplayDevices -- this API needs to be repeatedly called in a loop with
you (your app) incrementing a value in each subsequent call to get the next
piece of information (see
http://vbnet.mvps.org/code/enums/enumdisplaydevices.htm).

-----------

With respect to a point I mentioned earlier, namely that some callbacks
provide you to pass an application-defined value when making the initial API
call --- consider EnumFontFamilies shown at
http://vbnet.mvps.org/code/enums/enumfonts.htm. When calling this API, which
does provide for a callback, the demo passes a list box as the
application-defined value. This in turn is handed to the EnumFontFamProc
routine where it is used to populate a list on the form without the
necessity to use frmMain.List1.Additem directly.

--

Randy Birch
MS MVP Visual Basic
http://vbnet.mvps.org/

Please reply to the newsgroups so all can participate.




Show quoteHide quote
"arno" <rNOSPAMnospam@xs4all.nl> wrote in message
news:2icp12lqhhft4cp8j4lvp3k4k7tpvi9bpt@4ax.com...
: Hi all,
:
: Sorry if this is very newbie. Despite a lot of info on the net I am
: having great difficulty with the following:
:
: I want to get a list of the open windows that are part of an
: application I am talking to. There seems to be no shortage of ways
: thru the WinAPI to do so, notably FindWindowEx and EnumChildWindows.
: So far, I have successful in retrieving the window handle of the main
: application. Being a relative novice to VB and esp. winAPI stuff, I
: got stuck when it comes to the listing the 'child' windows part. There
: is a lot of talk on 'callback' functions that I don't really
: understand. Any suggestions are appreciated.
:
: kind regards,
: arno
Author
20 Mar 2006 6:59 PM
arno
Many thanks for your wealth of information. Very helpful indeed. I
feel confident I can get it done now. Thanks again

arno




On Sun, 19 Mar 2006 12:56:59 -0500, "Randy Birch"
<rgb_removet***@mvps.org> wrote:

Show quoteHide quote
>To use an API function that provides callback functionality, you provide -