GetObject eller GetActiveObject kan inte hitta ett aktivt Office-program

Gäller för: Office Products

Symptom


När du försöker använda GetObject (Microsoft Visual Basic) eller GetActiveObject (Microsoft Visual C++) för att automatisera ett Microsoft Office-program får du något av följande fel meddelanden, även om Office-programmet körs:
Felmeddelande 1
Körfel ' 429 ': ActiveX-komponenten kan inte skapa objekt
Felmeddelande 2
Fel: 0x800401e3 "-åtgärd ej tillgänglig"

Orsak


Trots att Office-programmet körs är det inte säkert att det är registrerat i objekt tabellen (RÖTANGREPP). En pågående instans av ett Office-program måste vara registrerad i en RÖTANGREPP innan den kan kopplas till med hjälp av GetObject (Visual Basic) eller GetActiveObject (Visual C++). När ett Office-program startas registreras inte de objekt som körs omedelbart. Då optimeras start processen för programmet. I stället för att logga in vid start registrerar ett Office-program sina aktiva objekt i bilden när det tappar fokus. Om du till exempel försöker använda GetObject eller GetActiveObject för att bifoga till en instans av ett Office-program som körs innan programmet har förlorat fokus, kanske ett av ovanstående fel meddelanden visas.

Lösning


Med kod kan du ändra fokus från Office-programmet till ditt eget program (eller till ett annat program) så att det kan registrera sig i fru-objektet. Om koden startar Office-programmets exe-fil kan du dessutom behöva vänta tills Office-programmet har lästs in innan det försöker ansluta till instansen. Ett kod exempel tillhandahålls som en lösning i "Mer information".

Status


Detta är avsiktligt.

Mer information


I de flesta fall måste utvecklare som vill automatisera ett Office-program använda CreateObject (Visual Basic) eller CoCreateInstance (Visual C++) för att starta en ny instans av Office-programmet. Men det finns fall där du kanske föredrar att automatisera ett Office-program som redan körs: om användaren till exempel startade Office-programmet tidigare. Om du har startat Office-programmets körbara fil med kod så kan du ange kommando rads växlar för programmet. För att automatisera den aktiva Office-tillämpningen måste du använda GetObject eller GetActiveObject.

Steg för att återskapa beteendet

  1. Starta Microsoft Visual Basic och skapa ett nytt Standard-EXE-projekt. Form1 skapas som standard.
  2. Lägga till en CommandButton -kontroll i Form1.
  3. Lägg till följande kod i formuläret kod.
    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. Kontrol lera att platsen för Excel. exe är korrekt i kod exempel.
  5. Avsluta Microsoft Excel om det redan körs.
  6. Kör projektet genom att trycka på F5 och klicka på Command1.

Lösning

För att undvika problemet kan du:
  • Ge Office-programmet fokus genom att ändra det andra argumentet för funktionen Shell till antingen vbMinimizedFocus, vbMaximizedFocuseller vbNormalFocus.
  • Ge ditt Visual Basic-formulär fokus.
  • Försök med GetObject vid redovisning av Office-programmets laddnings tid.
Denna åtgärd visar den här lösningen.
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

Lösning för C++

Om du programmerar i C++ visar följande kod exempel en liknande lösning som visas i exemplet ovan. Observera att SetForegroundWindow används för att flytta fokus från Excel så att den kan registrera sina aktiva objekt.
//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();

Referenser


Mer information får du om du klickar på följande artikel nummer och läser artiklarna i Microsoft Knowledge Base:
192919 Automatisera en säkerställd Access-databas med Visual Basic
237338 Fel meddelande med WordMail: "den här metoden eller egenskapen är inte tillgänglig"
240794 Avgöra sökvägen för ett Office-program