Simptome
Atunci când încercați să utilizați GetObject (Microsoft Visual Basic) sau GetActiveObject (Microsoft Visual C++) pentru a automatiza o aplicație Microsoft Office, primiți unul dintre următoarele mesaje de eroare, chiar dacă aplicația Office rulează:
Mesaj de eroare 1
Eroarea Run-Time ' 429 ': componenta ActiveX nu poate crea un obiect
Mesaj de eroare 2
Eroare: 0x800401e3 "Operațiunea nu este disponibilă"
Cauză
Deși aplicația Office rulează, este posibil să nu fie înregistrată în tabelul obiect care rulează (ROT). O instanță de rulare a unei aplicații Office trebuie să fie înregistrată în putregai înainte să poată fi atașată la utilizarea GetObject (Visual Basic) sau GetActiveObject (Visual C++). Atunci când pornește o aplicație Office, aceasta nu înregistrează imediat obiectele sale în execuție. Acest lucru optimizează procesul de pornire al aplicației. În loc să se înregistreze la pornire, o aplicație Office își înregistrează obiectele care se execută în putregai după ce pierde focalizarea. Prin urmare, dacă încercați să utilizați GetObject sau GetActiveObject pentru a atașa la o instanță curentă a unei aplicații Office înainte ca aplicația să piardă focalizarea, este posibil să primiți una dintre erorile de mai sus.
Rezolvare
Utilizând codul, puteți să modificați focalizarea de la aplicația Office la propria aplicație (sau la altă aplicație) pentru a-i permite să se înregistreze în putregai. În plus, dacă codul lansează fișierul exe al aplicației Office, poate fi necesar să așteptați ca aplicația Office să termine încărcarea înainte de a încerca să atașați la instanța care rulează. Un eșantion de cod este furnizat ca soluție de evitare în secțiunea "mai multe informații".
Stare
Acest comportament este proiectat.
Mai multe informații
În majoritatea situațiilor, dezvoltatorii care doresc să automatizați o aplicație Office trebuie să utilizeze funcția (Visual Basic) sau CoCreateInstance (Visual C++) pentru a lansa o instanță nouă a aplicației Office. Cu toate acestea, există cazuri în care este posibil să preferați să automatizați o aplicație Office care rulează deja: de exemplu, dacă utilizatorul a pornit anterior aplicația Office. Sau, dacă ați lansat executabilul aplicației Office utilizând codul, astfel încât să puteți specifica argumentele din linia de comandă pentru aplicație. Pentru a automatiza aplicația Office care funcționează, trebuie să utilizați GetObject sau GetActiveObject.
Pașii pentru reproducerea comportamentului
-
Porniți Microsoft Visual Basic și creați un nou proiect standard EXE. Form1 este creat în mod implicit.
-
Adăugați un control CommandButton la Form1.
-
Adăugați următorul cod la modulul cod al formularului.
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
-
Asigurați-vă că locația Excel. exe este corectă în eșantionul de cod.
-
Închideți Microsoft Excel dacă rulează deja.
-
Apăsați F5 pentru a executa proiectul și faceți clic pe Command1.
Soluție de evitare
Pentru a rezolva problema, puteți să:
-
Dați atenție aplicației Office modificând al doilea argument al funcției Shell la vbMinimizedFocus, vbMaximizedFocussau vbNormalFocus.
-
Dați focalizarea la forma vizuală.
-
Încercați GetObject în timp ce se calculează timpul de încărcare al aplicației Office.
Următorul cod revizuit ilustrează această soluție.
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ție pentru C++
Dacă programați în C++, următorul exemplu de cod demonstrează o soluție similară cu cea afișată în eșantionul Visual Basic de mai sus. Observați că SetForegroundWindow este utilizat pentru a muta focalizarea în afara Excel, permițându-i să își înregistreze obiectele în execuție.
//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();
Referințe
Pentru informaţii suplimentare, faceţi clic pe următoarele numere de articole pentru a le vizualiza în Baza de cunoştinţe Microsoft:
192919 Cum se automatizează o bază de date Access securizată utilizând Visual Basic
237338 Mesaj de eroare utilizând WordMail: "această metodă sau proprietate nu este disponibilă"
240794 Cum se determină calea pentru o aplicație Office