【実務・中級編】【実務直結】ページ削除時の「誤削除防止」ダイアログと、削除ログを外部テキストに出力する安全策 – Visio VBA解析バイブル

スポンサーリンク

【Visio VBA極限解説】ページ誤削除の悲劇を防げ!確認ダイアログと完全ログ監査システムの構築

開発プロジェクトの現場において、Visioの図面管理は属人化しやすく、ヒューマンエラーの温床になりやすい。特に、複数のステークホルダーが関わる巨大なフローチャートやネットワーク図において、「重要なページが誤って削除された」というトラブルは、プロジェクトの遅延に直結する致命傷となり得る。

標準のVisio UIには、ページ削除時に「このページを削除しますか?」という簡易的なアラートが出る。しかし、マクロやVBAから `Page.Delete` メソッドを実行した瞬間、容赦なく確認なしでページは消え去る。 オブジェクトのライフサイクルを理解しているエンジニアであれば、この「サイレント削除」の脅威はお分かりだろう。

今回は、Visio VBAにおいて「誤削除を絶対に防ぐガード機構」と、コンプライアンスやトレーサビリティの観点から不可欠な「削除ログの外部テキスト出力」を組み合わせた、プロダクション品質の堅牢なコードベースを伝授する。

—

1. なぜ「単純なVBA削除」では実務で使えないのか?

多くの初学者は、以下のようなコードを書いて満足しがちだ。

‘ 【アンチパターン】絶対に真似してはいけない危険なコード
Sub DangerousDelete()
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage

‘ いきなり削除する。確認もログもない。
vsoPage.Delete
End Sub

このコードの問題点は明白だ。
1. 安全弁の欠如: アクティブなページが「絶対に消してはいけないマスターページ」であっても、容赦なく消滅する。
2. 監査証跡の欠如: 「誰が」「いつ」「どのページのID・名前を」消したのかが一切記録されないため、トラブル発生時の原因究明が不可能。

プロのエンジニアが構築すべきシステムは、「操作の意図確認(UI層)」「システム的な保護判定(ロジック層)」「事後証跡の記録(I/O層)」の3レイヤーが完全に分離・連動していることである。

—

2. 堅牢なページ削除システムの設計思想

今回実装するアーキテクチャの要件は以下の通りだ。

1. 特定ページの保護(イミュータブル・ページ):
例えば、名前に `[Protected]` や `表紙` と含まれるページは、VBAからの削除をも拒絶するフェイルセーフを設ける。
2. 二重確認ダイアログ:
ユーザーに明確な警告(ページ名とIDを明示)を与え、本当に削除するかの意思決定を迫る。
3. 外部テキスト(CSV)への監査ログ出力:
ファイルI/Oを用いて、ローカルまたはネットワーク上の所定のパスに削除履歴を追記(Append)する。ファイルロック競合を考慮したエラーハンドリングも実装する。

—

3. プロダクションコード:安全削除&ログ監査マクロ

以下のコードをVisioの標準モジュールに貼り付けてほしい。実務での即戦力となるよう、エラーハンドリングとコメントを徹底している。

Option Explicit

‘ ==============================================================================
‘ 処理名: SafeDeleteActivePageWithLog
‘ 概要: アクティブページの保護判定、確認ダイアログ、および監査ログ出力を行って削除する
‘ ==============================================================================
Public Sub SafeDeleteActivePageWithLog()
Dim targetPage As Visio.Page
Dim pageName As String
Dim pageID As Long
Dim docName As String
Dim userResponse As VbMsgBoxResult

‘ 1. 対象ページの取得と存在チェック
On Error GoTo ErrorHandler
Set targetPage = ActivePage
If targetPage Is Nothing Then
MsgBox “削除対象となるアクティブページが存在しません。”, vbCritical, “エラー”
Exit Sub
End If

pageName = targetPage.Name
pageID = targetPage.ID

‘ ドキュメント名の取得(未保存の場合は “Untitled” などの考慮)
If ActiveDocument.Path = “” Then
docName = ActiveDocument.Name & ” (未保存)”
Else
docName = ActiveDocument.FullName
End If

‘ 2. システム保護ページかどうかの判定(例: 名前に “[Protected]” が含まれる場合は削除禁止)
If InStr(1, pageName, “[Protected]”, vbTextCompare) > 0 Then
MsgBox “このページはシステム保護されているため削除できません。” & vbCrLf & _
“対象ページ: ” & pageName, vbCritical, “削除拒否”
Exit Sub
End If

‘ 3. ユーザーへの厳重な確認ダイアログ
userResponse = MsgBox( _
“【警告】本当にこのページを削除しますか?” & vbCrLf & vbCrLf & _
“・ページ名: ” & pageName & vbCrLf & _
“・ページID: ” & pageID & vbCrLf & _
“・図面名: ” & docName & vbCrLf & vbCrLf & _
“※この操作は元に戻せません。”, _
vbYesNo + vbExclamation + vbDefaultButton2, _
“ページ削除の最終確認”)

If userResponse = vbNo Then
MsgBox “ページ削除をキャンセルしました。”, vbInformation, “キャンセル”
Exit Sub
End If

‘ 4. 外部テキストへのログ出力処理
Call WriteDeletionLog(docName, pageID, pageName)

‘ 5. ページの削除実行
targetPage.Delete

MsgBox “ページ「” & pageName & “」を正常に削除し、監査ログを記録しました。”, vbInformation, “完了”
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error: ” & Err.Description, vbCritical, “システムエラー”
End Sub

‘ ==============================================================================
‘ 処理名: WriteDeletionLog
‘ 概要: 削除情報を外部CSVファイルに追記する(ファイルI/O)
‘ ==============================================================================
Private Sub WriteDeletionLog(ByVal documentName As String, ByVal pID As Long, ByVal pName As String)
Dim fso As Object
Dim logFile As Object
Dim logPath As String
Dim userName As String
Dim logLine As String

‘ ログファイルの出力先(例: ユーザーのドキュメントフォルダ、または共有サーバー)
‘ 実務では環境に合わせてパスを変更してください
logPath = Environ(“USERPROFILE”) & “\Documents\VisioDeletionLog.csv”

‘ 実行Windowsユーザー名の取得
userName = Environ(“USERNAME”)

‘ FileSystemObject (FSO) の初期化
Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ ログファイルが存在しない場合は、ヘッダー行を先に書き込む
If Not fso.FileExists(logPath) Then
Set logFile = fso.OpenTextFile(logPath, 2, True) ‘ 2 = ForWriting
logFile.WriteLine “Timestamp,WindowsUser,DocumentName,PageID,PageName”
logFile.Close
End If

‘ ログデータを追記モード (ForAppending = 8) で開く
‘ ネットワークドライブ等の競合によるエラーをハンドリング
On Error GoTo LogError
Set logFile = fso.OpenTextFile(logPath, 8, True)

‘ CSV形式の行を作成 (日時, ユーザー名, 図面名, ページID, ページ名)
‘ ※カンマが含まれる可能性があるためダブルクォーテーションで囲む
logLine = Format(Now, “yyyy-mm-dd hh:nn:ss”) & “,” & _
“””” & userName & “””” & “,” & _
“””” & documentName & “””” & “,” & _
pID & “,” & _
“””” & pName & “”””

logFile.WriteLine logLine
logFile.Close

Set logFile = Nothing
Set fso = Nothing
Exit Sub

LogError:
‘ ログ書き込みに失敗してもVisioの動作自体を止めない設計にするか、あるいは厳格に止めるか。
‘ ここでは業務継続性を考慮し、警告を出して処理を続行させる。
MsgBox “警告: 削除ログのファイル出力に失敗しました。” & vbCrLf & _
“詳細: ” & Err.Description & vbCrLf & _
“パス: ” & logPath, vbExclamation, “ログ出力エラー”

If Not logFile Is Nothing Then logFile.Close
Set fso = Nothing
End Sub

—

4. この設計が「現場」で評価される理由

1. イミュータブル(不変)な命名規則の活用
`[Protected]` という文字列をフックにすることで、コードを書き換えなくても、図面上のページ名を変えるだけで誤削除ガード対象を動的にコントロールできる。
2. FileSystemObject (FSO) による堅牢なI/O
標準の `Open` ステートメントではなく `Scripting.FileSystemObject` を採用している点に注目してほしい。FSOはオブジェクト指向的なエラーハンドリングがしやすく、ファイルが存在しない場合の自動生成(`True` オプション)も含めて非常にスマートに記述できる。
3. 監査証跡のCSV出力フォーマット
出力されるログは標準的なCSV形式であり、Excelでそのまま開いてピボットテーブルで集計したり、Power BIなどのBIツールと連携して「誰がどの図面をどれくらい編集・削除しているか」のメトリクスを算出することが可能だ。

—

5. チーフアーキテクトからの提言

自動化マクロを書くとき、我々は「いかに効率よく処理を完了させるか(スピード)」ばかりに目を奪われがちだ。しかし、実務で本当に価値のあるツールとは、「ユーザーのうっかりミスを優しく、かつ厳格にガードし、企業の資産(図面)と履歴を守り抜くシステム」である。

このコードをベースに、組織のポリシーに合わせたログ保存先(共有サーバーのパスなど)の変更を行い、リボンカスタマイズからこの `SafeDeleteActivePageWithLog` を呼び出すように設定してほしい。それだけで、あなたのチームのVisio運用品質は一気にプロフェッショナルな領域へと到達するはずだ。

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