GetObject или GetActiveObject не удается найти запущенное приложение Office

Применимо к: Office Products

Проблемы


При попытке использовать GetObject (Microsoft Visual Basic) или GetActiveObject (Microsoft Visual C++) для автоматизации приложения Microsoft Office появляется одно из следующих сообщений об ошибке, даже если приложение Office запущено.
Сообщение об ошибке 1
Ошибка во время выполнения "429": компонент ActiveX не может создать объект
Сообщение об ошибке 2
Ошибка: 0x800401e3 "операция недоступна"

Причина


Несмотря на то, что приложение Office запущено, оно может быть не зарегистрировано в таблице текущих объектов (ROT). Запущенный экземпляр приложения Office должен быть зарегистрирован в таблице ROT, прежде чем его можно будет присоединить к функции GetObject (Visual Basic) или GetActiveObject (Visual C++). При запуске приложения Office регистрация запущенных объектов сразу же завершается. Это оптимизирует процесс запуска приложения. Вместо того чтобы регистрироваться при запуске, приложение Office регистрирует запущенные объекты в таблице ROT после того, как он теряет фокус. Таким образом, при попытке использовать GetObject или GetActiveObject для присоединения к запущенному экземпляру приложения Office перед тем, как приложение теряет фокус, может появиться одно из описанных выше ошибок.

Решение


С помощью кода можно изменить фокус от приложения Office на свое собственное приложение (или другое приложение), чтобы позволить ему зарегистрироваться в таблице ROT. Кроме того, если ваш код запускает exe-файл приложения Office, может потребоваться дождаться завершения загрузки приложения Office, прежде чем пытаться присоединиться к запущенному экземпляру. Пример кода предлагается в разделе "Дополнительные сведения".

Статус


Такое поведение является особенностью данного продукта.

Дополнительная информация


В большинстве случаев разработчикам, которые хотят автоматизировать приложение Office, нужно использовать CreateObject (Visual Basic) или CoCreateInstance (Visual C++) для запуска нового экземпляра приложения Office. Однако в некоторых случаях может потребоваться автоматизировать приложение Office, которое уже запущено: например, если пользователь ранее запустил приложение Office. Или, если вы запустили исполняемый файл приложения Office с помощью кода, так что вы можете указать параметры командной строки для приложения. Для автоматизации работающего приложения Office необходимо использовать GetObject или GetActiveObject.

Действия по воспроизведению поведения

  1. Запустите Microsoft Visual Basic и создайте новый стандартный проект EXE. По умолчанию создается форма Form1.
  2. Добавьте в форму Form1 элемент управления CommandButton .
  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. exe в примере кода.
  5. Закройте приложение Microsoft Excel, если оно уже запущено.
  6. Нажмите клавишу F5, чтобы запустить проект, и выберите пункт Command1.

Обходное решение

Чтобы обойти эту проблему, можно выполнить указанные ниже действия.
  • Передавайте фокус приложению Office, изменив второй аргумент функции Shell на vbMinimizedFocus, vbMaximizedFocusили vbNormalFocus.
  • Присвойте форме Visual Basic фокус.
  • Попробуйте выполнить операцию GetObject при выполнении учета во время загрузки приложения Office.
Следующий пересмотренный код иллюстрирует это временное решение.
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();

Ссылки


Для получения дополнительной информации щелкните приведенные ниже номера статей базы знаний Майкрософт:
192919 Автоматизация защищенной базы данных Access с помощью Visual Basic
237338 Сообщение об ошибке с помощью WordMail: "Этот метод или свойство недоступно"
240794 Определение пути для приложения Office