Проверьте, завершил ли Excel последовательность запуска / выключения
Я использую PowerShell
автоматизировать некоторые задачи Excel через COM, через PowerShell
Сценарий таков:
$xl = new-object -ComObject Excel.Application
sleep 5
DO THINGS...
$xl.quit()
sleep 5
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
[GC]::collect()
Моя проблема в том, что если я пропущу первый вызов sleep
Excel не будет готов к выполнению задач, требующих надстроек и вызова $xl.quit()
не работает, и процесс не может завершиться, о чем свидетельствуют:
PS > Get-Process EXCEL
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
784 104 104008 109380 944 3.21 5996 EXCEL
Аналогично, если я пропущу второй вызов sleep
Excel не успевает завершить работу, и в итоге это приводит к появлению диалогового окна "Microsoft Excel перестал работать...", и при следующем запуске Excel другое диалоговое окно сообщает "Microsoft Excel не удалось завершить работу правильно, запустить в безопасном режиме?
function XLtest {
$xl = new-object -ComObject Excel.Application
$xl.quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
[GC]::collect()
}
for($i=0;$i -lt 10; $i++){ XLtest } # generates multiple errors
Очевидно, что это проблемы, которых я хочу избежать, но эвристическое решение вызова sleep 5
все еще может потерпеть неудачу в случае Есть ли способ определить, когда Excel завершил свою последовательность запуска и готов к выдаче команд (xl.quit()
в частности) и когда последовательность выключения завершена (т.е. когда можно вызвать [System....Marshal]::ReleaseComObject($xl)
?
1 ответ
Хотя ваше точное окружение и ситуацию невозможно воспроизвести без такой надстройки, как DO THINGS..., как уже упоминалось, есть члены объекта приложения Excel, которые можно использовать для получения некоторого понимания состояния приложения.
Одним из возможных кандидатов является свойство _Application.CalculationState. Если был произведен полный пересчет, то Do While...: DoEvents: Loop
был обработан, псевдо-таймер мог приостановить сценарий powershell, пока Application.CalculationState
не было xlDone
во многом аналогично объекту Internet.Explorer, пока он не завершит получение своей веб-страницы.
$xl = new-object -ComObject Excel.Application
$xl.Calculate
do while $xl.CalculationState <> xlDone: $xl.DoEvents: Loop
$xl.quit()
... (do more things?)
Повторное вычисление также может быть принудительно вызвано свойством _Application.CalculateBeforeSave, если вы сохраняете данные перед закрытием (и последующим выходом).
Другим хорошим кандидатом является более простое свойство _Application.Ready.
$xl = new-object -ComObject Excel.Application
do while not $xl.ready: $xl.DoEvents: Loop
$xl.quit()
Посмотрите Члены приложения (Excel) для полного списка потенциальных свойств, где может быть определено "состояние". Более подробная информация в Руководстве разработчика по объекту приложения Excel 2010.