Lesson Objectives
Upon completion of this lesson, the participant will be able to:
Some Topics to be introduced in this lesson include:
OLE Automation
OLE Automation is the process by which a source application uses object variables or references to control a target application, or documents or other objects supported by the target application. You start by setting an object variable to the target application or some object that the target application supports, using CreateObject, GetObject, or you establish a reference to the target application's Application Object Library (if it has one). Then the object variable in the source macro can use the methods and properties of the corresponding object in the target application.
An application can also use CreateObject and GetObject to refer to itself or one of its subordinate objects. For example the following is both a legal Excel macro and a legal MSProject macro:
Sub Macro1( )
Dim s As Object
Set s = CreateObject("Excel.Sheet")
s.Cells(1, 3).Value = "abc"
s.SaveAs "d:\excel5\class\create2.xls"
End Sub
Note that an application cannot initiate a DDE conversation with itself - see the section on DDE. For example, the following statement is illegal in an MSProject macro:
DDEInitiate "Winproj", "System"
OLE Automation Support
Here's the degree to which Excel, MSProject, Word, and VB3 support OLE Automation:
Excel and MSProject
Excel 5.0 and MSProject 4.0 macros can use all three techniques: CreateObject, GetObject, or establishing a reference to another application's Application Object Library.
Word
Word 6.0 macros cannot use OLE Automation to control other applications, but other applications can use OLE Automation to control it. When other applications use an object variable to control Word, they cannot use the Word named arguments. Word commands can be used by listing the values of arguments without argument names, but you can't skip arguments with consecutive commas (or whatever the list separator is). For example, here's the syntax for the Word Basic command FileOpen, with the first three arguments:
FileOpen .Name = text [,.ConfirmConversions = number] [,.ReadOnly = number]
Both of the following Word lines open the specified file as read only:
FileOpen .Name = "c:\word6\t1.doc", .ReadOnly = 1
FileOpen "c:\word6\test1.doc", 0, 1
The second line above has a dummy 0 for the value of the ConfirmConversions argument - you can't skip it when you don't use the argument names.
The MSProject macro below tells Word Basic to do the same thing as the above. Word does not have to open when the macro runs. If Word is not open before the MSProject macro runs, then Word will automatically close when the MSProject macro ends, because w is a local variable.
Sub Sub1()
Dim w As Object
Set w = CreateObject("Word.Basic")
w.FileOpen "c:\word6\t1.doc", 0, 1
End Sub
DDE actually shines here - you can use the argument names if you use DDEExecute. Word must be open before the MSProject macro below runs.
Sub Sub1()
DDEInitiate "WinWord", "system"
DDEExecute "[FileOpen .Name = ""c:\word6\t1.doc"", .ReadOnly = 1]"
DDETerminate
End Sub
One last warning about using Word Basic commands without argument names - there are a few problems with some commands. For example, the EditFind command requires a bogus dummy string argument between its first and second argument if you don't use argument names:
EditFind .Find = "wow", .Direction = 0 'OK
EditFind "wow", 0 'Doesn't work, but should
EditFind "wow", " ", 0 'Does work, but shouldn't
Visual Basic
Visual Basic 3.0 procedures can use OLE Automation to control other applications, but another application cannot use OLE Automation to control VB3 objects. For example an MSProject macro can't set an object variable to manipulate a text box in a VB3 form. VB3 has some other limitations:
VB3 cannot make references to Application Object Libraries.
VB3 procedures can't use some of the block structures available in Visual Basic for Applications, such as the "For Each" loop and the "With" block.
VB3 procedures cannot used named argument, but must instead list the argument values in order. MSProject behaves inconsistently regarding skipping arguments by using consecutive commas (assuming the list separator is a comma). Skipping arguments by using consecutive commas causes an "Argument value not valid" error for some methods/functions in MSProject macros. Even in cases where it's OK in an MSProject macro, the same statement may cause the error when run from a VB3 procedure.
The following table of syntax examples assumes the object variable x refers to MSProject:
Statement | MSProject |
VB3 |
x.FileOpen Name:="P1.mpp" | Yes |
|
x.FileOpen "P1.mpp" | Yes |
Yes |
x.SelectCell 3, , False | Yes |
|
x.SelectCell 3, 4, False | Yes |
Yes |
x.FilePageSetupFooter "task
sheet", _ "left footer", , "right footer" |
||
x.FilePageSetupFooter "task
sheet", _ "left footer", "", "right footer" |
Yes |
Yes |
Some Terminology
Here's some terminology that will be used in the OLE Automation examples. These terms will become clearer in the examples, and are discussed in greater detail in the "Invisible Objects and Object Lifetime" topic.
Invisible Application: An application that is running but doesn't show in the Windows Task List. An application can be made visible by setting its Visible property to True if it has one. In this context, "visible" means "in the Windows Task List", not necessarily physically visible.
Invisible Document: A document in an invisible application, or a document in a visible application, but the document can't be seen and doesn't appear in the list of open windows. An invisible document can be "more hidden" than a "hidden" document. As you'll see later, an MSProject invisible project might not show up in the Window Unhide list, but will show in the Window New Window list.
Reference-Dependent Object: An open object that exists only as long as it or one of its subordinate objects is being referenced.
As you'll see later, some objects can be toggled between invisible and visible. Also, some actions can cause a reference-dependent object to become reference-independent.
Here's some things that can cause an object variable to stop pointing to an object:
The object variable was set to some other object
The object variable was set to Nothing, for example Set x = Nothing
The object variable was a local variable and the macro has ended
The END macro command was executed (not by choosing the menu command Run End)
The menu command Run, Reset was used
Note: The last two items apply to clearing the value of any variable.
As you experiment with CreateObject and GetObject, you may end up running invisible copies of applications. The following macros can be used to make MSProject and Excel visible. The way GetObject is used in these macros requires that MSProject and Excel already be running (visible or not). The On Error Resume Next statements prevent error messages if they are not running. The GetObject function is discussed in detail later in this lesson. There are also API calls that can be used to make applications visible - see Lesson 8.
Try This (A) The Excel macro below makes MSProject visible and active if it is running (and not busy). 1. Get into Excel and create an new module called OLE (From the Insert menu, choose Macro, and then Module). 2. Enter the following macro: Sub ShowMSProject() Dim oMSP As Object On Error Resume Next Set oMSP = GetObject(, "MSProject.Application") If Err > 0 Then MsgBox "MSProject is busy or not running." Else oMSP.Visible = True AppActivate "Microsoft Project" End If End Sub 3. Save the workbook. 4. Start MSProject, switch to Excel and run the ShowMSProject macro. MSProject should become active. As you'll see later, this macro can make MSProject active even if it were originally invisible. (B) The MSProject macro below makes the youngest instance of Excel visible and active if it is already running (and not busy). 1. Get into MSProject and create an new module called OLE. 2. Enter the following macro: Sub ShowExcel() Dim oXL As Object On Error Resume Next Set oXL = GetObject(, "Excel.Application") If Err > 0 Then MsgBox "Excel is busy or not running." Else oXL.Visible = True AppActivate "Microsoft Excel" End If End Sub 3. Start a new instance of Excel, switch to MSProject and run the ShowExcel macro. The instance of Excel should become active. As you'll see later, this macro can make the youngest instance of Excel active even if it were originally invisible. |
CreateObject (class)
Returns a reference to an object determined by the class argument. Depending on class, the reference may be to an existing object or to a newly created object. The object reference returned by CreateObject is usually assigned to an object variable.
Class
A string of the form "appName.objectType". Here are some of the values available for MSProject, Excel, and Word:
Note that Word doesn't have a Word.Application object. However, the Word.Basic object is like an application object. If Word is started as a result of CreateObject or GetObject then when the object variable ceases to exist, Word automatically closes all documents and the Word application without warnings.
Many of the following examples use x as the object variable, but any legal object variable name could be used.
Using CreateObject With MSProject Objects
Set x = CreateObject("MSProject.Application")
Refers to an existing instance if MSProject is running, otherwise it starts an invisible reference-dependent instance with no open projects. Does not activate MSProject. The x refers to MSProject.Application.
Note that a reference-dependent instance of MSProject becomes reference-independent if you open any projects with methods like FileNew or FileOpen.
Global.mpt Concerns: Project looks in the current directory and in the winproj.exe directory for Global.mpt, not in the working directory. If can't find, it creates one in the executable directory without warning.
Try This (A) The Excel macro below starts MSProject, and makes it visible: 1. Make sure MSProject is not running. 2. Enter the following macro in Excel and run it. Dim x As Object 'In the declaration area. Sub Sub1a() Set x = CreateObject("MSProject.Application") x.Visible = True End Sub 3. Switch to MSProject. You should see no open projects. 4. Switch back to the Excel macro and from the Run menu, choose Reset. 5. Check the Windows Task List. MSProject should not be listed. Is it running invisibly or just not running at all? Did the macro start a reference-dependent or reference-independent instance of MSProject. (B) The Excel macro below starts MSProject invisibly, creates a new project, and adds a new task to it. 1. Make sure MSProject is not running. 2. Enter the following macro in Excel and run it. Sub Sub1b() Dim x As Object Set x = CreateObject("MSProject.Application") x.FileNew x.ActiveProject.Tasks.Add Name:="wow" End Sub 3. Check the Windows Task List. Microsoft Project should not be in the list. 4. Start MSProject manually in Program Manager. The new project and task created by the macro should be there. Is this instance of MSProject reference-dependent? 5. Close MSProject and don't save changes to the new project. 6. Change the macro so that x is declared as a module-level variable, i.e. move the Dim statement to the declaration area of the Excel module. Also, add the line x.Visible=True before the line x.FileNew. 7. Run the macro again. 8. Try to close MSProject - you should get a warning that MSProject is being used by another application. Cancel the message. Why didn't this message come up the first time you ran the macro? 9. Switch back to the Excel macro and from the Run menu, choose Reset. 10. Switch to MSProject and close it. Why no message this time? |
Set x = CreateObject("MSProject.Project")
Starts an invisible reference-dependent instance of MSProject, if it's not running. It then creates a new invisible project. The x refers to the new project, and x.Parent refers to MSProject.Application. The new project is reference-dependent, unless the command executed as an MSProject command.
If MSProject is running visibly, then the name of the invisible project isn't listed in the Window menu's open project list or in the Window Unhide list, but is listed in the Window New Window list. You can use Window New Window to make the invisible project become visible.
Try This The MSProject macro below creates two new invisible projects and displays the names of all the "open" projects. 1. Enter the following macro in MSProject and run it. Sub Sub2a() Dim p As Object, p1 As Object, p2 As Object Set p1 = CreateObject("MSProject.Project") Set p2 = CreateObject("MSProject.Project") For Each p In Projects MsgBox p.Name Next End Sub 2. After the macro ends, check the MSProject Window menu, and you can see that the two new projects are not listed as open or hidden. Use Window New Window to make the projects visible, and then close them. Were these two new projects reference-dependent? 3. Paste the above macro into an Excel module. Replace the word "Projects" in the "For Each ..." line to "p1.Parent.Projects" (without the quotes). Note that p1.Parent refers to MSProject. 4. Run the macro. Switch to MSProject. Verify that the two new projects are not in the Window New Window list. Do you think the two projects are invisible or just not open at all? Were the two created projects reference-dependent? |
Using CreateObject With Excel Objects
Set x = CreateObject("Excel.Application")
Always starts a new invisible reference-independent instance of Excel. The x refers to the Excel.Application object of the new instance.
Set x = CreateObject("Excel.Sheet")
Starts an invisible reference-dependent instance of Excel if it's not running, otherwise it uses the *youngest instance. It creates a new worksheet "Sheet1" in a new reference-dependent workbook called "Object" (or "Object 2" etc.). The x refers to Sheet1, x.Parent to the workbook, and x.Parent.Parent to Excel.Application. If Excel is visible, then the new workbook is visible, and Excel is reference-independent.
*If there are existing instances, youngest means the one that was started last.
Try This The MSProject macro below creates two new workbooks, and puts the time in cell A1 of Sheet1 of each workbook. 1. Make sure Excel is not running. 2. Enter the following macro in MSProject and run it. Dim s1 As Object, s2 As Object 'In the declarations area. Sub Macro1() Set s1 = CreateObject("Excel.Sheet") Set s2 = CreateObject("Excel.Sheet") s1.Cells(1, 1).Value = Format(Now, "mm:ss") s2.Cells(1, 1).Value = Format(Now, "mm:ss") s1.Parent.Parent.Visible = True End Sub 3. Check the names of the workbooks and the times in cell Sheet1!A1 of each workbook. Close the workbooks "Object" and "Object 2". What does s1.Parent.Parent.Visible refer to? 4. Manually use File New to create another workbook in Excel and type "hey" in Sheet1!A1. 5. Leave Excel running. Switch back to MSProject and run the macro again. Note that it did not activate the Excel window this time - setting the Visible property to True only activates Excel if it is not in the Windows Task List. 6. Switch to Excel. Check the workbook names again. Did the macro create a new instance of Excel the second time it was run? 7. Leave Excel running. Switch back to MSProject and from the Run menu choose Reset. Switch to Excel. Are the workbooks created by the macro still there? Did the macro create reference-dependent workbooks? If s1 and s2 had been declared locally, would you have seen the workbooks created by the macro after the macro ended? |
Set x = CreateObject("Excel.Chart")
Starts an invisible reference-dependent instance of Excel if it's not running, otherwise it uses the youngest instance. It creates a new worksheet "Sheet1" and chart sheet "Chart1" in a new reference-dependent workbook called "Object (or "Object 2" etc.). Chart1 is based on Sheet1 which Excel populates with sample data. The x refers to Chart1, x.Parent to the workbook, and x.Parent.Parent to Excel.Application. If Excel is visible, then the new workbook is visible, and Excel is reference-independent.
Question: How can you use x to refer to Sheet1?
Try This The MSProject macro below creates a new workbook with one worksheet and one chart sheet. 1. Enter the following macro in MSProject and run it. Dim oChart As Object 'In the declarations area. Sub Macro1() Set oChart = CreateObject("Excel.Chart") oChart.Parent.Parent.Visible = True End Sub 2. Switch to Excel. Where is the chart getting its data from? How can you find out whether the workbook created is reference-dependent? |
Using CreateObject With Word Objects
Set x = CreateObject("Word.Basic")
If Word is not running, then a visible reference-dependent instance of Word is started with focus and with no open documents, otherwise x references the youngest existing instance of Word without activating it. The x refers to Word.Basic.
Try This The MSProject macro below creates a new Word document, enters some text, and saves the document. 1. Make sure Word is not running. 2. Enter the following macro in MSProject and run it. Sub w1() Dim w as object Set w = CreateObject("Word.Basic") w.FileNew w.Insert "hello" w.FileSaveAs "c:\temp.doc" End Sub 3. Is Word still running after the macro ends? Was the instance of Word created reference-dependent? If w had been declared as a module-level variable, would Word remain open after the macro ends? Open c:\temp.doc to see if it was created and saved correctly. Close temp.doc. Create a new doc and enter some text. 4. Leave Word running. Switch to MSProject and change "hello" to "wow" in the macro and run it again. Is Word still running? Did it overwrite c:\temp.doc? Any overwrite warning? Did it use the existing instance of Word or start a new instance? |
GetObject ([pathname][,class])
Returns a reference to an object determined by the arguments. Depending on the arguments, the reference may be to an existing object or to a newly created object. The object reference returned by CreateObject is usually assigned to an object variable.
pathname
The path and file name of a document file.
class
Has the same meaning as in CreateObject.
You must provide one or the other or both of the arguments.
You don't need to use the class argument if you give a document name. If you provide a document pathname but not a class, then it finds the correct application if the system associations are correctly setup, and then uses the default class for the application.
If you use an empty string for pathname then GetObject("", class) behaves like CreateObject(class).
If you leave out pathname, then GetObject(, class) usually requires class to be an application object and the application to be running.
If you provide both a document pathname and a class, then the specified document must support that class. For example, the first statement below is legal and the second is not:
Set x = GetObject("c:\winproj\p1.mpp", "MSProject.Project") 'OK
Set x = GetObject("c:\winproj\p1.mpp", "MSProject.Application") 'Not OK
Using GetObject With MSProject Objects
Set x = GetObject(, "MSProject.Application")
MSProject must be running, otherwise an OLE Automation error occurs. The x refers to MSProject Application.
Set x = GetObject("", "MSProject.Application")
Behaves like: Set x = CreateObject("MSProject.Application").
Set x = GetObject("", "MSProject.Project")
Behaves like: Set x = CreateObject("MSProject.Project")
Set x = GetObject("c:\wprj4dat\p1.mpp")
Set x = GetObject("c:\wprj4dat\p1.mpp", "MSProject.Project")
Each of these starts an invisible reference-dependent instance of MSProject, if it's not running. If the specified MPP file is not open, then it is opened invisibly, and is reference-dependent unless the command was executed as an MSProject command. The x refers to the project, and x.Parent refers to MSProject.Application.
These are ILLEGAL :
Set x = GetObject(, "MSProject.Project")
Set x = GetObject("c:\wprj4dat\p1.mpp", "MSProject.Application")
Using GetObject With Excel Objects
Set x = GetObject(,"Excel.Application")
Excel must be running, otherwise an OLE Automation error occurs. The x refers to
Excel.Application for the youngest instance of Excel.
Set x = GetObject("","Excel.Application")
Behaves like: Set x = CreateObject("Excel.Application").
Set x = GetObject("","Excel.Sheet")
Behaves like: Set x = CreateObject("Excel.Sheet")
Set x = GetObject("c:\Excel\test.xls")
Set x = GetObject("c:\Excel\test.xls", "Excel.Sheet")
Each of these starts an invisible reference-independent instance of Excel, if it's not running, otherwise it uses the youngest existing instance. If the specified XLS file is not open, then it is opened as a hidden workbook, and is reference-dependent unless the command was executed as an Excel command. The x refers to the activesheet in the specified file.
Set s = GetObject("","Excel.Chart")
Behaves like: Set s = CreateObject("Excel.Chart")
Set s = GetObject("c:\Excel\test.xls", "Excel.Chart")
Behaves like: GetObject("c:\Excel\test.xls") except that the workbook must contain at least one chart sheet.
These are ILLEGAL :
Set s = GetObject(,"Excel.Sheet")
Set s = GetObject("c:\Excel\test.xls", "Excel.Application")
Using GetObject With Word Objects
Set w = GetObject("", "Word.Basic")
Behaves like w = CreateObject("Word.Basic")
Set d = GetObject("d:\word6\test.doc")
Doesn't give an error message, but you can't use it for anything.
These are ILLEGAL:
Set w = GetObject(, "Word.Basic")
Set w = GetObject("d:\word6\test.doc", "Word.Basic")
CreateObject and GetObject - Review
There are many exotic ways to use CreateObject and GetObject, but only a few variations are commonly used. First of all, the application you want to control is usually already running visibly, and there usually is just one instance. Also, you usually set the object variable to refer to the application, not to a subordinate object in the application, like a sheet or chart. To work with other subordinate objects in the application, you work your way down the object ladder.
The table on the next page summarizes the syntax variations of CreateObject and GetObject. The most commonly used forms are highlighted.
Set x = | Result |
CreateObject("MSProject.Application") GetObject("","MSProject.Application") |
Refers to an existing instance if MSProject is running, otherwise it starts an invisible reference-dependent instance with no projects open. The x refers to MSProject.Application. |
CreateObject("MSProject.Project") GetObject("","MSProject.Project") |
Starts an invisible reference-dependent instance of MSProject, if it's not running. It then creates a new invisible project. The x refers to the new project, and x.Parent refers to MSProject.Application. The new project is reference-dependent, unless the command executed as an MSProject command. |
CreateObject("Excel.Application") GetObject("","Excel.Application") |
Always starts a new invisible reference-independent instance of Excel. The x refers to the Excel.Application object of the new instance. |
CreateObject("Excel.Sheet") GetObject("","Excel.Sheet") |
Starts an invisible reference-dependent instance of Excel if it's not running, otherwise it uses the youngest instance. It creates a new worksheet "Sheet1" in a new reference-dependent workbook called "Object" (or "Object 2" etc.). The x refers to Sheet1, x.Parent to the workbook, and x.Parent.Parent to Excel.Application. If Excel is visible, then the new workbook is visible and Excel is reference-independent. |
CreateObject("Excel.Chart") GetObject("","Excel.Chart") |
Starts an invisible reference-dependent instance of Excel if it's not running, otherwise it uses the youngest instance. It creates a new worksheet "Sheet1" and chart sheet "Chart1" in a new reference-dependent workbook called "Object (or "Object 2" etc.). Chart1 is based on Sheet1 which Excel populates with sample data. The x refers to Chart1, x.Parent to the workbook, and x.Parent.Parent to Excel.Application. If Excel is visible, then the new workbook is visible and Excel is reference-independent. |
CreateObject("Word.Basic") GetObject("", "Word.Basic") |
If Word is not running, then a visible reference-dependent instance of Word is started with focus and with no open documents, otherwise it activates the youngest existing instance. The x refers to Word.Basic. |
GetObject(,"MSProject.Application") | MSProject must be running, otherwise an OLE Automation error occurs. The x refers to MSProject Application. |
GetObject("c:\data\p1.mpp") GetObject("c:\data\p1.mpp", _ MSProject.Project") |
Starts an invisible reference-dependent instance of MSProject, if it's not running. If the specified MPP file is not open, then it is opened invisibly, and is reference-dependent unless the command was executed as an MSProject command. The x refers to the project, and x.Parent refers to MSProject.Application. |
GetObject(,"Excel.Application") | Excel must be running, otherwise an OLE Automation error occurs. The x refers to Excel.Application for the youngest instance of Excel. |
GetObject("c:\data\test.xls") GetObject("c:\data\test.xls", _ "Excel.Sheet") |
Each of these starts an invisible reference-independent instance of Excel, if it's not running, otherwise it uses the youngest existing instance. If the specified XLS file is not open, then it is opened as a hidden workbook, and is reference-dependent unless the command was executed as an Excel command. The x refers to the activesheet in the specified file. |
GetObject("c:\data\test.xls", _ "Excel.Chart") |
Behaves like GetObject("c:\data\test.xls") except that the workbook must contain at least one chart sheet in the workbook. |
USING APPLICATION OBJECT LIBRARIES
Excel and MSProject have their own Application Object Libraries. Other applications may have their own libraries in the future.
Advantages of using object libraries:
You don't need to set an object variable with either CreateObject or GetObject. Your macro can use the predefined object names that refer to the target application, for example, Excel and MSProject (although in some cases you must use Excel.Application and MSProject.Application).
Macros in the source application can use the named constants from the target Application Object Library. For example, if Excel has a reference to the Microsoft Project 4.0 Object Library, then Excel macros would automatically understand constants like pjDuration.
Disadvantages of using object libraries:
Once a macro in a source application references a target application library, the target application might continue to run invisibly after the source macro ends, and even after the source application closes.
If you close the target application after if has been referenced by a source macro, then the source application may have trouble referencing the library again until you do one of the following in the source application.
Choose the menu command Run Reset.
Execute the End command in the Debug window or in a macro.
Uncheck the reference to the Object Library, close the dialog, get back into it, and recheck the reference.
Exit and restart the source application.
Microsoft Project 4.0 Object Library
To use the Microsoft Project 4.0 Object Library from Excel, get into an Excel module and choose Tools, References, and check: Microsoft Project 4.0 Object Library. Then you don't need CreateObject or GetObject to refer to MSProject. You can just use the name MSProject or MSProject.Application to refer to MSProject. You could also introduce another object variable with a shorter name, for example:
Set x = MSProject.Application
When an Excel macro references MSProject, it refers to an existing instance if MSProject is already running, otherwise it starts a new invisible instance with no open projects. In the latter case, MSProject continues to run until you do one of the following:
Choose the Excel menu command Run Reset.
Execute the End command in the Debug window or in an Excel macro.
Uncheck the reference to the Microsoft Project 4.0 Object Library in Excel, close the dialog, get back into it, and recheck the reference.
Exit Excel and restart it.
Manually close MSProject or tell it to Quit via a macro.
Also, if you close MSProject after an Excel macro has referenced it, then Excel macros can't reference MSProject again until one of the above actions is taken.
Try This The Excel macro below starts MSProject if not already running, makes it visible and active, and creates a new visible project. 1. Enter the following Excel macro and run it. Sub Sub4() MSProject.Application.Visible = True AppActivate "Microsoft Project" MSProject.FileNew End Sub 2. Close MSProject (choose Yes to any warning message). 3. Run the macro again. Did you get an error message? From the Run menu, choose Reset, and run the macro again. |
Excel 5.0 Object Library from MSProject
To Use the Excel 5.0 Object Library from MSProject, get into the module editor and choose Tools, References, and check Excel 5.0 Object Library. Then you don't need CreateObject or GetObject to refer to Excel. You can just use the name Excel or Excel.Application. You could also use another object variable with a shorter name, for example:
Set x = Excel.Application.
The first time an MSProject macro references Excel, a new invisible instance is run, and all later references use that same instance. That instance continues running until you manually close it or use a macro to tell it to Quit. Note that there isn't a way to reference an existing instance of Excel using this library technique. If you need to reference an existing instance, then use GetObject.
Also, if you close Excel after an MSProject macro has referenced it, then MSProject macros can't reference Excel again (via the library reference) until one of the following actions is taken in MSProject:
Uncheck the reference to the Excel 5.0 Object Library, close the dialog, get back into it, and recheck the reference.
Execute the End command in the Debug window or in an MSProject macro.
Choose the menu command Run Reset.
Exit MSProject and restart it.
Note: Unlike MSProject, when you close Excel, it does not give a warning that another application is using Excel.
Invisible Objects and Object Lifetime - Review
This section reviews and formalized the concepts of reference-dependent objects and opening applications and documents invisibly.
Invisible Application:
An application that is running but doesn't show in the Windows Task List. This is not the same as being minimized or hidden under other windows. If a macro creates an invisible instance of an application, the macro may need to close the application or make it visible before the macro ends, to avoid having invisible instances eating up resources.
If x refers to MSProject.Application, then MSProject can be made visible by using x.Visible=True, x.AppMaximize, x.AppMinimize, or x.AppRestore. The last three statements always activate MSProject, but x.Visible=True makes MSProject active only if MSProject isn't already visible. The statement x.Visible=False has no effect on MSProject.
If x refers to Excel.Application, then x.Visible=True makes Excel visible, and x.Visible=False makes it invisible. Using x.Visible=True when Excel is already visible does not activate Excel.
Microsoft Word can't be made invisible using OLE Automation.
Invisible Document:
A document that is in an invisible application, or a document in a visible application, but the document can't be seen and doesn't appear on the list of open files at the bottom of the application's Window menu. If the application is visible, the document might be invisible because of the method used to open it, or because it was made hidden by some command after it was opened.
If you use CreateObject or GetObject to create/open a project in MSProject, then the project is invisible.
If you use CreateObject or GetObject to create/open a sheet or chart in a new invisible instance of Excel, then the associated workbook is invisible. If Excel is then made visible, the workbook is still a hidden workbook.
There are no invisible documents in Word.
Try This These Excel macros illustrates when an invisible project can or cannot be the active project. 1. Make a test project with two tasks named T1 and T2 and save it as "c:\p1.mpp". 2. Close MSProject. 3. Enter the following Excel macro and run it. Sub Macro1( ) Dim x As Object, p As Object Set x = CreateObject("MSProject.Application") 'Starts invisible x.FileOpen "c:\p1.mpp" 'Open p1.mpp Set p = x.ActiveProject 'Set object variable p.Tasks(2).Name = "zawa" 'Change task2 name x.Alerts False 'Save without asking x.Quit 'Close MSProject End Sub 4. Check that the name of task 2 has changed to zawa. 5. The following Excel macro won't work. Enter and run it. Choose OK to the MSProject error message, switch back to Excel, and choose Goto in the Excel error message. What's wrong with this macro? Sub Macro2() Dim x As Object, p As Object Set p = GetObject("c:\p1.mpp") Set x = p.Parent x.Visible = True p.Tasks(2).Name = "zawa" x.FileSave x.Quit End Sub 6. Here' a quick fix for the above macro. Add the following three lines before the x.FileSave line, and run the macro again. Which application's messages is the "On Error" line supposed to prevent? Which application's messages is the "x.Alert" line supposed to prevent? On Error Resume Next x.Alerts False x.FileOpen "c:\p1.mpp" |
Reference-dependent Object:
An open object that exists only as long as it or one of its subordinate objects is being referenced. The object could be an application or a subordinate object that the application supports, like a project in MSProject, or a worksheet in Excel, or Word Basic in Word.
If you run an MSProject macro that starts Word as a result of
x=CreateObject("Word.Basic")
then that instance of Word.Basic is reference-dependent, because if the value of x changes or x ceases to exist, then Word will automatically close without warning, and without saving changes to documents.
The next two definitions are specific cases:
Reference-dependent document:
An open document that exists only as long as it or one of its subordinate objects is being referenced. When a reference-dependent document closes automatically, it typically does not automatically save changes or ask if you want to save changes.
For example, if you run an EXCEL macro that opens a project using
Set p=GetObject("c:\winproj\p1.mpp")
then p1.mpp is reference-dependent, because if the value of p changes or p ceases to exist, then p1.mpp automatically closes without warning and without saving changes.
NOTE: If you run the above command in an MSProject macro instead of an Excel macro, then p1.mpp is not reference-dependent. I.e. even after p ceases to exist, p1.mpp is still open - it's invisible, but can be seen on the Window New Window list.
Similarly, if you run an MSProject macro that opens a worksheet using
Set s = GetObject("c:\Excel\test.xls")
then test.xls is reference-dependent, because if the value of s changes or s ceases to exist, then test.xls automatically closes. Note that test.xls opens as a hidden workbook and will become reference independent if unhidden manually or by executing
s.Parent.Parent.Windows("test.xls").Visible = True
Reference-dependent projects are created/opened as a result of CreateObject or GetObject run from another application like Excel, and are invisible at first. They can be made visible through the Window New Window menu command if it's available. Invisible reference-dependent projects can never be the active project.
Reference-independent projects are most recently created/opened with methods other than CreateObject or GetObject, i.e. like FileNew and FileOpen.
Technically there are no reference-dependent Word documents because Word doesn't have a Word.Document object. However, the Word.Basic object can be reference-dependent and if the Word.Basic object closes, it closes the application and all open documents without warning.
Reference-dependent Application Instance:
An instance of an application that exists only as long as it or one of its subordinate objects is being referenced.
MSProject can be reference-dependent only if there are no open reference-independent projects, and if MSProject was started as a result of CreateObject/GetObject or a reference via the Microsoft Project 4.0 Object Library.
For example, if MSProject is not running, then starting it with
Set x=CreateObject("MSProject.Application")
creates a reference-dependent instance of MSProject, because if the value of x changes or x ceases to exist, then MSProject closes automatically.
If MSProject is started as the result of CreateObject or GetObject, then if starts out dependent on the object variable used in the CreateObject or GetObject command. After that, it can become reference-independent by restarting it manually, or by opening reference-independent projects.
There are no visible reference-dependent instances of Excel. Once an instance of Excel shows up in the Windows Task List, it remains running until you manually close it or use some command like the Quit method. Invisible instances may or may not be reference dependent. CreateObject("Excel.Application") starts reference-independent instances. CreateObject("Excel.Sheet") and CreateObject(Excel.Chart") create reference-dependent instances if Excel was not already running.
Technically Word can't be a reference-dependent application because there is no
Word.Application object, but the Word.Basic object can be reference-dependent and behaves like an application object.
Using VB3 Forms With MSProject
Because Visual Basic for Applications in MSProject does not include rich event driven graphical interface objects such as text boxes, dropdown lists, etc., some developers will choose to create custom applications using VB3 and MSProject. Two possible design philosophies are listed below
Design it strictly as a VB3 program that controls MSProject. No MSProject macro code is used at all. Advantage: Simplicity.
Write most of the code in MSProject macros. Any "fancy" input/output dialogs are designed in small VB3 programs that are called from the MSProject macros. Advantage: Speed.
The second approach requires some way for the VB3 program to return user input to the calling MSProject macro. The are several ways to pass data between VB3 and MSProject macros, including: OLE Automation, DDE, and API calls (for example, passing data via a global memory block).
Try This This example illustrates a VB3 program returning input to MSProject via OLE Automation, using the Text9 and Text10 fields of the project summary task of the active project. The purpose of the example is for illustration only - the function it performs could be done without VB3. Here's a short description of the logic: The MSProject macro warns the user that the Text9 and Text10 fields of the project summary task will be modified and allows the user to cancel the macro. If the user chooses to continue, the MSProject macro sets the project summary Text10 field to blank. The MSProject macro uses Shell to start the VB3 program AddTask.exe. The MSProject macro waits in a DoEvents loop until the project summary Text10 field is no longer blank. During this time, in the VB3 form, the user can enter the name for a new task in a textbox and then choose OK or Cancel. The VB3 program returns "ok" or cancel" in the project summary Text10 field, and, if OK was chosen, returns the new task name in the project summary Text9 field. The MSProject macro assigns the returned values (the project summary Text9 and Text10 fields) to variables sTextEntered and sButtonChosen. If sButtonChosen = "ok", then a new task is added to the active project with the new name that the user entered. Here are the detailed steps: 1. Start VB3 (Microsoft Visual Basic 3.0). If the toolbox isn't showing, then from the Window menu choose Toolbox. Resize Form1 as shown in the picture. Press F4 and change the Caption property to "Add Task".
2. Create the textbox shown in the picture (use the tool). Change its Name property to txtTextBox and change its Text property to blank (so it's empty). 3. Create the OK command button as shown in the picture (use the tool). Change its Name property to cmdOK, and change its Caption property to "OK". Double click the button and enter the body of the cmdOK_Click procedure shown below: Sub cmdOK_Click () Dim oMSP As object Set oMSP = GetObject(, "MSProject.Application") oMSP.ActiveProject.Text9 = txtTextBox.Text oMSP.ActiveProject.Text10 = "ok" End End Sub 4. Create the command button that says "Cancel" as shown in the picture. Change its Name property to cmdCancel, and change its Caption property to "Cancel". Double click the button and enter the body of the cmdCancel_Click procedure shown below: Sub cmdCancel_Click () Dim oMSP As object Set oMSP = GetObject(, "MSProject.Application") oMSP.ActiveProject.Text10 = "cancel" End End Sub 5. In MSProject, create a test project, turn on the option to view the project summary task (in the Tools Options View dialog). 6. In VB3, press F5 to test run the program. If the form pops up successfully, enter a new task name in the textbox. Test both the OK and Cancel buttons. After each test, switch to MSProject and verify that Text9 and Text10 of the project summary task have been assigned the appropriate values. It won't change Text9 if Cancel is chosen. If you get runtime errors, use the Run menu End command, and fix the errors. 7. Switch to File Manager and create the directory C:\AddTask. Switch back to VB3. From the File menu, choose "Make Exe File ..." and save it as C:\AddTask\AddTask.exe. Next, from the File menu choose "Save Project", and save everything to the C:\AddTask directory, accepting the default file names. Finally, exit VB3. 8. Enter and test run the MSProject macro below: Sub AddTask() Dim sTextEntered As String Dim sButtonChosen As String Dim nAnswer As Integer nAnswer = MsgBox("This macro uses Text9 and Text10 of the " & _ "active project summary task. Continue?", vbOKCancel) If nAnswer = vbCancel Then End ActiveProject.Text10 = "" Shell "C:\AddTask\AddTask.exe", 1 'start as normal window Do DoEvents Loop Until ActiveProject.Text10 <> "" sTextEntered = ActiveProject.Text9 sButtonChosen = ActiveProject.Text10 If sButtonChosen = "ok" Then ActiveProject.Tasks.Add Name:=sTextEntered End If End Sub |
'This will update the task duration with the text from the txtDuration text box.
Sub
cmdUpdate_Click ()
oTask.Duration
= txtDuration
End
Sub
'This
will close the VB3 program.
Sub
cmdClose_Click ()
End
End
Sub
'This
will move to the previous task id unless it is already at 1.
Sub
cmdPrevious_Click ()
If nTaskID > 1 Then nTaskID = nTaskID - 1
lblTaskID
= nTaskID
Set
oTask = oMSP.ActiveProject.Tasks(nTaskID)
lblTaskName
= oTask.Name
txtDuration
= oTask.Duration
End
Sub
'This
will move to the next task id unless is at the largest id
in the project.
Sub
cmdNext_Click ()
If
nTaskID < nNumOfTasks Then nTaskID = nTaskID + 1
lblTaskID
= nTaskID
Set
oTask = oMSP.ActiveProject.Tasks(nTaskID)
lblTaskName
= oTask.Name
txtDuration
= oTask.Duration
End
Sub
Note: You can't activate the invisible project or apply a view or select any tasks in a table or use the link tool button. Use CreateObject to create the project. If P is the object variable that refers to the new invisible project, then you can use the Add method several times to add the three tasks, for example, P.Tasks.Add Name:="a". Then you can put the appropriate values in the Predecessors field for tasks 2 and 3, for example, P.Tasks(2).Predecessors=1.
After you
run the macro, look on the Window menu to see what projects
are open. Is the Unhide item available on the Window menu?
Choose New Window from the Window menu and make the invisible
project show up in a new window. Are the tasks and
predecessors correct?
The macro can assume that the data starts in cell A1 and that there are no blank rows, but has to calculate how many rows there are. The macro should do the following steps:
Start MSProject if it's not running: Use CreateObject and assign the returned value to an object variable called oMSP (so oMSP refers to MSProject).
Make MSProject visible and active.
Create a new visible project (use MSProject's FileNew method). Later, the new project can be referenced as oMSP.ActiveProject.
Assign the number of tasks on Sheet1 to a variable, for example
N = Sheets("Sheet1").Cells(1, 1).CurrentRegion.Rows.Count
For R = 1 to the number of tasks on Sheet1: Use the Add method (with parenthesis around the Name argument) to add another task to the project - use the appropriate cell value for the Name argument, and assign the return value from the Add method to an object variable T (so T refers to the new task). Then use T to assign the appropriate sheet values to the start and duration of the new task.
Use OLE Automation where possible, and avoid copy/paste techniques.
Notes:
In Excel, to access the content of a cell at row R column C of Sheet1, use can use the expression: Sheets("Sheet1").Cells(R,C).Value.
In the For loop, R will be the loop variable, and C will be 1, 2, or 3, depending on whether you want the name, start, or duration.
To add a new task at row R in the new project and have the object variable T refer to the new task, use: Set T = oMSP.ActiveProject.Tasks.Add (Name:= value)
where the Name argument comes from row R column 1 of Sheet1.
You can use ActiveSheet in the macro instead of Sheets("Sheet1"). If you use ActiveSheet, then some worksheet (not necessarily Sheet1) must be active before you run the macro. The advantage of using notation like Sheets("Sheet1") is that Sheet1 doesn't have to be active - you can run the macro from the Excel module editor.
Test run the
macro once when MSProject is open and once when it's not. You
should see the new project and tasks being added.
List1.AddItem string
Note: To check if a task oTasks(n) is not blank, use the If/EndIf block that starts with:
If Not oTasks(n) Is Nothing Then
Open or create a test project with some nonblank tasks and some blank tasks, and run the VB3 program. Only the nonblank tasks should show in the list.
The following limitations are from the VB3 Programmer's Guide, Appendix D: List boxes can
hold 5440
items, each item has a maximum of 1K characters, and the
total of all characters in the list box cannot exceed 64K.
x.Charts.Add
x.ActiveChart.ChartWizard _
Source:=s.Cells(1, 1).CurrentRegion, _
PlotBy:=2, _
CategoryLabels:=1