【実務・中級編】【初心者向け】図面を開く際の「パスワード保護」有無の事前判定と、実行時エラーのスマートな回避方法 – AutoCAD VBA解析バイブル

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

「バッチ処理の死神」を回避せよ:AutoCAD VBAにおけるパスワード保護図面のスマートな検知と設計思想

業務自動化の現場において、エンジニアが最初に直面する「壁」は、単なる文法エラーではない。「予期せぬユーザーインターフェース(UI)の割り込み」だ。

数百、数千の図面を夜間に一括処理(バッチ処理)するツールを開発していると想像してほしい。プログラムが順調に動いている最中、突如として「パスワードを入力してください」というモーダルダイアログが表示され、マクロの実行が停止する。あるいは、エラーハンドリングを怠ったために、エラーが発生した瞬間にAutoCAD自体がクラッシュし、処理中のデータがすべて消失する。

これは、設計思想が欠如した「動けばいいだけのコード」が招く、典型的な悲劇である。

本記事では、図面を開く際のパスワード保護の有無をいかにスマートに判定し、バッチ処理を止めずに「堅牢な(Robust)」システムとして構築するか、その極限の知見を伝授する。

1. 初心者が陥る「On Error Resume Next」の罠

多くの初心者は、エラーが発生した際に処理を止めたくないあまり、コードの冒頭にこう書き込む。

' --- やってはいけない、素人の書き方 ---
On Error Resume Next
Documents.Open "C:\Data\Protected_File.dwg"
' エラーを無視して次へ進むが、ファイルが開けていないことに気づけない

これは設計として最悪だ。なぜか?
`On Error Resume Next` は、エラーを「無視」するだけで「解決」はしないからだ。ファイルが開けなかった場合、オブジェクト変数は `Nothing` のままになり、その後の操作(レイヤー変更や図形抽出)で必ず別のランタイムエラーが発生する。結果として、プログラムは「何が起きたか分からないまま、制御不能な状態」で暴走する。

プロフェッショナルは、「エラーを無視するのではなく、エラーを分類し、適切にハンドリング(制御)する」。これが鉄則である。

2. 堅牢な設計思想:Try-Catch-Log パターン

図面を開く処理を設計する際、我々は以下の3つのステップを必ず実装しなければならない。

1. Pre-flight Check(事前確認): ファイルが存在するか、読み取り権限があるか。
2. Controlled Attempt(制御された試行): パスワード保護等のエラーを想定した実行。
3. Audit Trail(監査証跡): スキップした理由をログとして記録し、後で人間が確認できるようにする。

特に、AutoCAD VBAにおいてパスワードの有無を「開く前に」完全に判定するプロパティは、標準APIには存在しない。そのため、「開こうとして失敗したことを、エラーハンドリングによって検知する」というアプローチが最も現実的かつ効率的である。

3. プロダクション・グレードのコード実装

以下に、そのまま業務に投入できるレベルの、保守性の高いコード構造を示す。このコードは、エラーが発生しても処理を止めず、詳細なログをテキストファイルに出力する設計になっている。

Option Explicit

' ==============================================================================
' 業務自動化エンジニアのための図面バッチ処理モジュール
' 概要: 指定フォルダ内のDWGを順次開き、パスワード保護等のエラーを回避しながら処理する
' ==============================================================================

Sub BatchProcessDrawings()
    Dim targetFolder As String
    Dim fileName As String
    Dim fullPath As String
    Dim logFilePath As String
    Dim doc As AcadDocument
    
    ' --- 設定領域 ---
    targetFolder = "C:\AutoCAD_Batch_Work\" ' 対象フォルダ
    logFilePath = targetFolder & "process_log.txt" ' ログ出力先
    
    ' ログの初期化
    WriteLog logFilePath, "--- バッチ処理開始: " & Now & " ---"
    
    ' フォルダ内のDWGファイルを検索
    fileName = Dir(targetFolder & "*.dwg")
    
    Do While fileName <> ""
        fullPath = targetFolder & fileName
        
        ' 1. 図面を開く試行
        Set doc = AttemptOpenDocument(fullPath, logFilePath)
        
        ' 2. 開けた場合のみ、実際の業務ロジックを実行
        If Not doc Is Nothing Then
            On Error GoTo ErrorHandler
            
            ' ------------------------------------------------------
            ' ここに図面操作のメインロジックを記述する
            ' 例: doc.Layers.Add("AUTOMATION_LAYER")
            ' ------------------------------------------------------
            
            WriteLog logFilePath, "SUCCESS: " & fileName & " を処理しました。"
            
            ' 図面を閉じる(保存する場合は doc.Close acSaveChanges)
            doc.Close acDoNotSave
            Set doc = Nothing
        End If
        
        ' 次のファイルへ
        fileName = Dir()
        
NextIteration:
    Loop
    
    WriteLog logFilePath, "--- バッチ処理終了: " & Now & " ---"
    MsgBox "処理が完了しました。詳細はログを確認してください。", vbInformation
    Exit Sub

ErrorHandler:
    ' 予期せぬ致命的エラーが発生した場合の処理
    WriteLog logFilePath, "CRITICAL ERROR in " & fileName & ": " & Err.Description
    Resume NextIteration
End Sub

' ==============================================================================
' 関数: AttemptOpenDocument
' 目的: 図面を安全に開く。パスワード保護等で失敗した場合はNothingを返す。
' ==============================================================================
Function AttemptOpenDocument(ByVal filePath As String, ByVal logPath As String) As AcadDocument
    On Error Resume Next ' 判定のため一時的にエラーを無視
    
    Dim tempDoc As AcadDocument
    Set tempDoc = Documents.Open(filePath)
    
    If Err.Number <> 0 Then
        ' エラー番号の判定(AutoCADの内部エラーに応じたハンドリング)
        ' パスワード保護等のダイアログが出るケースや、アクセス拒否を捕捉
        Select Case Err.Number
            Case 0
                ' エラーなし
                Set AttemptOpenDocument = tempDoc
            Case Else
                ' エラー内容をログに記録
                WriteLog logPath, "SKIP: " & filePath & " (Reason: " & Err.Description & ")"
                Set AttemptOpenDocument = Nothing
        End Select
        Err.Clear
    Else
        Set AttemptOpenDocument = tempDoc
    End If
    On Error GoTo 0 ' エラーハンドリングを通常状態に戻す
End Function

' ==============================================================================
' 関数: WriteLog
' 目的: 処理結果をテキストファイルに追記する(監査証跡の確保)
' ==============================================================================
Function WriteLog(ByVal logPath As String, ByVal message As String)
    Dim fileNum As Integer
    fileNum = FreeFile
    
    Open logPath For Append As #fileNum
    Print #fileNum, message
    Close #fileNum
End Function

4. アーキテクトの視点:なぜこの設計なのか

このコードが「ただのコード」と一線を画す理由は、以下の3点にある。

① オブジェクトのライフサイクル管理

`AttemptOpenDocument` 関数内で、エラーが発生した際に `Nothing` を返す設計にしている。これにより、呼び出し元(メインルーチン)は `If Not doc Is Nothing Then` という極めてシンプルかつ強力な条件分岐だけで、「有効なオブジェクトに対してのみ操作を行う」という安全性を確保できる。これはメモリリークや不正アクセスを防ぐための鉄則だ。

② 疎結合な設計

「図面を開く処理」と「図面を操作するロジック」と「ログを書く処理」を分離している。もし将来的に、ログをテキストファイルではなく、SQL Serverなどのデータベースに書き込みたいとなった場合でも、`WriteLog` 関数の中身を書き換えるだけで済む。これを「関心の分離(Separation of Concerns)」と呼ぶ。

③ 監査証跡(Audit Trail)の重要性

バッチ処理において、「何が成功し、何が失敗したか」を後から検証できないツールは、実務では使い物にならない。パスワード保護でスキップされた図面が、後で手動で確認できるように、ログにファイル名と理由を明記している。これが、現場のユーザー(設計者)からの信頼を勝ち取る鍵となる。

5. さらなる高みへ:データベース連携とパフォーマンス

もし君が、さらに大規模なシステムを構築するなら、以下の点にも留意せよ。

  • DB連携: ログをDB(AccessやSQL Server)に格納すれば、失敗したファイルの一覧をSQLで即座に抽出でき、管理ツールとしての価値が飛躍的に高まる。
  • パフォーマンスの重み: `Documents.Open` は非常に重い処理だ。大量のファイルを開く際は、AutoCADの画面更新を抑制するなどの工夫が必要になる場合もあるが、VBAにおいては「開いた図面を確実に閉じる」ことの方が、メモリ管理の観点から遥かに重要だ。

結論

「エラーが起きないコード」を書こうとするな。「エラーが起きても、システム全体が崩壊しないコード」を書け。

パスワード保護という「不確定要素」を、エラーハンドリングとログ記録によって「制御可能なイベント」へと昇華させること。それこそが、伝説的なチーフアーキテクトへの第一歩である。

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