【入門編】【上級者向け】ページ追加・削除イベントをフックし、変更履歴を自動的にテキストログへ追記する監査ログシステム – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

「記録」から「制御」へ。Visio VBAで「見えない守護神(監査ログ)」を構築する技術

こんにちは。Visio VBAの深淵へようこそ。

皆さんは、マクロの記録機能を使って「あ、これ自動化できるな」と感じたことはありませんか?
もちろん、マクロの記録は素晴らしい第一歩です。しかし、そこから一歩踏み出し、「ユーザーが何かをした瞬間に、システムが自動で反応する」という領域に足を踏み入れたとき、あなたのエンジニアとしての視界は劇的に開けます。

今日は、単なる作業の自動化を超えた、「システムの監視と監査」という高度なテーマに挑戦しましょう。
テーマは、「ページが追加・削除された瞬間に、その履歴をテキストファイルに自動記録する監査ログシステム」です。

これを作る過程で、VBAの最重要概念の一つである「クラスモジュールによるイベントハンドリング」と、初心者が必ず躓く「オブジェクトの生存期間(ライフサイクル)」の本質をマスターしていただきます。

ここをクリアすれば、あなたは「ツールを作る人」から「システムを設計する人」へと進化できるはずですよ。

1. なぜ「普通のモジュール」ではいけないのか?

まず、設計思想の話をしましょう。

通常のマクロ(標準モジュール)は、あなたが「実行ボタン」を押したときにだけ動きます。いわば、「命令待ちの作業員」です。

しかし、今回やりたいことは違います。
「ユーザーが勝手にページを消した」「新しいページを作った」という、ユーザーの動作(イベント)をリアルタイムで検知したいのです。

これを実現するには、常にVisioの動きを背後で見守り続ける「監視役」が必要です。この「監視役」の役割を担えるのが、クラスモジュールなのです。

仕組みのイメージ図

[ ユーザーの操作 ] 
      ↓ (ページ追加!)
[ Visio Application ] 
      ↓ (イベント発生!)
[ クラスモジュール (監視役) ] ← ここが常に待ち構えている
      ↓ (検知したぞ!)
[ ログ出力関数 ] → [ audit_log.txt ]

2. 実装:監査ログシステムの構築

それでは、実際にコードを書いていきましょう。
作業は3つのステップに分かれます。

1. クラスモジュールの作成(監視役の定義)
2. 標準モジュールの作成(監視役の起動と停止)
3. ログ出力の実装(記録の実行)

ステップ1:クラスモジュールの作成

まず、VBAエディタのメニューから `挿入` -> `クラスモジュール` を選択してください。
作成されたクラスの名前を、プロパティウィンドウから `clsVisioWatcher` に変更してください。ここが重要です。

' --- クラスモジュール名: clsVisioWatcher ---
Option Explicit

' WithEvents を使うことで、Applicationのイベントを「捕まえる」ことができるようになります
' これが「監視役」の心臓部です
Private WithEvents App As Visio.Application

' 監視を開始するためのメソッド
Public Sub Initialize(ByVal visioApp As Visio.Application)
    Set App = visioApp
    Debug.Print "監査ログシステム:監視を開始しました。"
End Sub

' 監視を停止するためのメソッド
Public Sub Terminate()
    Set App = Nothing
    Debug.Print "監査ログシステム:監視を終了しました。"
End Sub

' --- イベントハンドラ:ページが追加されたとき ---
Private Sub App_PageAdd(ByVal Page As Visio.Page)
    Call WriteLog("PAGE_ADD", "新しいページが追加されました: " & Page.Name)
End Sub

' --- イベントハンドラ:ページが削除されたとき ---
Private Sub App_PageDelete(ByVal Page As Visio.Page)
    ' 注意:削除された直後のオブジェクトにアクセスするとエラーになることがあるため、
    ' 名前などの情報をあらかじめ取得しておく設計が理想的ですが、ここではシンプルに記述します
    Call WriteLog("PAGE_DELETE", "ページが削除されました。")
End Sub

' --- ログ書き出しの内部処理 ---
Private Sub WriteLog(ByVal action As String, ByVal details As String)
    Dim logPath As String
    Dim fileNum As Integer
    
    ' ログファイルの保存先(このExcel/Visioファイルと同じフォルダ)
    logPath = ThisDocument.Path & "\visio_audit_log.txt"
    fileNum = FreeFile
    
    ' ファイルを追記モード(Append)で開く
    Open logPath For Append As #fileNum
    ' [日時] [アクション] 詳細 という形式で記録
    Print #fileNum, "[" & Now & "] [" & action & "] " & details
    Close #fileNum
    
    ' イミディエイトウィンドウにも表示(デバッグ用)
    Debug.Print "Log Recorded: " & action
End Sub

ステップ2:標準モジュールの作成

次に、`挿入` -> `標準モジュール` を選択し、以下のコードを記述します。
ここで最も重要なテクニックは、「監視役(クラスのインスタンス)をモジュールレベル変数として保持する」ことです。

' --- 標準モジュール ---
Option Explicit

' 【超重要】ここを Sub の中ではなく、モジュールの先頭(宣言セクション)に書くこと!
' これにより、マクロが終わっても「監視役」がメモリ上に生き残り続けます。
Private Watcher As clsVisioWatcher

' 監視システムを起動するマクロ
Sub StartAuditSystem()
    ' 監視役(クラス)のインスタンスを作成
    Set Watcher = New clsVisioWatcher
    
    ' Visioアプリケーションを監視役にセット
    Watcher.Initialize Visio.Application
    
    MsgBox "監査ログシステムを起動しました。" & vbCrLf & _
           "ページの追加・削除を記録します。", vbInformation
End Sub

' 監視システムを停止するマクロ
Sub StopAuditSystem()
    If Not Watcher Is Nothing Then
        Watcher.Terminate
        Set Watcher = Nothing
        MsgBox "監査ログシステムを停止しました。", vbExclamation
    Else
        MsgBox "システムは起動していません。", vbInformation
    End If
End Sub

3. ここがプロの分かれ道:陥りやすいエラーと「生存期間」

ここまでのコードを動かすと、素晴らしい体験ができるはずです。しかし、初心者が必ずと言っていいほど陥る「罠」があります。

罠:なぜかログが記録されない!?

もし、`StartAuditSystem` の中で `Dim Watcher As clsVisioWatcher` と宣言してしまったらどうなるでしょうか?

' 失敗例
Sub StartAuditSystem()
    Dim Watcher As clsVisioWatcher ' プロシージャ内のローカル変数
    Set Watcher = New clsVisioWatcher
    Watcher.Initialize Visio.Application
End Sub ' ← ここで Watcher はメモリから消滅(死)してしまう!

プロシージャ(Sub)の中で宣言された変数は、そのSubが終わった瞬間に破棄されます。
つまり、監視役を起動した瞬間に、監視役が消えてしまうのです。

「オブジェクトのライフサイクル(生存期間)」を制御すること。
これが、単なるスクリプト作成者と、システムエンジニアを分ける決定的な差です。クラスをモジュールレベル(プロシージャの外)で宣言することで、私たちは「システムが動いている間、ずっと監視役を生かしておく」ことができるのです。

4. まとめ:次の一歩へ

お疲れ様でした!
今回作成したシステムは、以下の3つの高度な概念を組み合わせています。

1. クラスモジュール:イベントを待ち受ける「オブジェクト」の設計。
2. WithEvents:アプリケーションの挙動をフックする「魔法のキーワード」。
3. ライフサイクル管理:変数のスコープを理解し、システムを常駐させる「設計思想」。

この仕組みを応用すれば、「図形が変更されたら記録する」「特定のレイヤーが操作されたら警告を出す」といった、より複雑な自動化システムへと拡張できます。

「マクロの記録」という殻を破り、Visioというプラットフォームの上で、独自の「動的なシステム」を構築する楽しさを、ぜひ味わってください。

ここをクリアすれば、Visio VBAの基本はバッチリですよ。
さあ、次はどんなシステムを作りましょうか?

*Happy Coding!*

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