2

我正在使用PowerShell通过 COM 自动化一些 excel 任务,通过PowerShell这样的脚本:

$xl = new-object -ComObject Excel.Application
sleep 5
DO THINGS...
$xl.quit()
sleep 5
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
[GC]::collect()

我的问题是,如果我省略第一次调用 to sleep,Excel 将无法执行需要加载项的任务,并且调用 to$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)

4

1 回答 1

4

虽然如果没有像DO THINGS之类的加载项,就无法重现您的确切环境和情况......其中提到的Excel 应用程序对象的某些成员应该能够被利用以获得对应用程序状态的一些了解。

一个似乎可能的候选者是_Application.CalculationState 属性。如果强制进行完全重新计算,然后Do While...: DoEvents: Loop处理 a ,则伪计时器可能会暂停 powershell 脚本,而这与 Internet.Explorer 对象Application.CalculationState不太xlDone一样,直到它完成接收其网页。

$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 应用程序对象开发人员指南的更多信息。

于 2015-09-11T01:28:37.170 回答