PRB: GetObject or GetActiveObject Cannot Find a Running Office Application (238610)
The information in this article applies to:
- Microsoft Office Excel 2003
- Microsoft Excel 2002
- Microsoft Excel 2000
- Microsoft Excel 97 for Windows
- Microsoft Visual Basic for Applications 5.0
- Microsoft Visual Basic for Applications 6.0
- Microsoft Visual C++, 32-bit Professional Edition 5.0
- Microsoft Visual C++, 32-bit Professional Edition 6.0
- Microsoft Office Access 2003
- Microsoft Access 2002
- Microsoft Access 2000
- Microsoft Access 97
- Microsoft Office PowerPoint 2003
- Microsoft PowerPoint 2002
- Microsoft PowerPoint 2000
- Microsoft PowerPoint 97 for Windows
- Microsoft Office Word 2003
- Microsoft Word 2002
- Microsoft Word 2000
- Microsoft Word 97 for Windows
This article was previously published under Q238610 SYMPTOMS When you try to use GetObject (Microsoft Visual Basic) or GetActiveObject (Microsoft Visual C++) to automate a Microsoft Office application,
you get one of the following error messages, even though the Office application
is running: Run-time error '429': ActiveX
component can't create object -or- Error:
0x800401e3 "Operation unavailable" CAUSE Although the Office application is running, it might not be
registered in the Running Object Table (ROT). A running instance of an Office
application must be registered in the ROT before it can be attached to using GetObject (Visual Basic) or GetActiveObject (Visual C++).
When an Office application starts, it
does not immediately register its running objects. This optimizes the
application's startup process. Instead of registering at startup, an Office
application registers its running objects in the ROT once it loses focus.
Therefore, if you attempt to use GetObject or GetActiveObject to attach to a running instance of an Office application before
the application has lost focus, you might receive one of the errors above.
RESOLUTION Using code, you can change focus from the Office
application to your own application (or to some other application) to allow it
to register itself in the ROT. Additionally, if your code is launching the
Office application's exe file, you might need to wait for the Office
application to finish loading before attempting to attach to the running
instance. A code sample is provided as a workaround in the "More Information"
section below.
STATUS This behavior is by design.
MORE INFORMATION In most situations, developers who want to automate an
Office application need to use CreateObject (Visual Basic) or CoCreateInstance (Visual C++) to launch a new instance of the Office
application. However, there are cases where you might prefer to
automate an Office application that is already running: for example, if the
user previously started the Office application. Or, if you launched the Office
application's executable using code so that you could specify command-line
switches for the application. In order to automate the running Office
application, you must use GetObject or GetActiveObject. Steps to Reproduce Behavior- Start Microsoft Visual Basic and create a new Standard EXE
project. Form1 is created by default.
- Add a CommandButton control to Form1.
- Add the following code to the form's code module:
Private Sub Command1_Click()
Dim oExcel As Object
' Launch a new instance of Microsoft Excel:
Shell "C:\Program Files\Microsoft Office\Office\Excel.EXE", _
vbMinimizedNoFocus
' An error 429 occurs on the following line:
Set oExcel = GetObject(, "Excel.Application")
MsgBox oExcel.Name
Set oExcel = Nothing
End Sub
- Make sure the location of the Excel.exe is correct in the
code sample.
- Quit Microsoft Excel if it is already running.
- Press F5 to run the project, and click Command1.
Workaround To work around the problem, you can:
- Give focus to the Office application by changing the second
argument of the Shell function to either vbMinimizedFocus, vbMaximizedFocus, or vbNormalFocus.
- Give your Visual Basic form the focus.
- And finally, attempt GetObject while accounting for the Office application's load
time.
The following revised code illustrates this workaround:
Private Declare Sub Sleep Lib "kernel32" _
(ByVal dwMilliseconds As Long)
Private Sub Command1_Click()
Dim intSection As Integer
Dim intTries As Integer
Dim oExcel As Object
' Enable error handler for this procedure:
On Error GoTo ErrorHandler
' Launch Microsoft Excel, giving it focus:
Shell "C:\Program Files\Microsoft Office\Office\Excel.EXE", _
vbMinimizedFocus 'other options for starting with
'focus: vbMaximizedFocus and vbNormalFocus
' Move focus back to this form. (This ensures the Office
' application registers itself in the ROT, allowing
' GetObject to find it.)
Me.SetFocus
' Attempt to use GetObject to reference the running
' Office application:
intSection = 1 'attempting GetObject...
Set oExcel = GetObject(, "Excel.Application")
intSection = 0 'resume normal error handling
' Now you can automate Microsoft Excel:
MsgBox oExcel.Name & ": able to GetObject after " & _
intTries + 1 & " tries.", vbMsgBoxSetForeground
' Finished with automation so release your reference:
Set oExcel = Nothing
' Exit procedure:
Exit Sub
ErrorHandler:
If intSection = 1 Then 'GetObject may have failed because the
'Shell function is asynchronous; enough time has not elapsed
'for GetObject to find the running Office application. Wait
'wait 1/2 seconds and retry the GetObject. If you try 20 times
'and GetObject still fails, assume some other reason
'for GetObject failing and exit the procedure.
intTries = intTries + 1
If intTries < 20 Then
Sleep 500 ' wait 1/2 seconds
Resume 'resume code at the GetObject line
Else
MsgBox "GetObject still failing. Process ended.", _
vbMsgBoxSetForeground
End If
Else 'intSection = 0 so use normal error handling:
MsgBox Error$
End If
End Sub
Workaround for C++ If you are programming in C++, the following code sample
demonstrates a similar workaround as shown in the above Visual Basic sample.
Notice that SetForegroundWindow() is used to move focus away from Excel, allowing it to register
its running objects:
//Store the handle of the currently active window...
HWND hwndCurrent = ::GetForegroundWindow();
//Launch Excel and wait until it is waiting for
//user input...
STARTUPINFO Start;
PROCESS_INFORMATION ProcInfo;
ZeroMemory(&Start,sizeof(STARTUPINFO));
Start.cb=sizeof(Start);
Start.dwFlags = STARTF_USESHOWWINDOW;
Start.wShowWindow = SW_SHOWMINIMIZED;
//Change the path to Excel as needed...
LPSTR pszExcelPath =
"c:\\program files\\microsoft office\\office\\excel.exe";
::CreateProcess(NULL, pszExcelPath, 0, 0, 1,
NORMAL_PRIORITY_CLASS, 0, NULL, &Start, &ProcInfo);
if((::WaitForInputIdle(ProcInfo.hProcess, 10000))==WAIT_TIMEOUT)
{
::MessageBox(NULL, "Timed out waiting for Excel.", NULL,
MB_OK);
}
//Restore the active window to the foreground...
// NOTE: If you comment out this line, the code will fail!
::SetForegroundWindow(hwndCurrent);
//Initialize COM library...
::CoInitialize(NULL);
//Attach to the running instance...
CLSID clsid;
CLSIDFromProgID(L"Excel.Application", &clsid);
IUnknown *pUnk = NULL;
IDispatch *pDisp = NULL;
for(int i=1;i<=5;i++) //try attaching for up to 5 attempts
{
HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk);
if(SUCCEEDED(hr))
{
hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp);
break;
}
::Sleep(1000);
}
if (!pDisp) {
::MessageBox(NULL, "Failed to find instance!!", "Error",
MB_ICONHAND);
}
else {
::MessageBox(NULL, "Got instance of Excel!", "Success", MB_OK);
}
//Release the no-longer-needed IUnknown...
if (pUnk)
pUnk->Release();
//... Add your automation code for Excel here ...
//Release pDisp when no longer needed...
if (pDisp)
pDisp->Release();
//Cleanup COM...
CoUninitialize();
REFERENCES For related information, please click the article numbers
below to view the articles in the Microsoft Knowledge Base: 192919 HOWTO: Automate a Secured Access Database Using Visual Basic
237338 WD2000: ErrMsg: "This method or property is not available"
240794 HOWTO: Determine the Path for an Office Application
Modification Type: | Minor | Last Reviewed: | 7/16/2004 |
---|
Keywords: | kbAutomation kbprb KB238610 kbAudDeveloper |
---|
|