Visio VBAの深淵:DropManyによる「シェイプ一括移設」の極致
Visioのオートメーションにおいて、最も忌むべきは「Copy/Paste」という高レベルAPIの多用だ。GUIのクリップボード操作を模倣するこの手法は、UIイベントのトリガーやメモリ上の不要なフラグメントを生成し、数千個単位の図形を扱うシステムにおいては、アプリケーションを「死」へと誘う。
真のエンジニアは、Visioの描画エンジンに対して直接命令を下す。今日は、`DropMany`メソッドを用いた、圧倒的パフォーマンスと堅牢性を備えたシェイプ一括複製術を伝授する。
—
1. なぜ「Copy/Paste」が禁じ手なのか
`Shape.Copy`および`Page.Paste`をループ内で実行することは、以下の悪夢を招く。
- イベントの過負荷: 貼り付けごとに`ShapeAdded`イベントが走る。
- オブジェクト生成コスト: 毎回クリップボードを経由し、COMのマーシャリングオーバーヘッドが積み重なる。
- メモリリークの温床: 複雑なグループ化シェイプを連続コピーすると、Undoスタックが肥大化し、プロセスがクラッシュする。
対して`DropMany`は、マスターシェイプのリストと座標の配列を一括でエンジニアに渡し、Visioの描画スレッドを一気に駆動させる。これは、いわば「バッチ処理」と「対話型処理」の差である。
—
2. DropManyによる高速移設のアーキテクチャ
`DropMany`を使いこなすには、単なる引数の渡し方だけでなく、メモリレイアウトを意識する必要がある。特に、移動先ページへの座標変換と、マスターシェイプの参照保持が肝となる。
実装コード:高性能シェイプ一括移設モジュール
‘ 伝説的なチーフアーキテクトによるDropMany実装例
Public Sub BatchMoveShapes(sourcePage As Visio.Page, targetPage As Visio.Page)
Dim srcShapes As Visio.Shapes
Dim shp As Visio.Shape
Dim i As Long
‘ 1. 配列の確保(メモリの断片化を避けるため最小限に)
Dim count As Long: count = sourcePage.Shapes.count
If count = 0 Then Exit Sub
Dim masters() As Object
Dim posXY() As Double
ReDim masters(0 To count – 1)
ReDim posXY(0 To (count 2) – 1)
‘ 2. オブジェクトの事前キャッシュ
‘ VisioのCOM参照を配列に詰めることで、走査時のオーバーヘッドを排除
For i = 0 To count – 1
Set shp = sourcePage.Shapes(i + 1)
Set masters(i) = shp.Master ‘ マスター参照を取得
posXY(i 2) = shp.Cells(“PinX”).ResultIU
posXY(i 2 + 1) = shp.Cells(“PinY”).ResultIU
Next i
‘ 3. 高速一括配置(DropManyの真髄)
‘ これにより、UI描画更新を最小限に抑え、描画パイプラインをバイパスする
Dim newShapes() As Visio.Shape
targetPage.DropMany masters, posXY, newShapes
‘ 4. 後処理:明示的な参照解放
‘ VBAのガベージコレクションを待たず、即座にリソースを回収する
For i = LBound(masters) To UBound(masters)
Set masters(i) = Nothing
Next i
Debug.Print “移設完了: ” & UBound(newShapes) + 1 & ” 個のシェイプを転送しました。”
End Sub
—
3. シニアエンジニアが意識すべき「極限の知見」
座標系の整合性
`DropMany`はデフォルトでピン位置(PinX/PinY)を基準にする。もし移設先ページの原点(Ruler Origin)が異なる場合、座標系がズレる。必ず`Page.PageSheet`から`XForm`を取得し、オフセットを算出して`posXY`に適用せよ。
Windows APIとの親和性
もし大量のシェイプを処理する際に「Visioが応答なし」になるのを防ぎたいなら、`DoEvents`を安易に呼ぶのではなく、Windows APIの`Sleep`関数を用いて、CPUコアの占有率を適度に制御する設計が望ましい。
‘ CPU負荷を抑えるためのインターバル制御
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)
‘ 処理の合間に Sleep 1 を挟むだけで、OSのタスクスケジューラに対する配慮が可能になる
オブジェクトのライフサイクル管理
`DropMany`で生成された`newShapes`配列は、処理終了後に必ず明示的な解放(`Set = Nothing`)を行うこと。大規模な帳票システムでは、このわずかな解放漏れが数日間の稼働で致命的なメモリリークへと発展する。
—
最後に:レガシーを「資産」に変えるために
Visio VBAは、古臭い言語ではない。適切に設計されたオブジェクトモデルの操作は、現代のどのフレームワークよりも高速にドキュメント生成を完遂する。
「動けば良い」というコードは、数ヶ月後の自分への負債だ。`DropMany`のようなAPIの深淵に触れ、Visioの描画エンジンと対話せよ。それこそが、伝説的なエンジニアが辿る道である。
次は、「イベントシンクを用いた動的シェイプ制御」について掘り下げていく。準備はいいか。
