Finding Windows handles (20/08/13)

I was recently writing some programs which had to communicate between each other by sending Windows messages, and to do this I needed to find the handle of the window in question. For those who don't know, every window in Windows (aherm) has a unique numeric identifier called a handle. Once you know the handle, you can then direct messages to a particular window.

Here's some notes on what to do.

FindWindow()

If you know the exact title of the window in question, then the simplest option is to use the Windows API function FindWindow(). This is defined (in Visual Basic 6) by the following which can be placed in an external module, or in your main form code if you change Public to Private.

Public Declare Function FindWindow Lib "user32" Alias _
    "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName _
    As String) As Long

lpClassName determines what sort of windows the function searches for, but I usually set this to vbNullString to search for all windows (check out the MSDN page on FindWindow for more details). lpWindowName is the actual string title of the window to search for. The function returns a long value, which is the window handle. Here's how to use it:

my_hWnd = FindWindow(vbNullString, "Window title")

my_hWnd will then contain the handle of the window whose title is "Window title". If the window can't be found, the function returns 0.

This is all very well, but what happens when you don't know the exact window title? This happened to me, since the target window's title varied (a serial number was appended to the window title, and this varies between computers).

Wildcard search

I initially looked up how to do a wildcard search for window titles, and found http://www.freevbcode.com/ShowCode.asp?ID=1500 which contains a good example of how to implement a wildcard search. There is a Windows API function called EnumWindows. When started, this passes the handle of all the windows on the screen to a user-defined callback function. As long as the function returns TRUE (or nonzero), enumeration continues. The function can process each window handle until it reaches one which has a title that matches the desired search string.

Some additional functions are used to ensure that we're actually dealing with a "proper" window. IsWindowVisible checks (duh) if the window is actually visible, and GetParent is used to see if it is a top-level window (i.e. not a dialog or message box inside a program). If the window is visible and is top-level, then GetWindowText is used to retrieve the window's title. We can then check the string for a match and return a FALSE value to stop enumeration.

I've done a little VB6 demonstration program which lists the window handles and titles of all visible top-level windows. Source code and program available here (ZIP file).

Important note regarding VB6 forms

A VB6 program actually seems to have two window handles - I'm note sure exactly why this is. As a demonstration, I created a blank project with one form. The form's title is "Form caption". Under Project Properties -> Make, there is a field for the application title. I set this to "Application title" and compiled the project. Here's a screenshot of the IDE settings:

When I now list the handles of the available windows (using the example program given above), there are separate entries for "Form caption" and "Application title" with different window handles!. (E0900 and 16091E, respectively) In addition, "Application title" appears in the Task Manager, not "Form caption". Screenshot:

However, as far as communication with the window is concerned (sending messages etc.), it is the handle to the form that we want, i.e. E0900.

This probably makes sense to somebody, but not to me!