GetObject ou GetActiveObject não consegue encontrar uma aplicação de Escritório em execução

Sintomas

Quando tenta utilizar o GetObject (Microsoft Visual Basic) ou o GetActiveObject (Microsoft Visual C++) para automatizar uma aplicação do Microsoft Office, obtém uma das seguintes mensagens de erro, mesmo que a aplicação do Office esteja em execução:

Mensagem de erro 1

Erro de tempo de execução '429': Componente ActiveX não pode criar objeto

Mensagem de erro 2

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

Causa

Embora o pedido do Office esteja em execução, pode não estar registado na Tabela de Objetos de Execução (ROT). Uma instância em execução de um pedido de Escritório deve ser registada no ROT antes de poder ser anexada à utilização do GetObject (Visual Basic) ou getActiveObject (Visual C++). Quando uma aplicação do Office começa, não regista imediatamente os seus objetos de funcionamento. Isto otimiza o processo de arranque da aplicação. Em vez de se registar no arranque, uma aplicação do Office regista os seus objetos de funcionamento no ROT assim que perde o foco. Portanto, se tentar utilizar o GetObject ou o GetActiveObject para anexar a uma instância de execução de uma aplicação do Office antes de a aplicação perder o foco, poderá receber um dos erros acima referidos.

Resolução

Utilizando o código, pode alterar o foco da aplicação Do Office para a sua própria aplicação (ou para qualquer outra aplicação) para permitir que se registe no ROT. Além disso, se o seu código estiver a lançar o ficheiro exe da aplicação do Office, poderá ter de esperar que o pedido do Office termine de ser carregado antes de tentar anexar a instância de execução. Uma amostra de código é fornecida como uma solução alternativa na secção "Mais Informações".

Estado

Este comportamento é por desígnio.

Mais Informações

Na maioria das situações, os desenvolvedores que pretendam automatizar uma aplicação do Office precisam de usar o CreateObject (Visual Basic) ou CoCreateInstance (Visual C++) para lançar uma nova instância da aplicação do Office. No entanto, existem casos em que poderá preferir automatizar uma aplicação do Office que já está em execução: por exemplo, se o utilizador já tinha iniciado a aplicação do Office. Ou, se lançou o código executável da aplicação do Office para que possa especificar comutadores de linha de comando para a aplicação. Para automatizar a aplicação do Office em execução, tem de utilizar o GetObject ou o GetActiveObject.

Passos para reproduzir o comportamento

  1. Inicie o Microsoft Visual Basic e crie um novo projeto Standard EXE. A Forma1 é criada por defeito.

  2. Adicione um comando Descotam o comando ao Formulário1.

  3. Adicione o seguinte código 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 = NothingEnd Sub
  4. Certifique-se de que a localização do Excel.exe está correta na amostra de código.

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

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

Solução

Para contornar o problema, pode:

  • Concentre-se na aplicação do Office alterando o segundo argumento da função Shell para vbMinimizedFocus, vbMaximizedFocus, ou vbNormalFocus.

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

  • Tente obter o GetObject enquanto faz contas do tempo de carga do pedido do Office.

O seguinte código revisto ilustra esta solução.

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

Solução alternativa para C++

Se estiver a programar em C++, a seguinte amostra de código demonstra uma solução semelhante à mostrada na amostra de Base Visual acima. Note que o SetForegroundWindow é utilizado para afastar o foco do Excel, permitindo-lhe registar os seus objetos de funcionamento.

//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 artigos para ver os artigos na Base de Conhecimento da Microsoft:

192919 Como automatizar uma base de dados de acesso segura usando o Visual Basic

237338 Mensagem de erro usando o WordMail: "Este método ou propriedade não está disponível"

240794 Como determinar o caminho para uma aplicação do Escritório

Precisa de mais ajuda?

Aumente os seus conhecimentos
Explore as formações
Seja o primeiro a obter novas funcionalidades
Aderir ao Microsoft insiders

As informações foram úteis?

Obrigado pelos seus comentários!

×