PowerShell で PowerPoint 操作
ソースコード
手続き的
$file = "" $target_dir = "" Add-Type -AssemblyName Microsoft.Office.InterOp.PowerPoint $app = New-Object -ComObject PowerPoint.Application $app.Visible = $True $pres = $app.Presentations.open($file) $pres.SaveAs($target_dir, [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::PpSaveAsPNG, $False) $pres.Close() $app.Quit() [gc]::collect() [gc]::WaitForPendingFinalizers() [gc]::collect()
ScriptBlockを利用した形式
function PP_Application($blk) { $app = New-Object -ComObject PowerPoint.Application try { &$blk $app } finally { if ($app -ne $Null) { $app.Quit() [gc]::Collect() [gc]::WaitForPendingFinalizers() [gc]::Collect() } } } function PP_Presentation($app, $filepath, $blk) { $app.Visible = $True $pres = $app.Presentations.Open($filepath) try { &$blk $pres } finally { if ($pres -ne $Null) { $pres.Close() } } } $file = "" $target_dir = "" Add-Type -AssemblyName Microsoft.Office.InterOp.PowerPoint $saveas_type = [Microsoft.Office.InterOp.PowerPoint.PpSaveAsFileType]::PpSaveAsPNG PP_Application { param($app) PP_Presentation $app $file { param($pres) $pres.SaveAs($target_dir, $saveas_type, $False) } }
.NETのガベコレとファイナライザについて
COMオブジェクトは.NET FrameworkにおけるUnmanaged Resourceを取り扱っているのでFinalizerが呼び出されるまで実際の終了処理は行われないようです。
この場合においては
- Quit()が呼ばれる。
- 参照が無くなる。
- Finalization Queueにオブジェクトが追加される。
- Garbage Collect時にオブジェクトが持っているFinalizeメソッドが呼び出される。
- Finalizeメソッドの中でPowerPointのプロセス終了処理が行われる。
という流れになります。
Collect() → WaitForPendingFinalizers() → Collect() という処理は
- 1回目のCollectでFinalize()を呼び出すべきオブジェクトを見つけ、Unmanaged Resourceの解放を実際に行い、
- WaitForPendingFinalizer()ですべてのFinalizeが完了するのを待ち、
- 2回目のCollectでFinalizerを呼ぶことによって発生した参照の無くなったManaged Resourceの解放を行う。
ということをやっています。