Applies ToOffice Products

Sintomas

Ao tentar usar GetObject (Microsoft Visual Basic) ou GetActiveObject (Microsoft Visual C++) para automatizar um aplicativo do Microsoft Office, você obtém uma das seguintes mensagens de erro, mesmo que o aplicativo do Office esteja em execução:

Mensagem de erro 1

Erro em tempo de execução '429': O componente ActiveX não pode criar objeto

Mensagem de erro 2

Erro: 0x800401e3 "Operação indisponível"

Causa

Embora o aplicativo do Office esteja em execução, ele pode não ser registrado na ROT (Tabela de Objetos em Execução). Uma instância em execução de um aplicativo do Office deve ser registrada no ROT antes de poder ser anexada ao uso de GetObject (Visual Basic) ou GetActiveObject (Visual C++).Quando um aplicativo do Office é iniciado, ele não registra imediatamente seus objetos em execução. Isso otimiza o processo de inicialização do aplicativo. Em vez de se registrar na inicialização, um aplicativo do Office registra seus objetos em execução no ROT quando perde o foco. Portanto, se você tentar usar GetObject ou GetActiveObject para anexar a uma instância em execução de um aplicativo do Office antes que o aplicativo tenha perdido o foco, você poderá receber um dos erros acima.

Resolução

Usando o código, você pode alterar o foco do aplicativo do Office para seu próprio aplicativo (ou para algum outro aplicativo) para permitir que ele se registre no ROT. Além disso, se o código estiver iniciando o arquivo exe do aplicativo do Office, talvez seja necessário aguardar que o aplicativo do Office termine o carregamento antes de tentar anexar à instância em execução. Um exemplo de código é fornecido como uma solução alternativa na seção "Mais Informações".

Status

Este é o comportamento padrão.

Informações adicionais

Na maioria das situações, os desenvolvedores que desejam automatizar um aplicativo do Office precisam usar CreateObject (Visual Basic) ou CoCreateInstance (Visual C++) para iniciar uma nova instância do aplicativo do Office.No entanto, há casos em que talvez você prefira automatizar um aplicativo do Office que já está em execução: por exemplo, se o usuário iniciou anteriormente o aplicativo do Office. Ou, se você iniciou o executável do aplicativo do Office usando o código para que pudesse especificar comutadores de linha de comando para o aplicativo. Para automatizar o aplicativo do Office em execução, você deve usar GetObject ou GetActiveObject.

Etapas para reproduzir o comportamento

  1. Inicie o Microsoft Visual Basic e crie um novo projeto STANDARD EXE. O Form1 é criado por padrão.

  2. Adicione um controle CommandButton ao Form1.

  3. Adicione o código a seguir ao módulo de código do formulário.

    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
    
  4. Verifique se o local do Excel.exe está correto no exemplo de código.

  5. Saia do Microsoft Excel se ele já estiver em execução.

  6. Pressione F5 para executar o projeto e clique em Comando1.

Solução alternativa

Para contornar o problema, você pode:

  • Dê foco ao aplicativo do Office alterando o segundo argumento da função Shell para vbMinimizedFocus, vbMaximizedFocus ou vbNormalFocus.

  • Dê o foco ao seu formulário do Visual Basic.

  • Tente GetObject durante a contabilidade do tempo de carga do aplicativo do Office.

O código revisado a seguir ilustra essa solução alternativa.

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

Solução alternativa para C++

Se você estiver programando no C++, o exemplo de código a seguir demonstrará uma solução alternativa semelhante à mostrada no exemplo do Visual Basic acima. Observe que SetForegroundWindow é usado para afastar o foco do Excel, permitindo que ele registre seus objetos em execução.

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

Referências

Para obter mais informações, clique nos seguintes números de artigo para exibir o artigo:

Como encontrar o caminho de instalação de um aplicativo do Office

Precisa de mais ajuda?

Quer mais opções

Explore os benefícios da assinatura, procure cursos de treinamento, saiba como proteger seu dispositivo e muito mais.

As comunidades ajudam você a fazer e responder perguntas, fazer comentários e ouvir especialistas com conhecimento avançado.