Ознаки
Під час спроби використовувати GetObject (Microsoft Visual Basic) або getactiveobject (Microsoft Visual C++), щоб автоматизувати програму Microsoft Office, з'являється одне з таких повідомлень про помилку, хоча програма Office працює:
Повідомлення про помилку 1
Помилка під час запуску "429": компонент ActiveX не може створити об'єкт
Повідомлення про помилку 2
Помилка: 0x800401e3 "операцію недоступне"
Причина
Хоча програма Office працює, її не можна зареєструвати в таблиці з запущеними об'єктами (ГНИЛІ). Екземпляр програми Office має бути зареєстрований в області ГНИТТЯ, перш ніж його можна буде приєднати до використання функції GetObject (Visual Basic) або Getactiveobject (Visual C++). Під час запуску програми Office він не одразу зареєструє її запущені об'єкти. Це оптимізує процес запуску програми. Замість того, щоб реєструвати під час запуску, програма Office реєструє її запущені об'єкти в ГНИЛІ після того, як вона втрачає фокус. Тому, якщо ви намагаєтеся скористатися програмою GetObject або getactiveobject , щоб вкласти до запущеного екземпляра програми Office, перш ніж програма втратила фокус, може з'явитися одна з наведених вище помилок.
Спосіб вирішення
Використовуючи код, ви можете змінити фокус із програми Office на власну програму (або іншій програмі), щоб дозволити їй зареєструвати себе в області ГНИТТЯ. Крім того, якщо ваш код запускає exe-файл програми Office, можливо, доведеться зачекати, доки завершиться завантаження програми Office, перш ніж вкласти його в екземпляр запуску. Зразок коду надається як спосіб вирішення в розділі "Додаткові відомості".
Стан
Це зроблено навмисно.
Додаткові відомості
У більшості випадків розробники, які бажають автоматизувати програму Office, повинні використовувати CreateObject (Visual Basic) або Cobreateекземпляра (Visual C++), щоб запустити новий екземпляр програми Office. Однак існують випадки, коли можливо, ви захочете автоматизувати програму Office, яку вже запущено: наприклад, якщо користувач раніше почав програму Office. Або, якщо ви запустили виконуваний код програми Office за допомогою коду, щоб можна було указати Перемикачі командного рядка для програми. Щоб автоматизувати запуск програми Office, потрібно використовувати об'єкт GetObject або getactiveobject.
Дії з відтворення поведінки
-
Запустіть Microsoft Visual Basic і створіть новий стандартний EXE-проект. Form1 створюється за замовчуванням.
-
Додайте елемент керування CommandButton до Form1.
-
Додайте наведений нижче код до модуля коду форми.
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
-
Переконайтеся, що розташування Excel. exe правильна в зразку коду.
-
Закрийте програму Microsoft Excel, якщо вона вже запущена.
-
Натисніть клавішу F5, щоб запустити проект, і натисніть кнопку Command1.
Інші способи вирішення
Щоб вирішити цю проблему, можна виконати наведені нижче дії.
-
Надайте фокус до програми Office, змінивши другий аргумент функції оболонки, щоб вона не була в центрі уваги, абов разі _ _ _ _ фокуса.
-
Надання Visual Basic формі фокуса.
-
Спроба GetObject під час обліку часу завантаження програми Office.
Наведений нижче переглянутий код ілюструє цей спосіб вирішення.
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
Тимчасове рішення для C++
Якщо ви програмували на C++, наведений нижче зразок коду демонструє аналогічне вирішення, що відображається у наведеному вище зразку Visual Basic. Зверніть увагу, що програма Setforegrodwindow використовується для переміщення фокуса від програми Excel, що дає змогу реєструвати її запущені об'єкти.
//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();
Посилання
Щоб отримати докладні відомості, клацніть наведені нижче номери статей, щоб переглянути статті в базі знань Microsoft Knowledge Base:
192919 Як автоматизувати базу даних захищеного доступу за допомогою Visual Basic
237338 Повідомлення про помилку за допомогою WordMail: "цей метод або властивість недоступні"
240794 Визначення шляху для програми Office