Logga in med Microsoft
Logga in eller skapa ett konto.
Hej,
Välj ett annat konto.
Du har flera konton
Välj det konto som du vill logga in med.

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 felmeddelanden, även om Office-programmet körs:

Felmeddelande 1

Körningsfel 429:
ActiveX-komponenten kan inte skapa objekt

Felmeddelande 2

Fel: 0x800401e3 "Åtgärden är inte tillgänglig"

Orsak

Även om Office-programmet körs kanske det inte är registrerat i rot -tabellen (Running Object Table). En aktiv instans av ett Office-program måste registreras i ROT innan den kan kopplas till med GetObject (Visual Basic) eller GetActiveObject (Visual C++).

När ett Office-program startas registreras inte omedelbart dess löpande objekt. Detta optimerar programmets startprocess. I stället för att registrera sig vid start registrerar ett Office-program sina löpande objekt i ROT när fokus försvinner. Om du försöker använda GetObject eller GetActiveObject för att bifoga till en aktiv instans av ett Office-program innan programmet har tappat fokus kan du därför få något av felen ovan.

Lösning

Med hjälp av kod kan du ändra fokus från Office-programmet till ditt eget program (eller till något annat program) så att det kan registrera sig själv i ROT. Om koden startar Office-programmets exe-fil kan du dessutom behöva vänta tills Office-programmet slutför inläsningen innan du försöker bifoga till den pågående instansen. Ett kodexempel tillhandahålls som en lösning i avsnittet "Mer information".

Status

Detta är avsiktligt.

Mer information

I de flesta situationer 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.

Det finns dock fall där du kanske föredrar att automatisera ett Office-program som redan körs: till exempel om användaren tidigare startade Office-programmet. Eller om du startade Office-programmets körbara fil med hjälp av kod så att du kan ange kommandoradsväxlar för programmet. För att automatisera Office-programmet som körs måste du använda GetObject eller GetActiveObject.

Steg för att reproducera beteendet

  1. Starta Microsoft Visual Basic och skapa ett nytt Standard EXE-projekt. Formulär1 skapas som standard.

  2. Lägg till en CommandButton-kontroll i Formulär1.

  3. Lägg till följande kod i formulärets kodmodul.

    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. Kontrollera att platsen för Excel.exe är korrekt i kodexemplet.

  5. Avsluta Microsoft Excel om det redan körs.

  6. Tryck på F5 för att köra projektet och klicka på Kommando1.

Lösning

Du kan kringgå problemet genom att:

  • Fokusera på Office-programmet genom att ändra det andra argumentet för funktionen Kör till vbMinimizedFocus, vbMaximizedFocus eller vbNormalFocus.

  • Ge Visual Basic-formuläret fokus.

  • Försök med GetObject medan du tar hänsyn till Office-programmets inläsningstid.

Följande ändrade kod illustrerar 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 If
End Sub

Lösning för C++

Om du programmerar i C++, visar följande kodexempel en liknande lösning som i ovanstående Visual Basic-exempel. Observera att SetForegroundWindow används för att flytta fokus från Excel, så att det kan registrera sina löpande 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

Om du vill ha mer information klickar du på följande artikelnummer för att visa artikeln:

Så här hittar du installationssökvägen för ett Office-program

Behöver du mer hjälp?

Vill du ha fler alternativ?

Utforska prenumerationsförmåner, bläddra bland utbildningskurser, lär dig hur du skyddar din enhet med mera.

Communities hjälper dig att ställa och svara på frågor, ge feedback och få råd från experter med rika kunskaper.

Hade du nytta av den här informationen?

Hur nöjd är du med språkkvaliteten?
Vad påverkade din upplevelse?
Genom att trycka på skicka, kommer din feedback att användas för att förbättra Microsofts produkter och tjänster. IT-administratören kan samla in denna data. Sekretesspolicy.

Tack för din feedback!

×