GetObject 或 GetActiveObject 无法找到正在运行的 Office 应用程序

症状

当你尝试使用 GetObject (Microsoft visual Basic)或 GetActiveObject (Microsoft visual c + +)自动执行 Microsoft Office 应用程序时,将收到以下错误消息之一,即使 Office 应用程序正在运行:

错误消息 1

运行时错误 "429": ActiveX 组件无法创建对象

错误消息 2

错误: 0x800401e3 "操作不可用"

原因

虽然 Office 应用程序正在运行,但它可能未在运行对象表(ROT)中注册。 必须先在 ROT 中注册 Office 应用程序的运行实例,然后才能使用 GetObject (visual Basic)或 GetActiveObject (visual c + +)将其附加到该应用程序。 当 Office 应用程序启动时,它不会立即注册其运行对象。 这将优化应用程序的启动过程。 Office 应用程序在失去焦点后将其运行的对象注册到 ROT 中,而不是在启动时注册。 因此,如果你尝试使用 GetObject 或 GetActiveObject 附加到 Office 应用程序的运行实例,然后应用程序失去焦点,你可能会收到上述错误之一。

解决方案

使用代码,你可以将焦点从 Office 应用程序更改为你自己的应用程序(或其他应用程序),以便允许它在 ROT 中注册自己。 此外,如果你的代码启动 Office 应用程序的 exe 文件,你可能需要等待 Office 应用程序在尝试附加到正在运行的实例之前完成加载。 在 "详细信息" 部分中提供了一个代码示例作为解决方法。

状态

这是设计的行为。

更多信息

在大多数情况下,想要自动化 Office 应用程序的开发人员需要使用 CreateObject (visual Basic)或 CoCreateInstance (visual c + +)启动 office 应用程序的新实例。 但是,在某些情况下,你可能希望自动执行已在运行的 Office 应用程序:例如,如果用户以前启动了 Office 应用程序。 或者,如果你使用代码启动 Office 应用程序的可执行文件,以便你可以为应用程序指定命令行开关。 为了自动运行运行的 Office 应用程序,必须使用 GetObject 或 GetActiveObject。

重现问题的步骤

  1. 启动 Microsoft Visual Basic 并创建新的标准 EXE 项目。 默认情况下会创建 Form1。

  2. 将 命令按钮 控件添加到 Form1。

  3. 将以下代码添加到窗体的代码模块中。

    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 = NothingEnd Sub
  4. 请确保在代码示例中,Excel 的位置正确无误。

  5. 如果 Microsoft Excel 已在运行,请退出它。

  6. 按 F5 运行项目,然后单击 " Command1"。

解决方法

要解决此问题,您可以:

  • 通过将 Shell 函数的第二个参数更改为 " vbMinimizedFocus"、" vbMaximizedFocus" 或 " vbNormalFocus",将焦点交给 Office 应用程序。

  • 为你的 Visual Basic 窗体提供焦点。

  • 在核算 Office 应用程序的加载时间时尝试 GetObject 。

以下修改后的代码演示了此解决方法。

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 IfEnd Sub

C + + 的解决方法

如果你使用的是 c + + 编程,则以下代码示例演示了上述 Visual Basic 示例中所示的类似解决方法。 请注意, SetForegroundWindow 用于将焦点移出 Excel,从而允许它注册其运行对象。

//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();

参考

有关详细信息,请单击下面的文章编号,以查看 Microsoft 知识库中的文章:

192919 如何使用 Visual Basic 自动化安全的 Access 数据库

237338 使用 WordMail 的错误消息: "此方法或属性不可用"

240794 如何确定 Office 应用程序的路径

需要更多帮助?

扩展你的技能
了解培训
抢先获得新功能
加入 Microsoft 内部人员

此信息是否有帮助?

你对翻译质量的满意程度如何?

哪些因素影响了你的体验?

是否还有其他反馈?(可选)

谢谢您的反馈意见!

×