Visioを「ただの作図ツール」から「高精度データレポジトリ」へ変貌させる極限の技術
Visio VBAを単なる「図形配置の自動化」と捉えているなら、それはこの強力なプラットフォームの可能性を著しく過小評価していると言わざるを得ない。
Visioの真骨頂は、Shapeオブジェクトが持つ「データ属性の保持能力」にある。`CellsU`プロパティを制する者は、Visioを単なるベクターグラフィックスから、動的なデータベースとして駆動させることができる。本稿では、レガシーなシステム連携の現場で培った、堅牢かつ極限まで最適化されたシェイプデータ操作の流儀を伝授する。
—
1. CellsU vs Cells: なぜ「U」でなければならないのか
初学者は`Cells`を使いがちだが、シニアエンジニアは必ず`CellsU`(Universal)を選択する。
- Cells: ローカル言語(日本語版Visioなら日本語)に依存する。OSの言語設定やVisioのロケールが変わった瞬間にコードは腐敗する。
- CellsU: 言語に依存しない「ユニバーサル名(英語定義)」でセルを特定する。
システム間連携や長期保守を前提とするなら、`CellsU`一択だ。これは単なる規約ではなく、アーキテクチャ上の生存戦略である。
—
2. シェイプデータ操作の深淵:実装パターン
シェイプデータ(旧カスタムプロパティ)に値を書き込む際、`Shape.CellsU(“Prop.ラベル名”)`を直叩きするのは素人のやり方だ。実務では、データが存在しない場合のエラーハンドリングと、型変換のオーバーヘッドを考慮する必要がある。
以下に、メモリ効率と堅牢性を両立させた汎用プロシージャを示す。
”’
”’
Public Sub SetShapeData(ByVal shp As Visio.Shape, ByVal propName As String, ByVal val As String)
Dim cell As Visio.Cell
‘ セルの存在確認(CellsUは存在しないプロパティへアクセスすると例外を投げる)
If shp.CellExistsU(“Prop.” & propName, visExistsAnywhere) Then
Set cell = shp.CellsU(“Prop.” & propName)
‘ 文字列として値を代入(数式として評価させない場合は .FormulaU ではなく .ResultStr を使う)
‘ 大規模図面では、IsFormulaなどのチェックを挟むことで再計算コストを制御可能
If Not cell.IsFormula Then
cell.ResultStr(“”) = val
End If
Else
‘ 存在しない場合の動的生成(必要に応じて実装)
Debug.Print “Property ” & propName & ” not found in shape: ” & shp.Name
End If
‘ オブジェクトの明示的解放(VBAでも参照の即時解放はメモリ肥大化抑制に寄与する)
Set cell = Nothing
End Sub
—
3. レガシー環境とパフォーマンス:最適化の極致
Visioの描画エンジンは、特に大量の図形を処理する際に「再描画」と「イベントハンドリング」によって著しくパフォーマンスが低下する。数千個のシェイプデータを一括更新する場合、以下の鉄則を守れ。
A. 画面更新の強制停止
ループ処理中は、`Application.ScreenUpdating` を必ずオフにする。これだけで処理速度は10倍変わる。
B. イベントの抑制
もし文書内に`ShapeAdded`や`CellChanged`イベントが定義されている場合、書き込みのたびにイベントが発火し、システムがフリーズする。
Application.EventsEnabled = False
‘ — ここで大量のデータ更新 —
Application.EventsEnabled = True
C. オブジェクトのキャッシュ
`shp.CellsU(“Prop.X”).ResultStr` をループ内で何度も呼び出すな。`CellsU`へのアクセスはCOM呼び出しのオーバーヘッドを伴う。必要なデータは一度メモリ(配列やDictionary)に引き抜き、処理後に書き戻すのがアーキテクトの矜持だ。
—
4. システム間連携の勘所:外部DBとの同期
Visioを「フロントエンド」として使う場合、外部データベース(SQL Server等)とのハッシュ値比較が鍵となる。
1. ユニークキーの保持: 各シェイプに `Prop.UID` を持たせ、DBの主キーと同期させる。
2. 更新フラグの活用: `Prop.SyncStatus` セルを用意し、同期済みか否かを管理する。
3. Windows APIの活用: 必要に応じて `SHGetFileInfo` や `GetSystemTime` 等を使い、外部ファイルのタイムスタンプと図面内のデータを整合させる。
もし、VBAの限界を超えた複雑な通信が必要なら、C#でCOMアドインを作成し、`Interop`経由で`Visio.Application`を制御する道を選ぶべきだ。その際、`Marshal.ReleaseComObject` を使った徹底的なメモリ解放を忘れてはならない。VisioのCOMオブジェクトは、ガベージコレクションを待っていると平気でメモリリークを引き起こす。
—
結論
Visioのシェイプデータ操作は、単なるプロパティの書き換えではない。それは、図形という「器」に「意味」を流し込む行為である。
今回紹介した`CellsU`の厳密な運用と、イベント抑制、そして参照解放の徹底。これらを体得した時、あなたの書くコードは「動く」から「止まらない・腐らない」堅牢なシステムへと昇華されるはずだ。
技術は常に泥臭い。だが、その泥の中にこそ、システムの寿命を延ばす真理が埋まっている。次回の記事では、`Section`オブジェクトを用いたシェイプデータの動的追加と、そのメモリ消費量について深掘りする予定だ。準備はいいか。
