Проверьте, завершил ли 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()

Моя проблема в том, что если я пропущу первый вызов sleepExcel не будет готов к выполнению задач, требующих надстроек и вызова $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

Аналогично, если я пропущу второй вызов sleepExcel не успевает завершить работу, и в итоге это приводит к появлению диалогового окна "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.

Другие вопросы по тегам