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. |
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.
Make sure Microsoft Project is running before using this macro.
The message box should just have an OK button. Then the macro ends.
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.
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.