Automation clients may use early binding in Visual Basic
(VB) to programmatically work with a Microsoft Office application. When
Automation clients do so, they may inadvertently use unqualified property or
method calls in their code. This may lead to errors or to unexpected
behaviors.
Programmers who use an Office application type library in
their VB project must be sensitive to this issue when they write
code.
Unqualified References in Visual Basic
Visual Basic is designed to make programming simple and intuitive
for programmers of all skill levels. VB introduced the concept of the
Global object to make the coding for a particular component easier and
more user-friendly. Programmers who use the object can call its properties and
methods without the need to explicitly dimension and create a new instance of
the object. In other words, the object itself can be called from anywhere in
the code. Therefore, it is "global." Programmers do not have to explicitly
write code on their own to do this.
NOTE: The Global object is differentiated by setting the appobject attribute on the coclass in the type library of the object. It is typically, but not
necessarily, called "Global."
For example, consider the
LoadPicture method in VB. This method is frequently called without
qualification, as follows:
Dim pic As StdPicture
Set pic = LoadPicture("C:\sometestpicture.bmp")
However, if you view the
LoadPicture function in the Visual Basic Object Browser, you see that the
function is really a method on a
Global object. VB keeps this
Global object loaded for the life of the program. You do not have to
dimension or create the object before calling the method. Nor do you have to
qualify the call with the object name. VB handles that the first time that the
object is accessed. This simplifies the code. VB programmers can focus more on
the task at hand than on the objects that are necessary to complete the
task.
NOTE: Developers who are familiar with writing ActiveX components in
VB will recognize this behavior as the same behavior that you get if you set
the instancing property of a Public class to GlobalMultiUse. In fact, a GlobalMultiUse class is a Global object.
When the VB compiler encounters a
function or a subroutine that does not appear to belong to the current project,
the VB compiler searches the list of
Global objects that are referenced in the project. The VB compiler looks
for a matching function name and a matching signature among the properties and
methods of the object. If the VB compiler finds a match, VB sets the code to
call that function or property on the
Global object.
When the code is called, VB creates the object
if the object has not been created before. VB then sets a reference to that
object in a hidden variable. The reference is not released until the project is
ended. Projects are typically ended when the application shuts down.
Any unqualified method or property call on that object is invoked on the hidden
reference. You do not have access to this hidden variable. You cannot change it
or release it from VB code.
Global Objects in Microsoft Office Applications
Microsoft Office is designed to use
Global objects in much the same way that VB uses them for its native
functions. This makes coding easier for macros written in Microsoft Visual
Basic for Applications (VBA). VBA code makes wide use of unqualified property
and method calls to keep the code simple and to keep the code understandable
for beginners.
For example, the following Microsoft Word VBA code
sets some text after the third paragraph in a document:
Sub AddSomeText()
ActiveDocument.Paragraphs(3).Range.Select
Selection.Collapse wdCollapseEnd
Selection.TypeText "Some new text."
End Sub
The code uses two objects,
ActiveDocument and
Selection. Both objects are native to Word VBA. To access these objects,
the code makes unqualified method calls on two property procedures on the Word
Global object. (The property procedures use the same name and return the
respective object.) The process is equivalent to the following:
Public oGlobalWordApp As Word.Application
Sub AddSomeText()
If oGlobalWordApp Is Nothing Then
' Sets variable to the running instance of the Word
' Global object (which is nearly the same as Word.Application)...
Set oGlobalWordApp = Word.Global
End If
oGlobalWordApp.ActiveDocument.Paragraphs(3).Range.Select
oGlobalWordApp.Selection.Collapse wdCollapseEnd
oGlobalWordApp.Selection.TypeText "Some new text."
End Sub
Look at the two code samples. You can see why most developers
prefer to use unqualified code. Unqualified code is easier to understand and is
less trouble to write. Additionally, when unqualified code is used in the
native container for which it is designed, it is also completely safe.
The Problems in Using Unqualified Code with Office
Problems may occur when you reference a
Global object that does not live inside your process space. In this
situation, many of the assumptions about global objects break down. These
assumptions include things such as the following: that there is only one
instance; that calls to the object are native to the host; or that calls are
kept alive for the length of the host application. When these assumptions break
down, buggy behavior may result.
Office applications use
Global objects and live out-of-process. Therefore, VB code that uses
early binding to automate these applications is especially vulnerable to
problems involving unqualified method calls. Note that unqualified method calls
only occur if you reference the type library for the Office application in the
References dialog box. You typically do this when you use early binding.
Code that uses late binding is always qualified. It does not experience these
problems if you do not reference the type library.
In itself,
unqualified code frequently runs just fine in VB, even when it references
out-of-process objects. This makes the problems that you experience harder to
deal with, because the code appears to work successfully some of the time.
There is, however, one warning sign to look for, as follows:
If the code always appears to work the first time that it is run, and if the errors or the unexpected behaviors occur only during subsequent calls to the same code, an unqualified method call is the cause.
This problem occurs because the code creates a new
instance of the Office application each time that it runs, but the unqualified
code caused VB to set a hidden reference to the old instance. Therefore,
subsequent calls on the hidden variable (for an unqualified method) are made to
the wrong server.
Some of the errors or unexpected behaviors that you
might experience if you make an unqualified call to an Office object are as
follow:
- Error 462 or Error -2147417848: The code uses an unqualified method on an Office instance that
has been ended (for example, by calling the Quit method). If the code is structured to create a new Office
application instance each time that it is run, it will typically close the
instance at the end of the task. If this code is run a second time, the
unqualified call is unsuccessful. VB calls the previous instance, but the
remote server has unloaded.
- Application Does Not Shut Down: Unqualified calls in VB set a hidden variable reference to the
Office Global object. Therefore, an Office application may fail to shut down,
even if you call the Quit method, because it still has outstanding references. This
behavior typically occurs on the first instance that the code uses. However,
complex programs may cause it to occur with multiple instances.
- Error 91 or Object is Missing Errors: You may see errors or unexpected results relating to the
application state. You may also see unexpected results relating to an empty
object. These behaviors occur if the code creates a new Office instance each
time that it is run and if it does not quit the previous instance properly. Or,
these behaviors occur if the code creates a new Office instance each time that
it is run and if the Office application does not shut down, as mentioned in the
preceding issue. These errors occur if the document or other objects that you
are trying to access are located in another instance of the application than
the Global object that VB has referenced, and if the objects (such as ActiveDocument or ActiveChart) do not exist in the global instance.
- Code Runs Without Error, But Document Is
Incorrect: Unqualified calls can be invoked for an instance other than
the one that you explicitly set up. Therefore, some tasks (especially those
calls to Selection or Range) may be successfully performed, but these tasks are performed on
the wrong document. Avoid the use of non-specific range or non-specific
selection objects that can run on any document.
The exact error or behavior may differ depending on the Office
application that is involved and depending on the context in which the problem
occurs.
Qualifying the Code to Avoid Errors
The best guideline is to avoid using any Office object that you
do not explicitly call from a parent object that you set in a specific
variable. In other words, look for code that uses Office objects without
qualifying which Office instance or document that it is supposed to refer to.
For example, this code uses an unqualified call to display the count of open
workbooks in Microsoft Excel:
Sub CreateThreeBooks()
Dim oXL As Excel.Application
Dim i As Long
' Create Excel instance (make it visible for test)...
Set oXL = New Excel.Application
oXL.Visible = True
' Open a few empty workbooks...
For i = 1 To 3
oXL.Workbooks.Add
Next i
' How many books did we open?
MsgBox "Number of workbooks: " & Workbooks.Count, vbMsgBoxSetForeground
' Shutdown Excel (or do we?)...
oXL.Quit
Set oXL = Nothing
' Check the Processes list. Excel.exe is still running!
End Sub
When you run the code, it appears to run correctly the first time.
However, Excel continues to run, even though you called the
Quit method. If you call the code again, the message box now
incorrectly displays 0 for the workbook count. Your code may now fail where you
would expect it to succeed.
To resolve both problems, you must fully
qualify the Workbooks object that you reference for the count, as
follows:
MsgBox "Number of workbooks: " & oXL.Workbooks.Count, vbMsgBoxSetForeground
Some Office objects and functions are typically unqualified in VBA
code. They can cause problems if you use that same code in VB and if you do not
add the appropriate qualifications. Here is a list of common objects and
functions that are typically unqualified in VBA code.
What to Do If You Experience These Problems
If you have an existing project that no longer works because of
one of the problems in this article, here are a few things you can do to fix
it:
- Make sure that you set Option Explicit at the top of each file in your project. This setting makes sure
that VB generates a compile-time error and that VB does not automatically use a
zero value for constants that it does not recognize.
- If the project is relatively simple, or if the Office
Automation code is brief, remove the Office type library from your list of
references, and then recompile the project. You then receive errors about
unknown types for each object declaration that you used for an Office type.
Change these to type Object. You may also have to change any New statements to use CreateObject instead. If you use any enumeration values or constants from the
Office type library, you have to replace them with their numeric value. After
you have finished that, the only compile errors that you receive are for
unqualified methods. Find each error, and then qualify the call with the
application or document object, as appropriate.
- If the program is complex, try to find the unqualified
calls by explicitly forcing the remote Office application to quit after the
code runs for the first time. If the code explicitly creates a new instance
each time, it should be able to run even if the previous instance was ended. To
do so, follow these steps:
- Run the code one time to make sure it runs the first
time (even if unqualified).
- Check the Processes list in the Task Manager window, and then quit the instance of
the Office application that you started during the first run.
- Rerun the code with VB set to Break on All Errors. If VB breaks and displays Error 462 (or Error -2147417848)
during the second run, that line probably contains an unqualified method or
property call.
NOTE: Unqualified calls may appear as parameter values to a function or
a property that is itself fully qualified. Therefore, examine carefully the
parameters that you are passing, especially when you use a named-argument
syntax. After you find an unqualified object or function that is not native to
Visual Basic, qualify it with the variable name of the Application object that
you used to start the Office application.