Visio VBAの限界を突破せよ:GetResultsによる「秒速」データ抽出の極意
Visioでの自動化において、多くのエンジニアが陥る「禁忌」がある。それは、`Shape.CellsU(“Prop.Value”).ResultStr(“”)` をループで回し続けるという過ちだ。
数百個程度のシェイプならまだいい。だが、数千個、数万個のオブジェクトが配置された図面でそれをやれば、CPUはI/O待ちで悲鳴を上げ、処理時間は数分から数十分へと跳ね上がる。Visioのオブジェクトモデルを個別に叩くコストは、あなたが想像する以上に重いのだ。
今日は、プロフェッショナルとして知っておくべき`Page.GetResults`を用いた、次元の異なる高速データ取得手法を伝授する。
—
なぜ「1つずつ取得」が重いのか
Visioの `CellsU` プロパティは、呼び出されるたびに「ドキュメントの内部構造へのアクセス」「セルの解決」「型の変換」というオーバーヘッドを伴う。VBAからVisioエンジンへのコンテキストスイッチがループの回数だけ発生する――これが遅延の正体だ。
対して `Page.GetResults` は、メモリ上で連続した領域を一括で解決する。一度の呼び出しで全データを配列に書き出すため、オーバーヘッドは実質ゼロに近い。
—
実装パターン:Page.GetResultsの極限コード
以下に、実務でそのまま使える堅牢なクラスモジュール風のコードを示す。ここでは `Prop.Label` と `Prop.Value` を全シェイプから一括取得する例を挙げる。
Option Explicit
”’
”’
Public Sub ExtractShapeDataFast()
Dim vsoPage As Visio.Page
Dim vsoShapes As Visio.Shapes
Dim count As Long
Dim i As Long
‘ 取得したいセル名(例: Prop.Label, Prop.Value)
Dim cellNames(0 To 1) As String
cellNames(0) = “Prop.Label”
cellNames(1) = “Prop.Value”
Set vsoPage = ActivePage
Set vsoShapes = vsoPage.Shapes
count = vsoShapes.count
‘ 1. 取得対象のシェイプとセルを定義する配列を準備
Dim srcCells() As Variant
ReDim srcCells(0 To (count 2) – 1)
For i = 1 To count
‘ Page.GetResultsは「シェイプの参照」と「セル名」のペアを要求する
Set srcCells((i – 1) 2) = vsoShapes(i).CellsU(cellNames(0))
Set srcCells((i – 1) 2 + 1) = vsoShapes(i).CellsU(cellNames(1))
Next i
‘ 2. 結果を受け取るための配列を準備(Variantで受けるのが鉄則)
Dim results() As Variant
‘ 3. 一括取得の実行(これが最速のキーポイント)
‘ 引数: セル配列, フラグ, 結果配列, 単位
vsoPage.GetResults srcCells, VisGetResultsFlags.visGetResultsStr, results
‘ 4. データの活用(配列を回す処理はメモリ内なので一瞬で終わる)
For i = 0 To count – 1
Debug.Print “Shape: ” & vsoShapes(i + 1).Name _
& ” | Label: ” & results(i 2) _
& ” | Value: ” & results(i 2 + 1)
Next i
End Sub
—
現場で勝つための「設計の注意点」
1. エラーハンドリングの境界線
`GetResults` は、指定したセルが存在しないシェイプがあるとエラーを吐く。全シェイプに必ずそのプロパティがあるとは限らない場合、事前に `Shape.CellExistsU` で確認するか、エラーが発生しないよう「セルの存在確認」を行うロジックを前段に置くべきだ。
2. メモリとパフォーマンスのトレードオフ
数万個のシェイプを扱う場合、`results` 配列のメモリ消費量も馬鹿にならない。必要以上に広範囲(例えば全ページ)を一度に取得しようとせず、処理単位(1ページごと等)に区切って実行するのが、クラッシュを防ぐアーキテクトの定石だ。
3. DB連携への応用
この手法で取得した配列は、`ADO.Recordset` や `Excel Range` へ一気に書き出すための「中間バッファ」として最適だ。データベースへ保存する場合、個別にSQLを発行するのではなく、`GetResults` でメモリに全展開し、トランザクションを張って一括インサートすることで、ツール全体の実行時間を数分から数秒へと短縮できる。
—
まとめ:エンジニアとしての矜持
「動けばいい」コードを書くのは素人だ。
Visio VBAにおいて、オブジェクトモデルを深く理解し、エンジンの挙動を制御する技術は、そのまま「ビジネスのスピード」に直結する。
`GetResults` を使いこなすことは、単なる高速化ではない。「処理の複雑性をデータ構造に逃がす」というプログラミングの基本原則を、Visioの世界で実践するということだ。
あなたの書くコードが、次のプロジェクトで圧倒的なパフォーマンスを発揮することを期待している。さあ、今すぐ不要なループを削除し、このアーキテクチャに書き換えてくれ。
