Príznaky
Pri pokuse o použitie funkcie GetObject (Microsoft Visual Basic) alebo GetActiveObject (Microsoft Visual C++) na automatizáciu aplikácie balíka Microsoft Office sa zobrazí jedno z nasledujúcich chybových hlásení, napriek tomu, že je spustená aplikácia balíka Office:
Chybové hlásenie 1
Chyba spustenia "429": súčasť ActiveX nedokáže vytvoriť objekt
Chybové hlásenie 2
Chyba: 0x800401e3 "operácia nie je k dispozícii"
Príčina
Hoci je aplikácia balíka Office spustená, nemusí byť zaregistrovaná v tabuľke spusteného objektu (ROT). Spustená inštancia aplikácie balíka Office musí byť zaregistrovaná v HNILOBe pred tým, ako môže byť pripojená k používaniu funkcie GetObject (Visual Basic) alebo GetActiveObject (Visual C++). Keď sa aplikácia balíka Office spustí, okamžite sa nezaregistrujú jeho spustené objekty. Týmto sa optimalizuje proces spúšťania aplikácie. Namiesto toho, aby ste sa zaregistrovali pri spustení, aplikácia balíka Office registruje spustené objekty v HNILOBe po tom, ako sa stratí zameranie. Ak sa teda pokúsite použiť funkciu GetObject alebo GetActiveObject na pripojenie k spustenej inštancii aplikácie balíka Office predtým, než sa aplikácia stratí zameranie, môže sa zobraziť niektorá z vyššie uvedených chýb.
Riešenie
Pomocou kódu môžete zmeniť zameranie z aplikácie balíka Office na svoju vlastnú aplikáciu (alebo na inú aplikáciu), aby sa mohla zaregistrovať v HNILOBe. Ak však váš kód spúšťa Súbor exe aplikácie balíka Office, budete musieť počkať na dokončenie načítania aplikácie balíka Office, kým sa nepokúsite pripojiť k spustenej inštancii. Vzorka kódu sa uvádza ako alternatívne riešenie v časti Ďalšie informácie.
Stav
Toto správanie je zámerné.
Ďalšie informácie
Vo väčšine situácií vývojári, ktorí chcú automatizovať aplikáciu balíka Office, potrebujú použiť CreateObject (Visual Basic) alebo CoCreateInstance (Visual C++) na spustenie novej inštancie aplikácie balíka Office. Existujú však prípady, kedy môžete radšej automatizovať aplikáciu balíka Office, ktorá je už spustená: napríklad, ak používateľ predtým spustil aplikáciu balíka Office. Ak ste spustili spustiteľný súbor aplikácie balíka Office s použitím kódu, aby ste mohli zadať prepínače príkazového riadkov pre aplikáciu. Ak chcete automatizovať spustenú aplikáciu balíka Office, musíte použiť funkciu GetObject alebo GetActiveObject.
Postup na reprodukovanie správania
-
Spustite Microsoft Visual Basic a vytvorte nový štandardný projekt EXE. Form1 sa vytvorí na základe predvoleného nastavenia.
-
Pridanie ovládacieho prvku CommandButton na Form1.
-
Do modulu kód formulára pridajte nasledujúci kód.
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
-
Skontrolujte, či je v ukážke kódu správne umiestnenie Excel. exe.
-
Ukončite Microsoft Excel, ak je už spustený.
-
Stlačením klávesu F5 spustite projekt a kliknite na položku Command1.
Alternatívne riešenie
Ak chcete problém obísť, môžete:
-
Zamerajte sa na aplikáciu balíka Office zmenou druhého argumentu funkcie shell buď na vbMinimizedFocus, vbMaximizedFocusalebo vbNormalFocus.
-
Pomenujte svoju vizuálnu základnú formu.
-
Skúste funkciu GetObject pri účtovaní času načítania aplikácie balíka Office.
Tento alternatívny postup znázorňuje Tento revidovaný kód.
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
Alternatívne riešenie pre C++
Ak plánujete programovanie v jazyku C++, v nasledujúcej ukážke kódu sa zobrazuje podobné alternatívne riešenie, ktoré je uvedené v ukážke jazyka Visual Basic. Všimnite si, že SetForegroundWindow sa používa na presun zamerania mimo programu Excel, čo umožňuje zaevidovať jeho spustené objekty.
//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();
Odkazy
Ďalšie informácie získate po kliknutí na nasledovné čísla článkov databázy Microsoft Knowledge Base:
192919 Automatizácia zabezpečenej databázy programu Access pomocou jazyka Visual Basic
237338 Chybové hlásenie s použitím programu WordMail: "Táto metóda alebo vlastnosť nie je k dispozícii"
240794 Určenie cesty aplikácie balíka Office