Recipe 11.8 Check to See if an Application Is Already Running

11.8.1 Problem

You need to start up other Windows programs from within your Access application?for instance, to send data to Excel or to format a report in Word. If you just use the Shell command to start these programs, you may end up with multiple instances of the application. How can you tell if an application is already running before you attempt to start it?

11.8.2 Solution

There are a number of solutions to this problem, and none, unfortunately, are as easy as you might like. To ask Windows whether Excel is currently running and receive an answer, you must know the Windows class name for the main window of the application. This solution explains the format of the question and how to ask it. In addition, it demonstrates how to switch to a running application from your Access application.

If you have code that interacts with applications external to Access, it is often useful to be able to determine whether the application is running. The sample form, frmAppsRunning (Figure 11-10), asks Windows the question, "Is this app running?" for each of six predefined window classes, and you can add one more of your own. For each application that frmAppsRunning finds, it fills in the window handle (hWnd) column and the window caption column on the form. The AppActivate command in Access requires that you know the exact title of the window, so this form uses code from Chapter 4 (in basAccessCaption) to retrieve the caption for each running application. Finally, you can click on any of the enabled buttons in the righthand column to switch to the running application.

Figure 11-10. frmAppsRunning shows the state of certain applications
figs/acb2_1110.gif

Try the sample form with Microsoft applications you have installed. Press F1 to bring up Help, and then switch back to Access and click on the Search button on the sample form. This will reinitiate the search for active applications, and it will find WINHELP.EXE running. Click on the question-mark icon to switch back to WinHelp.

Follow these steps to include this functionality in your own applications:

  1. Import the modules listed in Table 11-9 from 11-08.MDB into your application.

Table 11-9. Modules to import from 11-08.MDB

Module

Contains

basCaption

acbGetAccessCaption, acbGetWindowCaption, acbSetAccessCaption

basUsage

acbIsAppLoaded

  1. To be able to ask Windows the question, "Is some application running?", you'll need to know the Windows class name for the main window of the application. Table 11-10 lists the names for several Windows applications.

Table 11-10. Windows application class names

Application

Class name

Access (all versions)

OMain

Excel (all versions)

XLMain

Explorer

ExploreWClass

Outlook (all versions)

rrctrl_renwnd32

Notepad

Notepad

PowerPoint 2003

PP11FrameClass

WordPad

WordPadClass

Microsoft Word (all versions)

OpusApp

  1. The class names are somewhat arbitrary. Because they're assigned by the development staff, not by the marketing or documentation departments, class names often reflect the project's code name or the state of mind of the developer.

Finding Class Names

There are many ways to find the class names for applications' main windows. The simplest is to use the sample form for the Solution in Recipe 11.9, which displays a list of open windows and their class names. If you want to know the class name for a specific application, open it and run the sample form. The second column will list the class name for you.


  1. To check whether a given application is currently running, use the acbIsAppLoaded function in basUsage. Pass a class name to this function as a parameter, and it returns the window handle of the application if it's running, or 0 if it's not. For example, this will return a nonzero value if Microsoft Word is currently running (note that the class names are not case-sensitive):

    hWnd = acbIsAppRunning("opusapp")
  2. Once you know the window handle for the application, you can use the AppActivate command in Access to make that application active. To do this, you'll need to know the exact window caption. To make that easier, you can call the acbGetWindowCaption function in basCaption before attempting to activate the application. For example, this code will switch to Excel, if it's running:

    Dim hWnd as Integer
    
    hWnd = acbIsAppLoaded("XLMain")
    If hWnd <> 0 Then
       AppActivate acbGetWindowCaption(hWnd)
    End If
  3. If the application you want to activate isn't currently running (acbIsAppLoaded returned 0), use the Shell command to start it. In this case, you'll need to know the DOS executable filename for the given application (EXCEL.EXE, for example). The example form doesn't attempt to load the applications if they aren't already loaded, but your own application can load the program as needed.

11.8.3 Discussion

The acbIsAppLoaded function couldn't be simpler: It calls a single Windows API function. The entire routine looks like this:

Function acbIsAppLoaded (ByVal varClassName As Variant) As Long
   If IsNull(varClassName) Then
      acbIsAppLoaded = 0
   Else
      acbIsAppLoaded = acb_apiFindWindow(CStr(varClassName), 0&)
   End If
End Function

This routine allows you to pass in a class name. If the class name isn't null, the function calls the FindWindow API function (aliased as acb_apiFindWindow), which takes a class name and returns the window handle of the first instance of that class it finds. acbIsAppLoaded returns that handle to its caller.

This example uses the following code from basCaption to determine the caption of a window, given its window handle. Although this code isn't the focus of this section, you'll need to include it if you want to find a window's caption.

Declare Function acb_apiSetWindowText Lib "user32" _
 Alias "SetWindowTextA" (ByVal hwnd As Long, _
 ByVal lpString As String) As Long
Declare Function acb_apiGetWindowText _
 Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, _
 ByVal lpString As String, ByVal aint As Long) As Long

Public Function acbGetWindowCaption(ByVal hwnd As Long) As Variant

   ' Get any window's caption, given its hWnd.

   Dim strBuffer As String
   Dim intLen As Integer

   Const acbcMaxLen = 128

   If hwnd <> 0 Then
      strBuffer = Space(acbcMaxLen)
      intLen = acb_apiGetWindowText(hwnd, strBuffer, acbcMaxLen)
      acbGetWindowCaption = Left$(strBuffer, intLen)
   End If
End Function

Don't expect acbIsAppLoaded to distinguish between multiple copies of the same application. That is, if you have two copies of Notepad running, you can't count on acbIsAppLoaded to return the handle to a specific instance of Notepad: it will return the handle of the first instance it comes across. But that shouldn't bother you, as you're simply trying to find out if any copy of the application is currently running.