Testez si Excel a terminé sa séquence de démarrage / arrêt

J'utilise PowerShell pour automatiser certaines tâches Excel via COM, via un script PowerShell manière suivante:

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

Mon problème est que si je supprime le premier appel à sleep , Excel ne sera pas prêt à effectuer des tâches nécessitant des compléments et l'appel à $xl.quit() ne fonctionne pas et le process ne parvient pas à quitter, comme en témoignent:

 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 

De même, si je supprime le deuxième appel à l' sleep , Excel n'a pas le time de terminer l'arrêt et, finalement, il en résulte une boîte de dialog indiquant "Microsoft Excel a cessé de fonctionner …" et la prochaine fois que Excel démarre, un autre la boîte de dialog indique "Microsoft Excel n'a pas réussi à fermer correctement, Démarrer en mode sans échec?"

 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 

Évidemment, ce sont des problèmes que je veux éviter, mais la solution heuristique de l'appel du sleep 5 pourrait encore échouer à l'occasion. Existe-t-il un moyen de détecter quand Excel a terminé sa séquence de démarrage et est prêt à émettre des commands ( xl.quit() en particulier) et lorsque la séquence d'arrêt est terminée (c.-à-d. Lorsqu'il est correct d'appeler [System....Marshal]::ReleaseComObject($xl) ?

Bien que votre environnement et votre situation exacte soient impossibles à reproduire sans un complément tel que DO THINGS … mentionné, il existe des membres de l' object Application Excel qui devraient être exploités pour avoir un sens de l'état de l'application.

Un qui semble être un candidat probable est la propriété _Application.CalculationState . Si un recalcul complet a été forcé, alors, Do While...: DoEvents: Loop été traitée, un pseudo-minuteur pourrait faire une pause sur le script du xlDone alors que l' Application.CalculationState n'était pas xlDone identique qu'un object Internet.Explorer est attendu jusqu'à ce qu'il finisse de recevoir sa page Web.

 $xl = new-object -ComObject Excel.Application $xl.Calculate do while $xl.CalculationState <> xlDone: $xl.DoEvents: Loop $xl.quit() ... (do more things?) 

Un recalage peut également être forcé avec la propriété _Application.CalculateBeforeSave si vous enregistrez avant la fermeture (et ensuite la sortie).

Un autre bon candidat est la propriété _Application.Ready plus simple.

 $xl = new-object -ComObject Excel.Application do while not $xl.ready: $xl.DoEvents: Loop $xl.quit() 

Voir Membres de l'application (Excel) pour une list complète des propriétés potentielles où un «état» peut être déterminé. Plus d'informations sur le Guide du développeur de l'object d'application Excel 2010 .