UWSCでPowerPointのスライドをセクションを指定して抜き出す→動画保存

表題のとおりです。PowerPointの既存スライドから特定セクションのスライドを抜き出して保存します。
詳しいソースはGithubに上げてあるので、興味がある人は見てください。

 * [UWSCScripts/PowerPoint/PickupSection.uws](https://github.com/TakamiChie/UWSCScripts/blob/master/PowerPoint/PickupSection.uws)

# コツ
PowerPointのOLEオブジェクトは、"PowerPoint.Application"で取得できます。VBAマクロとしてプレゼンファイルに書くと

 * プレゼンテーションそのものとマクロが紐付いてしまう(マクロがファイル内に記録されてしまう)
 * プレゼンテーションをpptmで保存しなければならなくなる

ということで、自分は基本的に外部からOLEオブジェクトを使用してOfficeマクロを書いています。
あえてUWSCにする理由は

 * 起動済みのPowerPointオブジェクトを指定してオブジェクト化する、`GETACTIVEOLEOBJ'関数がある
 * セレクトボックスなどのごく簡易的なGUIが揃っている

ということで、今回はUWSCを使ってPowerPointのスライドを叩くことにしました。

# 必要なメソッドとか。
プレゼンテーション内のセクションに関する情報を得る場合は、Presentation.SectionProperties()オブジェクトを使用します。このオブジェクトは他のオブジェクトと違ってコンテナ構造になっていないため、

 * SectionProperties.Countプロパティでセクションの数を取得
 * SectionProperties.Name()メソッドでセクションの名前を取得
 * SectionProperties.FirstSlide()メソッドでセクションの先頭スライドのスライド番号を取得
 * SectionProperties.SlidesCount()メソッドでセクション内のスライド個数を取得

という形となります。
最初のスライドとセクション内のスライド数がわかったら、あとはSlides.Range()メソッドでセクションをすべて選択し、Copyメソッドを呼べばOK。
新しいプレゼンテーションファイルを作って貼り付け、Presenration.CreateVideo()メソッドで保存すればOK。

# というわけでコード。

というわけでコードです。今回はPowerPointに関する定型的な処理をとりあえずモジュール化しました。

```uwsc:PPT.uws
//
// PowerPoint関係の処理を詰め込んだモジュール
//
MODULE PPT

  DIM app

  //
  // コンストラクタ
  //
  PROCEDURE PPT()
    COM_ERR_IGN
    app = GETACTIVEOLEOBJ( "PowerPoint.Application")
    COM_ERR_RET    
    IF COM_ERR_FLG THEN app = NULL
  FEND

  //
  // PowerPointオブジェクトを取得する
  // 戻り値…PowerPoint。開かれていなかった場合NULL
  //
  FUNCTION GET()
    RESULT = app
  FEND

  //
  // 開いている全てのPowerPointファイルの中から一つを選択して返す
  // 戻り値…選択されたPowerPointファイル。
  //   PowerPointが開いていない場合、選択がキャンセルされた場合はNULLを返す
  //
  FUNCTION CHOICEPRESENTATION()
    DIM app = GET()
    DIM files[0]
    COM_ERR_IGN
    DIM count = GETOLEITEM( app.presentations )
    COM_ERR_RET
    IFB count <= 0 OR COM_ERR_FLG THEN
      RESULT = NULL
    ELSE
      RESIZE(files, count)
      FOR i = 0 TO count - 1
        files[i] = ALL_OLE_ITEM[i].name
      NEXT
      // ファイルを選択
      DIM file = SLCTBOX(SLCT_CMB + SLCT_STR, 0, "ファイルを選択", files)

      IF file = "-1" THEN RESULT = NULL ELSE RESULT = app.presentations(file)
    ENDIF
  FEND

  //
  // プレゼンテーションの中からセクションを選択する
  // presentation…セクションを検索するプレゼンテーションファイル
  // 戻り値…選択されたセクションのインデックス
  //   セクションが無い場合は-1、選択がキャンセルされた場合は-2を返す
  //
  FUNCTION CHOICESECTION(presentation)
    DIM sections[0]
    DIM count = presentation.sectionProperties.count
    IFB count <= 0 THEN
      RESULT = -1
    ELSE
      RESIZE(sections, count)
      FOR i = 1 TO count
        sections[i] = presentation.sectionProperties.name(i)
      NEXT
      // セクションを選択
      DIM sel = SLCTBOX(SLCT_CMB + SLCT_NUM, 0, "セクションを選択", sections)

      IF sel = "-1" THEN RESULT = -2 ELSE RESULT = sel
    ENDIF
    
  FEND
ENDMODULE
```

```uwsc:SaveMovieAtSection.uws
//
// 指定ファイル内の選択したセクションを抜き出し、動画として保存
//
CALL PPT.uws
DIM app = PPT.GET()

// プレゼンテーション・セクションを選択
DIM file = PPT.CHOICEPRESENTATION()

IF file = NULL THEN EXIT
DIM index = PPT.CHOICESECTION(file) + 1
IF index <= 0 THEN EXIT
// 最初と最後のスライド番号を取得
DIM first = file.sectionProperties.firstSlide(index)
DIM count = file.sectionProperties.slidesCount(index)
DIM name = file.sectionProperties.name(index)
DIM last = first + count - 1
PRINT "Pickup:" + first + " TO " + last
// コピー
DIM newppt = app.presentations.add(TRUE)
DIM r = SAFEARRAY(1, count)
FOR i = 1 TO count
  r[i] = first + i - 1
NEXT
file.slides.range(r).copy()
newppt.slides.paste()
//
newppt.createVideo(GET_CUR_DIR + "\" + name + ".mp4", -1)
PRINT name + ".mp4 Save End!"
```

とりあえず注意すべき所はふたつかな。

## Slides.Range()メソッド
Slides.Range()メソッドの引数は、VBArrayです。、UWSCではSafeArrayになります。格納する値もコピーするスライドの最初と最後のスライドインデックスから、選択するスライドのインデックスをすべて指定になりますので、注意が必要です。

## Presentation.CreateVideoメソッド

Presentation.CreateVideoメソッドの第二引数は、各スライドに指定した画面切り替えのタイミングを使うかどうかで、データ型はBooleanです。
しかしこの場合、TRUEまたはFALSEではなく、数値を指定します。-1がTrueで、それ以外がFalse。確かこの辺はVBの伝統ですね。


ほかはたぶんUWSCの基礎がわかっていれば迷うことはなさそう。