【テクニカル・上級編】【上級者向け】SQL Serverから取得したデータに基づき、テンプレートから動的に図面を生成・保存するパイプライン – Visio VBA解析バイブル

スポンサーリンク

Visio VBAの深淵:SQL Server連動による「動的図面生成パイプライン」の構築

エンジニア諸君。Visioのオートメーションにおいて、「コードが動く」ことと「システムが死なない」ことの間には、深い溝がある。

多くの者がDAOやADOを叩き、`Application.Documents.Open` を繰り返してメモリをリークさせ、結果としてVisioのプロセスを肥大化させ、最終的にハングアップする。これはプロフェッショナルの仕事ではない。

今回は、エンタープライズの現場で「止まらない、汚さない、速い」自動化を実現するための、Visio図面生成アーキテクチャの核心を伝授する。

—

1. アーキテクチャの鉄則:プロセス分離とリソース管理

VisioのCOMオブジェクトは極めて脆い。特にVSDX形式は内部がXML(OPCパッケージ)であるため、不適切なインスタンス生成はメモリ解放の遅延を招く。

核心となる設計指針

  • Late Binding(遅延バインディング)の回避: `Object`型での宣言は、開発時の利便性と引き換えに実行時の型チェックコストを支払う。`Microsoft Visio 16.0 Type Library` を参照し、明示的に型を定義せよ。
  • Object Lifecycleの制御: ループ内で`Set obj = Nothing`を呼ぶだけでは不十分だ。`.Close`メソッドの後に明示的なガベージコレクションを意識した参照解放を行う。
  • DAO/ADOの分離: データベース接続ロジックをVBAのモジュールに直接書くな。可能であればVB.NETでCOMラッパーDLLを作成し、VBAから呼び出すのが「エンタープライズ」の流儀だ。

—

2. 実装:SQL Server連動・動的生成パイプライン

以下は、テンプレートをベースにSQL Serverから取得したノード情報を配置する、堅牢な生成プロセスの雛形である。

Option Explicit

‘ メモリ管理の定石:グローバルスコープでのオブジェクト保持を避ける
Public Sub GenerateDiagramFromSQL()
Dim vApp As Visio.Application
Dim vDoc As Visio.Document
Dim vPage As Visio.Page
Dim conn As Object ‘ ADODB.Connection
Dim rs As Object ‘ ADODB.Recordset

‘ プロセス起動の最適化(画面更新を停止)
Set vApp = New Visio.Application
vApp.ScreenUpdating = False
vApp.AlertResponse = 7 ‘ ダイアログを自動で「いいえ」または非表示に

On Error GoTo Cleanup

‘ データベース接続(接続文字列は環境変数/外部ファイルから読み込むこと)
Set conn = CreateObject(“ADODB.Connection”)
conn.Open “Provider=SQLOLEDB;Data Source=SERVER;Initial Catalog=DB;Integrated Security=SSPI;”
Set rs = conn.Execute(“SELECT ShapeID, X, Y, Label FROM Dim_Shapes”)

‘ テンプレートから新規作成
Set vDoc = vApp.Documents.Add(“C:\Templates\BaseTemplate.vstx”)
Set vPage = vDoc.Pages(1)

‘ シェイプ配置ループ
Do While Not rs.EOF
Call PlaceShape(vPage, rs!X, rs!Y, rs!Label)
rs.MoveNext
Loop

‘ 保存とPDF出力
vDoc.SaveAs “C:\Output\Result_” & Format(Now, “yyyymmdd_hhnn”) & “.vsdx”
vDoc.Export “C:\Output\Result.pdf”

Cleanup:
‘ 明示的な終了処理
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
If Not conn Is Nothing Then conn.Close: Set conn = Nothing
If Not vDoc Is Nothing Then vDoc.Close False: Set vDoc = Nothing

vApp.ScreenUpdating = True
vApp.Quit
Set vApp = Nothing

If Err.Number <> 0 Then MsgBox “Error: ” & Err.Description, vbCritical
End Sub

Private Sub PlaceShape(page As Visio.Page, x As Double, y As Double, label As String)
‘ テンプレート内のマスターシェイプをドロップ
Dim shp As Visio.Shape
Set shp = page.Drop(page.Application.Documents(“Stencil.vssx”).Masters(“Node”), x, y)
shp.Text = label
End Sub

—

3. レガシー環境を生き抜くための極限の知見

Windows APIによる「強制終了」の回避

Visioがフリーズした際、タスクマネージャーに頼るな。`user32.dll` の `GetWindowThreadProcessId` を使い、特定の図面ウィンドウだけをPIDから特定して終了させる設計を組み込むのが、真の管理者だ。

PDF出力の罠

`Export`メソッドは、時としてVisioのレンダリングエンジンと競合する。大規模な図面の場合、一度`.SaveAs`でVSDXを確定させてから、`PrintOut`メソッドで「Microsoft Print to PDF」へリダイレクトする手法の方が、カラープロファイルの崩れやフォント欠けを回避できる確率は高い。

パフォーマンスを極める

シェイプが数千個を超える場合、`Drop`メソッドは遅すぎる。
1. グループ化: シェイプを個別にDropせず、XML構造を直接書き換えるアプローチ(VSDXの裏側を直接操作する)も選択肢に入れよ。
2. イベント抑制: `vApp.EventEnabled = False` を活用し、シェイプ配置ごとの再描画や計算をすべて停止させること。これだけで処理速度は3倍以上変わる。

—

結びに代えて

自動化とは、単に手作業をコードに置き換えることではない。「システムが本来持っているはずの安定した挙動を、エンジニアが管理下に置くこと」である。

もし君がこのコードをコピー&ペーストするだけでなく、なぜ`ScreenUpdating`を落とすのか、なぜ`Nothing`代入が不可欠なのかを理解したなら、君もまた、レガシーという名の戦場で生き残る資格がある。

次の設計では、この「パイプライン」をさらに拡張し、非同期処理によるキューイングまで視野に入れてみてほしい。健闘を祈る。

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