As part of some of your large Access applications, you often allow users to start other Windows tools (Notepad, Calculator, Calendar, etc.); once those tools are open, your application doesn’t touch them. Some users have complained about all the “junk” left over once your application closes. Is there some way you can close another window from your Access application? That way, on the way out you can close any tools your application has opened.
Section 11.9.2 demonstrated the retrieval of a list of all the running Windows applications’ captions, class names, and window handles. Once you know that information, it’s easy to close an application: given a window handle, simply tell it to close. Using the Windows API PostMessage function, you can close any window at any time. Of course, some applications (those that support Automation; see Chapter 12 for more information) allow themselves to be closed programmatically without using the Windows API. Other applications that don’t support Automation will require either the API method described here, or SendKeys, which is unreliable at best.
Load and run frmListWindows from 11-10.MDB
. This
form, shown in Figure 11-12, is similar to the sample
form in Section 11.9.2
with the addition of the Stop App button, which
lets you close the selected window. Try a few; you can even close
Access this way, if you want.
Some top-level windows shouldn’t be closed—you should never include a form like this as part of an end-user application. On the other hand, given an array of window captions and handles, you could programmatically decide which window to close and close it yourself from within your application. This form is a demonstration of the power of the method, not a tool you’d actually use.
To use this functionality in your own applications, follow these steps:
Import the modules basWindowList (if you haven’t already for Section 11.9.2 ) and basCloseWindows.
Follow the steps listed in Section 11.9.2 to create and fill in the array of top-level windows.
Decide which window you want to close. Windows sometimes appends document names to the application name (e.g., “Microsoft Word—11-10.DOC”), so check against just the first portion of the window name in your array. For example:
For intI = 0 To intCount - 1 If Left$(atypWindowList(0).strCaption, 14) = "Microsoft Word" Then ' You found a match. Do something. End If Next intI
When you’ve found the item you want to close, use the acbCloseWindow function, passing to it the handle of the window you care about:
If acbCloseWindow(atypWindowList(intI).hWnd) = 0 Then ' If you got 0 back, it got the message! End If
The acbCloseWindow
function calls the PostMessage API function. By
posting a message to a particular window, you are telling it to do
something, but you don’t bother waiting for a response. (The
corresponding API function, SendMessage,
does cause you to wait for a response. You can
use SendMessage if you want to stop and wait for
the other application to close, but we don’t recommend it.) The
acbCloseWindow function sends the
WM_CLOSE
message to your chosen window, telling it
to shut down. It’s as if you quit your Windows shell program
with some applications running. Your shell sends a message to each
main application window to shut down because Windows is shutting
down. The acbCloseWindow function, then, looks
like this:
Function acbCloseWindow (ByVal hWnd As Long) Const WM_CLOSE = &H10 acbCloseWindow = PostMessage(hWnd, WM_CLOSE, 0, vbNullString) End Function
The purpose of this wrapper function that calls PostMessage is to prevent you from having to remember how to post a message to a window. It’s a lot simpler to call acbCloseWindow than to call PostMessage directly.
Sending a WM_CLOSE
message to a window
doesn’t necessarily close it. If that application has an
unsaved document, it will pop up its own dialog asking what you want
to do with that unsaved document. In the sample form, if this
happens, the list box won’t be updated correctly. Once you
return from your duties with the foreign application, press the
Requery button on the form to force it to search again for all open
applications.