noise

計算機科学や各種設定のメモ

PowerShell で PowerPoint 操作

目的

PPTファイルからPNG画像への変換スクリプトです。

ソースコード

手続き的
$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が呼び出されるまで実際の終了処理は行われないようです。
この場合においては

  1. Quit()が呼ばれる。
  2. 参照が無くなる。
  3. Finalization Queueにオブジェクトが追加される。
  4. Garbage Collect時にオブジェクトが持っているFinalizeメソッドが呼び出される。
  5. Finalizeメソッドの中でPowerPointのプロセス終了処理が行われる。

という流れになります。

Collect() → WaitForPendingFinalizers() → Collect() という処理は

  1. 1回目のCollectでFinalize()を呼び出すべきオブジェクトを見つけ、Unmanaged Resourceの解放を実際に行い、
  2. WaitForPendingFinalizer()ですべてのFinalizeが完了するのを待ち、
  3. 2回目のCollectでFinalizerを呼ぶことによって発生した参照の無くなったManaged Resourceの解放を行う。

ということをやっています。