Lesson 1: Starting, Activating, and Closing Applications

Lesson Objectives

Upon completion of this lesson, the participant will be able to:

Some Topics to be introduced in this lesson include:

Activating Applications

Switching to another application means the same thing as "giving it focus" or "activating" it. There are a variety of ways a macro in a source application can make a target application active. Most of them require that the target application is running and is in the Windows Task List. An "invisible" application is one that is running in memory, but is not physically visible and does not show up in the Windows Task List. Throughout Module 3, unless specified otherwise, the phrase "visible application" or "running visibly" means the application is in the Windows Task List, not that it's physically visible. This concept is covered in detail in Lesson 3.

If invisible applications aren't strange enough, an application can have no windows at all, so there is nothing to activate. Such an application can still show up in the Windows Task List, for example a VB3 program that has a Main procedure but no Forms. The rest of Module 3 assumes all running applications have a window and are in the Windows Task List unless specified otherwise.

Here's some items related to activating an application:

AppActivate

The most common way to activate an application The application to be activated has to be in the Windows Task List. AppActivate is discussed in detail later.

AppMaximize, AppMinimize, AppRestore (MSProject window only)

Another application can use DDE or OLE Automation to tell MSProject to execute one of these. MSProject must be in the Windows Task List. The MSProject window is activated as well as changed in the specified manner. See MSProject Online Help for more information about these methods.

Visible Property

Many applications that support OLE Automation have a Visible property. If an application is running but not in the Windows Task List, then setting its Visible property to True will add it to the Windows Task List and activate it. If it's already in the Windows Task List, then setting Visible to True does nothing. OLE Automation and the Visible property are covered in detail in Lesson 3.

Shell

The Shell command is normally used to start an instance of an application, but can also be used to switch to a currently running application that supports only one instance. For example, using the Shell command in an Excel macro to start MSProject will simply switch to MSProject if it's already running. The Shell command is discussed in detail later in this lesson.

AppExecute

MSProject also has the AppExecute method which can be used to start or switch to a target application. The AppExecute method is discussed in detail later in this lesson.

The table below provides some comments and sample code illustrating some of the ways to activate an application.

AppActivate Target Application must be in the Windows Task List. You specify the window title that you want to activate. In VB for Applications, you don't have to specify the name of maximized documents. MSProject macro that switches to an instance of Excel that is in the Windows Task List.

Sub Sub1()

AppActivate "Microsoft Excel"

End Sub

AppMaximize

AppMinimize

AppRestore

MSProject methods. Another application can use DDE or OLE Automation to tell MSProject to execute one of these. MSProject must be in the Windows Task List. Excel macro that switches to MSProject and maximizes it - MSProject must be in the Windows Task List.

Sub Sub2()

Dim x As Object

Set x = GetObject(,"MSProject.Application")

x.AppMaximize

End Sub

Visible A property common to many applications that support OLE Automation. If an application is running but not in the Windows Task List, setting its Visible property to True will add it to the Windows Task List and activate it. If it's already in the Windows Task List, setting Visible to True does nothing. It's usually used in combination with AppActivate. Excel macro that activates MSProject. MSProject must be running but doesn't have to be in the Windows Task List. Setting Visible to True covers that possibility.

Sub Sub3()

Dim x As Object

Set x = GetObject(,"MSProject.Application")

x.Visible = True

AppActivate "Microsoft Project"

End Sub

Shell If the target application is already running (in the Windows Task List or not), and supports only one instance, then Shell activates it rather than starting it. Excel macro that switches to MSProject if it is already running, otherwise it starts MSProject.

Sub Sub4()

Shell "C:\Winproj\Winproj.exe", 3

End Sub

AppExecute Specific to MSProject. MSProject can use this to activate an application in the Windows Task List or to start another application. Requires an exact window title in order to switch to another application. MSProject macro to switch to Excel if "Microsoft Excel - Book1" is in the Windows Task List.

Sub Sub5()

AppExecute Window:="Microsoft Excel - Book1"

End Sub

AppActivate title [ , wait ]

Used to switch to any application listed in the Windows Task List.

title

In VB3 this must be set to the title bar text of the window to be activated - including the hyphen and document name if there is an open maximized document. In applications that support Visual Basic for Applications, like Excel and MSProject, the title only needs to include the application name part of the title bar, but if you do include the hyphen part, it must match exactly. The title argument is not case sensitive.

If there is more than one window that matches the specified title, then the most recently used instance (the highest one in the Windows Task List) is activated. Windows that are not on the Windows Task List can't be activated.

AppActivate cannot activate an application that is running invisibly - i.e. one that is running but doesn't show in the Windows Task List.

wait

This argument is only available in applications that support Visual Basic for Applications. VB3 doesn't use this argument. Set this argument to True if the source macro trying to execute the AppActivate command must wait until the source application has focus before it is allowed to activate the specified target. The default is False.

 

Example

Suppose there are three instances of NotePad listed in the Windows Task List in the order shown:

NotePad - Test2.txt

NotePad - Test1.txt

NotePad - (Untitled)

The table below shows what would result from various uses of AppActivate:

Command

Result

AppActivate "NotePad" Activates the first one in the Windows Task List.
AppActivate "NotePad - wow" Error
AppActivate "NotePad - Test1.txt" Activates the specified instance only.

Example

Suppose the title bar in MSProject says: Microsoft Project - P1.MPP

Then an Excel macro could switch focus to MSProject with any of the following commands:

AppActivate "Microsoft Project"

AppActivate "Microsoft Project"

AppActivate "Microsoft Project - P1.MPP"

A VB3 procedure could only use the last statement above.

If a source application establishes an OLE conversation with MSProject, then it can use AppActivate with the Caption property of the target application. The Caption property represents the exact title bar text. The following example could be a VB3 procedure or an Excel macro that activates MSProject regardless of what's on the title bar:

Sub Sub1()

Dim x As Object

Set x = GetObject(,"MSProject.Application")

AppActivate x.Caption

End Sub

Maximizing and Minimizing Another Application

Depending on the applications, a source application might be able to maximize, minimize, resize, or move a target application. You can manipulate the MSProject window using the MSProject methods AppMaximize, AppMinimize, AppRestore, AppMove, and AppSize (there are similar methods to manipulate the document windows). The above methods are specific to MSProject. Many applications have a WindowState property that can be used to maximize, minimize, or restore their application window. Some commands, like Shell, that are used to start applications include options to control how the target application window comes up - Shell is covered later in this lesson.

Example

The following Excel macro assumes that MSProject is already running. It makes MSProject visible (in case it was running invisibly), switches to MSProject and maximizes it.

Sub Sub5()

Dim x As Object

Set x = GetObject(, "MSProject.Application")

x.Visible = True

x.AppMaximize

End Sub

Example

The following MSProject macro assumes that an instance of Excel is already running. It makes that instance visible and maximizes it.

Note that the predefined MSProject constant pjMaximized has the same value as the predefined Excel constant xlMaximized. The MSProject macro used pjMaximized instead of xlMaximized because the Excel constants are not recognized in MSProject macros automatically without establishing a reference to the Excel 5.0 Object Library. This is covered in detail in lesson 3. Of course, you can use the actual value instead of the constant.

Sub b2()

Dim x As Object

Set x = GetObject(, "Excel.Application")

x.Visible = True

x.WindowState = pjMaximized

End Sub

Starting Other Applications

There are a variety of ways a macro in a source application can start a target application. Many applications support a command like Shell. If both the source and target applications support OLE Automation, then the source can use CreateObject or GetObject to start the target application. MSProject also has the AppExecute method which can switch to, or start up, a target application.

See Online Help for a complete discussion of related commands.

Shell pathname [ , windowstyle ]

Starts the specified application with the optional specified window style. To insure that the target application is completely started before the source macro continues, follow the Shell command with the DoEvents command if it has one.

pathname

Name of executable file including optional path. It can include optional command line arguments. It can not be the name of a document (although Online Help says it can).

windowstyle

Pass one of the following optional values to control the state of the target window when it starts (default is 2).

1, 5, 9 Normal with focus.

2 Minimized with focus.

3 Maximized with focus.

4,8 Normal without focus.

6,7 Minimized without focus.

As soon as the target application responds that it has finished the initial part of its startup process, the calling macro will proceed to the next line of code after the Shell command. It will not wait for the other application to close before continuing. Shell can be used as a function. It returns an id number (called a module handle) that identifies the instance of the executable that it started. You can pass this id to some API procedures to get information about that instance, including whether it's still running. If you don't want your macro to continue until the target executable has quit, the GetModuleUsage API function is useful. API calls are covered in lesson 8. The GetModuleUsage function is used in an example later in this lesson. If you don't want to use the value returned by Shell, then don't use ( ) around the arguments.

If the target application supports multiple instances (like Excel) then Shell always starts a new instance. For applications like MSProject that support only a single instance, Shell activates the existing instance.

When Shell looks for the specified executable, if a directory is supplied with the filename, it only looks there. If no directory is specified, it looks at the following, in the order given, until it finds the executable or gives an error: current directory, windows directory, system directory, and path statement. It doesn't look in Win.ini or Reg.dat (OLE registry information).

If you include command line arguments (like a document filename) with the executable name, Shell will wait only until the target application releases control back to the operating system; it doesn't necessarily wait for the document to open.

Shell is not aware of "working directories". If it's important, try using the Chdrive and Chdir commands to switch to the working directory before using the Shell command - that way the target application might find startup files it needs (for example MSProject's Global.mpt).

Example

Assume MSProject is not running, that winproj.exe is in c:\winproj and Global.mpt is in c:\winproj\workdir and that the current directory is c:\stuff. Then this Excel macro will start MSProject maximized with focus, but will create a new default Global.mpt without warning messages.

Sub StartMSProject()

Shell "c:\winproj\winproj.exe", 3

End Sub

With the same assumptions as above, the following Excel macro will start MSProject with the Global.mpt from the working directory:

Sub StartMSProject()

ChDrive "c"

ChDir "c:\winproj\workdir"

Shell "c:\winproj\winproj.exe", 3

End Sub

Example

Assume Excel is not running. This MSProject macro starts Excel maximized with focus and tells it to load the specified workbook. As soon as Excel finishes its startup screen, it lets the MSProject macro continue as it loads test.xls in the background.

Sub Sub1()

Shell "c:\Excel\Excel.exe c:\Excel\data\test.xls", 3

AppActivate "Microsoft Project"

End Sub

Note that if you replace the above Shell statement with

Shell "c:\Excel\data\test.xls", 3

it gives an error, although Online Help says it should work.

AppExecute window, command, minimize, activate

MSProject method only. It can be used to activate or start a target application or both. You must provide the window or command argument or both.

window

Set to the title bar text of the window to be activated, including the hyphen and document name if there is a maximized document. It's not case sensitive.

command

The command used to start the target application. Similar to the pathname argument in the Shell command.

minimize

Set this to True to minimize the target window. Default is False.

activate

Set this to True if you want to give focus to the target application. Default is True.

AppExecute looks at the window argument first if provided. If it finds the window, then it ignores the command argument. If the window argument is not given or has a bad value, then it looks to the command argument. In the case where it has to depend on the command argument, it may look for an exiting instance first or it may not, depending on the target application. For example, it always starts a new copy of NotePad. In Windows 3.1 it uses an existing instance of Excel, but in Windows 95 it always starts a new instance.

In cases where AppExecute is switching to an existing instance, the minimize and activate arguments are ignored, and AppExecute switches to the most recently used instance of the target application (the highest one in the Windows Task List). It cannot be used to activate an application that is not in the Windows Task List.

If AppExecute does have to start a new instance, it looks at the following to locate the executable: If a pathname is supplied in the command argument, it looks no further, otherwise it checks Reg.dat, and then in the current directory, windows directory, system directory, and the path statement. This is different from Shell which always starts a new instance, and never checks Reg.dat.

 

You can specify a document file along with the executable file in the command argument, but then Reg.dat is not checked. You cannot specify just a document file for the command argument.

Example

Suppose there are two copies of Excel running and two copies of NotePad running, and they are in the following order in the Windows Task List:

NotePad - Test2.txt

Microsoft Excel - Book1

NotePad - Test1.txt

Microsoft Excel - Book2

The table below shows the result of various commands, each starting with the above assumptions.

Command Result
AppExecute window:="Notepad" Error
AppExecute window:="Notepad - Test1.txt" Activates that one
AppExecute command:="Notepad" Starts a new copy of NotePad
AppExecute command:="Notepad - Test1.txt" Error
AppExecute command:="Excel" Activates the first Excel in the Windows Task List
AppExecute window:="Excel - Book2" Activates that one

Example

Note: The following command should start Excel minimized with focus, but gives an error if Excel is not already running. Get rid of the Minimize argument or set it to False, and it works OK.

AppExecute Command:="c:\Excel\Excel.exe", Minimize:=True

Example

Assuming Excel is not running and that Excel.exe is in c:\Excel and that Excel is properly registered, then any of the following alone should start Excel and give it focus.

AppExecute command:="c:\Excel\Excel.exe"

AppExecute command:="Excel.exe"

AppExecute command:="Excel"

AppExecute window:="ha ha", command:="Excel"

Example

Assume the same as the above, but also that c:\Excel is not in the Path statement, and that Test.xls is in c:\Excel. Then

AppExecute command:="c:\Excel\Excel.exe test.xls"

works, but

AppExecute command:="Excel.exe test.xls"

fails because it can't find Excel.exe and won't check the registry.

AppExecute command:="c:\Excel\test.xls"

fails too, because it doesn't do associations.

Example

Assume Excel is already running, and that the title bar is "Excel - Book1.xls". Then the following both work:

AppExecute Window:="Excel - Book1.xls"

AppExecute Window:="Excel - Book1.xls", Command:="ha ha"

Closing Applications

There are a couple of ways that a macro can close an application: Using OLE Automation to apply the Quit method of the target application (if it has one) or DDE to send the Quit command of the target application (if it has one), or, in the worse case, activating the target application and using a SendKeys command to choose File Exit or to send the Alt-F4 key combination. SendKeys, OLE Automation, and DDE are covered in later lessons.

Applications that are started as a result of an OLE reference may close automatically when the OLE reference is destroyed. Reference-dependence is covered in detail in Lesson 3.

When a macro tells a target application to quit, it should take into account the possibility that the target application might display "alerts", warning messages, or error messages. An alert is usually a message that offers you a choice of actions. For example, when told to quit, MSProject might give the message "Save changes to 'Project1'?", or "Some other application is using Microsoft Project. Do you want to exit Microsoft Project?". The conservative approach to handling potential messages is to activate the target application before telling it to close. Some applications have commands that turn off "alerts". The default response for an alert is automatically chosen without showing the message. Both MSProject and Excel have the DisplayAlerts property. MSProject also has the Alerts method. The following lines have the same effect in MSProject:

Alerts False

DisplayAlerts = False

With alerts turned off, MSProject automatically saves changes to projects that have been saved at least once in the past, and automatically brings up the Save As dialog for new projects that have changed.

MSProject has its DisplayAlerts property equal to True by default. If a macro wants to be sure MSProject will display alerts, it should put DisplayAlerts equal to True, just in case some other macro had previously put DisplayAlerts equal to False.

Try This

The following Excel macro saves any projects in MSProject that need to be saved, without giving alert messages. Then the macro closes MSProject.

1. Create two new projects in MSProject. Save one but not the other, then enter a task in each one.

2. Enter and run the following Excel macro. When it brings up the Save As dialog, see what happens if you choose cancel.

Sub Sub1()

Dim x As Object

Set x = GetObject(,"MSProject.Application")

x.DisplayAlerts = False

AppActivate "Microsoft Project"

x.Quit

End Sub

3. Change the macro so it assigns True to DisplayAlerts instead of False. Create two more projects as in step (1) and run the macro again.

Note: The DisplayAlerts line could have been replaced by: x.Alerts False

MSProject was activated before closing it so any unanticipated error messages could be seen.

Example

Suppose several copies of NotePad are running and one has the title bar "NotePad - Test1.txt". The following MSProject macro closes that specific instance of NotePad:

Sub Sub1()

AppActivate "NotePad - Test1.txt"

SendKeys "%{F4}", True

End Sub

If you leave off the " - Test1.txt" in the AppActivate statement, it would close one of the instances of NotePad, but maybe not the one you wanted.

How To Tell If An Application Is Running

Here's a couple of ways to tell if another application is currently running.

Try to activate another application and trap the error if it fails. If it fails, you know the application's not in the Windows Task List, although it might be running "invisibly".

Try to establish an OLE or DDE conversation with an application and trap the error if it fails (although it might fail because the other application is running but not responding). This method can tell if an application is running even if it's not in the Windows Task List. Using GetObject when the target application is displaying a message might cause the calling macro to lock up. OLE Automation and DDE are covered in detail in Lessons 3 and 4.

API calls: These are covered in detail in Lesson 8. The FindWindow function is perhaps the cleanest way to tell if an application is running (in the Windows Task List or not). To use it, you must know the classname of the application. For example, the classname of MSProject 4.0 is "JWinproj-WhimperMainClass", and the classname of Excel 5.0 is "XLMAIN". The GetModuleUsage function is often used with the Shell command to test if the application instance started with Shell is still running.

Try This

The following MSProject macro tells you whether NotePad is in the Windows Task List or not.

1. Make sure NotePad is not running.

2. Enter and run the following MSProject macro.



Sub IsNotePadRunning()

Dim MyErr As Integer

On Error Resume Next

AppActivate "NotePad"

MyErr = Err

On Error GoTo 0

If MyErr > 0 Then

MsgBox "NotePad is not running."

Else

AppActivate "Microsoft Project"

MsgBox "NotePad is running"

End If

End Sub

3. Start NotePad and run the above macro again.

 

Try This

The following Excel macro tells you whether MSProject is responding or not to GetObject.

1. Make sure MSProject is not running.

2. Enter and run the following Excel macro.

Sub IsMSProjectRunning()

Dim x As Object, MyErr As Integer

On Error Resume Next

Set x = GetObject(, "MSProject.Application")

MyErr = Err

On Error GoTo 0

If MyErr > 0 Then

MsgBox "MSProject is not responding."

Else

MsgBox "MSProject is responding"

End If

End Sub

3. Start MSProject. Don't have any dialogs or messages open in MSProject. Run the above Excel macro again.

4. Make sure you don't have anything important open in any application. Open the Tools Macros dialog in MSProject, switch back to Excel, and run the above macro again.

 

Try This

The following Excel macro tells you whether MSProject is running or not. It uses the FindWindow API call with the classname of MSProject. The GetClassname API function in Lesson 8 can be used to find classnames.

1. Make sure MSProject is not running.

2. Enter and run the following Excel macro.

'PLACE THE DECLARE LINE IN THE DECLARATION AREA OF AN EXCEL MODULE

Declare Function FindWindow Lib "USER" _

(ByVal lpClassName As Any, ByVal lpWindowName As Any) As Integer

Sub IsMSProjectRunning()

If FindWindow("JWinproj-WhimperMainClass", 0&) = 0 Then

MsgBox "MSProject is not running"

Else

MsgBox "MSProject is running"

End If

End Sub

3. Start MSProject and run the above Excel macro again.

 

Try This

The following Excel macro starts MSProject and establishes an OLE conversation. Then it waits in a DoEvents loop until it is no longer able to use the reference to MSProject to read the MSProject caption.

1. Make sure MSProject is not running.

2. Enter and run the following Excel macro. It should start and activate MSProject. Adjust the path to MSProject if necessary.

Sub Sub5()

Dim x As Object, s As String

Shell "c:\winproj\winproj.exe", 3

On Error Resume Next

Set x = GetObject(, "MSProject.Application")

Do

DoEvents

s = x.Caption

Loop Until Err > 0

MsgBox "MSProject is busy or not running."

End Sub

3. Exit MSProject. The MsgBox line in the above macro should execute.

 

Try This

The following MSProject macro uses the Shell statement to start a new instance of Excel and waits in a DoEvents loop until that instance of Excel quits. The value returned by the Shell statement is stored in the variable moduleHandle which identifies the instance of Excel. The API function GetModuleUsage is passed the value of moduleHandle and returns a nonzero result as long as the instance of Excel is still running.

1. Make sure Excel is not running.

2. Enter and run the following MSProject macro. It should start and activate Excel.

'PUT THIS IN THE DECLARATION AREA:

Declare Function GetModuleUsage _

Lib "KERNEL" (ByVal hModule As Integer) As Integer

Sub a1()

Dim moduleHandle As Integer

moduleHandle = Shell("c:\Excel\Excel.exe", 3)

Do

DoEvents

Loop Until GetModuleUsage(moduleHandle) = 0

MsgBox "The instance of Excel is no longer running."

End Sub

3. Exit MSProject. The MsgBox line in the above macro should execute.

Lesson 1 Exercises

Assume in these exercises that there are no "invisible" applications, i.e. that any applications running are listed in the Windows Task List. Also assume that there are no "busy" applications. Try to do these without API calls. They all can be done using AppActivate, SendKeys, and On Error Resume Next.

  1. Write an Excel macro that tries to activate (not start) MSProject. If it fails, then the macro gives the following message:


  2. Make sure Microsoft Project is running before using this macro.

    The message box should just have an OK button. Then the macro ends.

  3. Write an MSProject macro that tries to activate (not start) Excel. If it fails, then the macro gives the following message:


  4. Excel is not running. Do you want to start it?

    The message box should have a Yes and No button. If the user selects Yes, then the macro starts a new instance of Excel, and ends. If the user selects No, then the macro just ends.

  5. Write an MSProject macro that tests if Excel is running. If Excel is not running, then the macro starts Excel and ends. If Excel is running, then the macro activates MSProject and displays the following message:


  6. Excel is already running. You can switch to it,

    or start a new instance.

    The message box should have 3 buttons labeled: Current, New, and Cancel. If the user chooses the Current button then the macro activates Excel and then ends. If the user chooses the New button, then the macro starts a new instance of Excel, makes it active, and ends. If the user chooses Cancel then the macro just ends.

    Use the "Message" method so you can change the Yes button caption to Current, and the No button caption to New. For help, look up "Message" in the MSProject Online Help, in the VB section.

  7. Write an MSProject macro that closes one instance of Excel. Make sure that any Excel alerts like "Save changes in 'Book1'?" are shown before it closes. Test the macro by entering some data in a new Excel workbook, and then switching to MSProject and running the macro.