Непонятное поведение Excel+GetObject

Обсуждение вопросов клиентского программирования.

Модератор: Duncon

Ответить
Fktrc
Сообщения: 40
Зарегистрирован: 20 фев 2004, 11:22
Откуда: Кемерово
Контактная информация:

Люди умные, объясните, что происходит, ибо "нич-чего не понимаю"(С). Ситуация: WSH 5.6, Excel 2003. Имеется следующий JS-скрипт:

Код: Выделить всё

var Excel;
var WSH = new ActiveXObject("WScript.Shell");

while(!Excel){
   try {
      // пытаемся подключиться к запущенному экземпляру Excel
      Excel = GetObject("", "Excel.Application");
   } catch(a) {
      WScript.Sleep(1000);
   }
}
WScript.Echo("Excel closing...");
Excel.Application.Quit();
Вроде все правильно - в бесконечном цикле ожидаем запуска Excel. Если к нему удалось подключиться, выходим из цикла, выдаем сообщение "Excel closing..." и после его закрытия закрываем Excel. Результаты же запуска скрипта озадачивают не на шутку!

Первый вариант запуска: Сначала запускаем Excel. Затем запускаем скрипт. Он отрабатывает, как и должен - подключается к Excel, выдает сообщение и закрывает Excel.

Второй вариант, ради которого, собсно, и затевался сыр-бор: сначала запускаем скрипт. Он, как и положено, крутится в цикле, периодически пробуя подключиться к Excel. Запускаем Excel. Ждем... (Excel запущен и активен!) еще ждем... и еще ждем... . Нифига. Но стоит переключиться из окна Excel на любое другое окно (да хоть мышкой по панели задач щелкнуть), как тут же выскакиваем окошко "Excel closing...".
То есть такое впечатление, как будто сразу после запуска Excel его OLE сервер неактивен или не создан. Но как только окно Excel теряет фокус, то OLE сервер тут же создается, либо активизируется, позволяя подключиться к себе...

Казалось бы, бред полный. Но факты - упрямая вещь. Кто поопытнее меня, разъясните, в чем замес. А то я уже просто не знаю что и думать...
alex191175
Сообщения: 7
Зарегистрирован: 11 янв 2005, 17:46

А у меня все с точностью до наоборот, решил перенять твой метод под себя, вот что получается(на бейсике):

Код: Выделить всё

Dim Excel
set WshShell = WScript.CreateObject("WScript.Shell") 
KL = True 
do while KL 
  if WshShell.AppActivate("Microsoft Excel") then
    WScript.Sleep 1000
    set Excel = GetObject("", "Excel.Application") 
    WScript.Echo(Excel)
    Excel.Application.Quit() 
    KL = false 
  end if 
loop
скрипт запускаем, он ждет запуска Excel, потом выдает сообщение "MS Excel", и дальше.......ничего не происходит, если же заменить сторку 8 на WScript.Echo(Excel.ActiveWorkBook.Name) пишет , что "требуется объект ActiveWorkBook", в твоем же случае имя книги он сообщает.....такое ощущение, что в твоем случае он видит переменную Excel как объект, а в моем нет, ведь я просто скопировал часть твоего кода в свой , он же по идее должен работать, зато в моем случае решена твоя проблема, он работает на ожидание запуска Excel.....неужели никто не объяснит, почему так происходит! Поэксперементируй с моим вариантом, может додумаешься, у меня не получается.....
Fktrc
Сообщения: 40
Зарегистрирован: 20 фев 2004, 11:22
Откуда: Кемерово
Контактная информация:

Поправил, но у тебя та же ботва, что и у меня вылезла.
Вот правильный код:

Код: Выделить всё

Dim Excel 
set WshShell = WScript.CreateObject("WScript.Shell") 
KL = True 
do while KL 
  if WshShell.AppActivate("Microsoft Excel") then 
    WScript.Sleep 1000 
    WScript.Echo ("Ёксель запущен")
    set Excel = GetObject(, "Excel.Application") 
    WScript.Echo(Excel.ActiveWorkBook.Name) 
    Excel.Application.Quit() 
    KL = false 
  end if 
loop
Надо писать не GetObject("", "Excel.Application"), а GetObject(, "Excel.Application") - почувствуй разницу :)
Но! как только ты закомментируешь строчку "WScript.Echo ("Ёксель запущен")", как скрипт откажется работать, мотивируя, что

Код: Выделить всё

Невозможно создание объекта контейнером ActiveX: GetObject'
Код:	800A01AD
Источник: 	Ошибка выполнения Microsoft VBScript
То есть тут скорее всего та же ботва, что и у меня - сразу после запуска Excel толком непригоден к использованию. Надо переключиться с него на другое приложение, потом сразу на него - тогда заработает. Брэд оф сив кэйбл, бред сивой кобылы, но факт.
Роль приложения, на которое переключаемся, выполняет окошко "WScript.Echo ("Ёксель запущен")", видно поэтому все и работает без сбоев. То есть той полусекунды, на которую Excel теряет фокус, ему хватает.
Дурдом на выезде...
Fktrc
Сообщения: 40
Зарегистрирован: 20 фев 2004, 11:22
Откуда: Кемерово
Контактная информация:

На RSDN.ru подсказали причину такого поведения
MSDN PRB: GetObject or GetActiveObject Cannot Find a Running Office Application Q238610 писал(а):
CAUSE
Although the Office application is running, it might not be registered in the Running Object Table (ROT). A running instance of an Office application must be registered in the ROT before it can be attached to using GetObject (Visual Basic) or GetActiveObject (Visual C++).

When an Office application starts, it does not immediately register its running objects. This optimizes the application's startup process. Instead of registering at startup, an Office application registers its running objects in the ROT once it loses focus. Therefore, if you attempt to use GetObject or GetActiveObject to attach to a running instance of an Office application before the application has lost focus, you might receive one of the errors above.

RESOLUTION
Using code, you can change focus from the Office application to your own application (or to some other application) to allow it to register itself in the ROT. Additionally, if your code is launching the Office application's exe file, you might need to wait for the Office application to finish loading before attempting to attach to the running instance. A code sample is provided as a workaround in the "More Information" section below.

STATUS
This behavior is by design.
mad666
Сообщения: 3
Зарегистрирован: 28 июн 2005, 12:12

может не в тему, но может так set objExcel = CreateObject("Excel.Application"), да и работать с ним?
Ответить