【テクニカル・上級編】一時的な計算用セル(Scratch Section)の活用:ShapeSheetのワークエリアをVBAで動的作成・破棄する手法 – Visio VBA解析バイブル

スポンサーリンク

序文:ShapeSheetという名の「演算回路」を掌握せよ

Visioを単なる作図ツールと捉えているうちは、真の自動化エンジニアとは呼べない。卓越したアーキテクトにとって、Visioの真価はその背後に潜むShapeSheetという名の「スプレッドシート型演算エンジン」にある。

多くの開発者は、複雑な座標計算やプロパティの連動をVBAのロジックのみで解決しようとする。しかし、それは大きな過ちだ。VBAとShapeSheet間のCOMインターフェースを跨ぐ呼び出し(Inter-process Communicationのオーバーヘッド)は、数千個のシェイプを扱う大規模システムにおいて、致命的なパフォーマンス低下を招く。

ここで登場するのが、Scratch Section(スクラッチ・セクション)だ。
これはシェイプ内に動的に確保できる「計算用レジスタ」であり、複雑な中間演算をシェイプ内部の高速な計算エンジンに委ねるための聖域である。本稿では、このScratch SectionをVBAから動的に生成・活用・破棄する「極限の動的演算手法」を伝授する。

1. Scratch Section:隠蔽されたワークエリアの構造

Scratch Sectionは、他のセクション(GeometryやUser-defined Cells)とは異なり、通常はユーザーの目には触れない。1つの行につき、X, Y, A, B, C, Dの計6つの汎用データ列を保持できる。

なぜここを使うのか? 理由は3つある。

1. カプセル化: 一時的な計算式をGeometryセクションやUser定数に書き込むと、既存のロジックを破壊するリスクがある。
2. 型変換の自動化: ShapeSheetエンジンは、単位(mm, deg, pt)の変換をVBAよりも遥かに正確かつ高速に処理する。
3. 揮発性: 計算が終わればセクションごと消去すれば良い。ドキュメントの肥大化を防ぎ、クリーンな状態を維持できる。

2. 実装:動的計算スタックの構築

以下に示すコードは、単なるサンプルの域を超えた、プロダクション環境に耐えうる「計算用サンドボックス」の構築ロジックである。Windows APIを用いた高精度タイマーによる計測を加え、パフォーマンスの重みを可視化する。

高精度タイマーと動的操作のコア・ロジック

Option Explicit

‘ Windows APIによる高精度パフォーマンス計測
Private Declare PtrSafe Function QueryPerformanceCounter Lib “kernel32” (lpPerformanceCount As Currency) As Long
Private Declare PtrSafe Function QueryPerformanceFrequency Lib “kernel32″ (lpFrequency As Currency) As Long

”’

”’ シェイプのScratchセクションを利用して、複雑な座標変換を高速に実行する
”’

Public Sub ExecuteHighSpeedCalculation(ByVal targetShape As Visio.Shape)
Dim startCount As Currency, endCount As Currency, freq As Currency
QueryPerformanceFrequency freq
QueryPerformanceCounter startCount

‘ 1. セクションの動的追加
‘ visSectionScratch = 6
Dim scratchIdx As Integer
If Not targetShape.SectionExists(visSectionScratch, False) Then
scratchIdx = targetShape.AddSection(visSectionScratch)
End If

‘ 2. 行の追加 (visRowScratch = 0)
Dim rowIdx As Integer
rowIdx = targetShape.AddRow(visSectionScratch, visRowLast, visTagDefault)

‘ 3. 計算式の流し込み
‘ 例:シェイプの幅の30%の位置から、特定の角度(45度)で100mm進んだ位置のX座標を計算
‘ ShapeSheet関数を直接利用することで、VBAでの三角関数計算を回避
targetShape.CellsSRC(visSectionScratch, rowIdx, visScratchA).FormulaForceU = “Width 0.3”
targetShape.CellsSRC(visSectionScratch, rowIdx, visScratchB).FormulaForceU = “100mm COS(45deg)”

‘ 結果を取得(内部ユニットのままでなく、明示的に単位を指定して取得可能)
Dim resultX As Double
resultX = targetShape.CellsSRC(visSectionScratch, rowIdx, visScratchA).Result(visMillimeters) + _
targetShape.CellsSRC(visSectionScratch, rowIdx, visScratchB).Result(visMillimeters)

Debug.Print “計算結果 (X座標): ” & resultX & ” mm”

‘ 4. 破棄:計算が終われば証拠を隠滅する
‘ これにより、シェイプのデータ構造をクリーンに保ち、保存時のファイルサイズ増大を防ぐ
targetShape.DeleteRow visSectionScratch, rowIdx

QueryPerformanceCounter endCount
Debug.Print “処理時間: ” & Format$((endCount – startCount) / freq, “0.000000”) & ” 秒”
End Sub

3. チーフアーキテクトが教える「最適化の急所」

メモリとライフサイクルの管理

VBAでVisioを操作する際、最も重い処理は `ActivePage` や `ActiveWindow` へのアクセスだ。ループ内でこれらを参照することは、プロフェッショナルとして許されない。必ず、最上位の `Application` オブジェクトから、 `Document` -> `Page` -> `Shape` とオブジェクト変数を明示的に保持し、再利用すること。

また、`FormulaForceU` を使用している点に注目してほしい。`Formula` プロパティはローカライズされた関数名(日本語環境なら日本語の関数名)を期待するが、これは移植性を著しく損なう。常に Universal Syntax (U-Property) を使うのが、グローバル環境で動作するシステムの鉄則である。

大規模処理における「計算の分離」

数千個のシェイプに対して動的なScratch操作を行う場合、一時的に `Application.ScreenUpdating = False` を指定するのは基本だが、それだけでは不十分だ。`Application.DeferRecalc = True` を設定し、一連のScratch行の構築が終わるまでシェイプの再計算をサスペンドさせることで、さらに20〜30%のパフォーマンス向上が見込める。

4. レガシー環境と最新アーキテクチャの橋渡し

20年以上続くVisioのアーキテクチャにおいて、Scratch Sectionは「不変の安定性」を誇る。.vsdx形式に移行した現在でも、内部のXMLスキーマにおける `Scratch` セクションの扱いは極めて軽量だ。

.NET (C#) からVisioを制御する場合でも、この手法は有効である。COM Interopの回数を減らすために、複雑なロジックを1つの大きな `Formula` 文字列としてScratchセルに書き込み、一括で結果を読み取る手法は、現代のシステム連携においても「最適解」の一つといえる。

結言:美しさは内部構造に宿る

優れた図形システムとは、見た目が美しいだけでなく、その内部構造(ShapeSheet)が論理的かつ効率的に整理されているものを指す。

VBAからScratch Sectionを動的に操る技術は、まさに「外科手術」のようなものだ。必要なときにだけ最小限のメスを入れ、目的を達したら速やかに縫合(破棄)する。このストイックなまでのリソース管理こそが、レガシーをモダンへと昇華させるチーフアーキテクトの矜持である。

現場で泥臭くコードを書き続けるシニアエンジニア諸氏には、ぜひこの「動的Scratch活用」を武器に、Visio自動化の限界に挑戦していただきたい。

タイトルとURLをコピーしました