AutoCAD自動化の極意:二重起動の呪縛を解く「堅牢なオープン処理」の設計論
AutoCADのVBA開発において、避けては通れない「ファイル管理」。
初心者が最初に陥る罠が、「既に開いている図面を、無防備にもう一度開こうとして、実行時エラー(あるいは読み取り専用ダイアログ)を食らう」という事態だ。
「エラーが出たらOn Error Resume Nextで無視すればいい」などと考えているなら、今すぐその考えを捨ててほしい。それはコードの腐敗を招き、重大なデータ損失を引き起こす引き金になる。
プロのエンジニアにとって、コードは単に動けばいいものではない。「いかなる状況下でもシステムをクラッシュさせない」という高い堅牢性(Robustness)こそが、現場を支える武器となるのだ。
—
1. なぜ「力技」ではいけないのか
AutoCADの`Documents.Open`メソッドを不用意に叩くと、既に開いているファイルに対して以下の弊害が生じる。
- ユーザー体験の破壊: 突然現れる「読み取り専用で開きますか?」のダイアログ。自動化処理がここで停止し、ユーザーは混乱する。
- メモリリークの温床: エラーを適切にハンドリングしない場合、AutoCADのCOMオブジェクトが解放されず、バックグラウンドでゾンビプロセスが蓄積する。
- トランザクションの不整合: 万が一、データベース連携を行っている場合、二重起動によるファイルロックが競合を起こし、データの書き込みに失敗する可能性がある。
—
2. 実践:Documentsコレクションを走査する「真のオープン処理」
賢いエンジニアは、新しいファイルを開く前に「既にそのフルパスがメモリ上のDocumentsリストに存在するか」を確認する。`Documents`コレクションは、現在開かれているすべての図面ファイルを管理する、いわば「図面の守護神」だ。
以下に、プロダクション環境でもそのまま使える堅牢な関数を提示する。
‘ ==============================================================================
‘ 機能:指定されたフルパスの図面が既に開かれているかを確認し、
‘ 開かれていればそのDocumentオブジェクトを返し、なければ開いて返す。
‘ ==============================================================================
Public Function GetOrOpenDocument(ByVal targetFilePath As String) As AcadDocument
Dim doc As AcadDocument
Dim targetFile As String
‘ パスの正規化(大文字小文字の違いによる誤判定を防ぐ)
targetFile = UCase(targetFilePath)
‘ 1. 現在開いているドキュメントを走査
For Each doc In Application.Documents
If UCase(doc.FullName) = targetFile Then
‘ 既に開かれている場合は、そのドキュメントをアクティブにして返す
doc.Activate
Set GetOrOpenDocument = doc
Exit Function
End If
Next
‘ 2. 開かれていない場合は、新たに開く(ここでエラーハンドリングを厳格に)
On Error GoTo ErrorHandler
Set GetOrOpenDocument = Application.Documents.Open(targetFilePath)
Exit Function
ErrorHandler:
MsgBox “図面のオープンに失敗しました。” & vbCrLf & _
“パス: ” & targetFilePath & vbCrLf & _
“エラー詳細: ” & Err.Description, vbCritical
Set GetOrOpenDocument = Nothing
End Function
—
3. このロジックが「プロの設計」である理由
このコードには、単なる「動くコード」にはない3つの設計的こだわりがある。
① パスの正規化(UCase関数の活用)
Windowsのファイルシステムではパスの大文字小文字は区別されないが、VBAの文字列比較はデフォルトで厳格だ。`UCase`(または`StrComp`)で比較することで、環境依存のバグを徹底的に排除している。
② Documentオブジェクトの再利用
単に開くかどうかを判定するだけでなく、既に開かれている場合に「アクティブ化(`doc.Activate`)」して返す設計にしている。これにより、呼び出し元は「開いていようが閉じていようが、対象のドキュメントを確実に手に入れられる」という安心感を得られる。
③ 戻り値による依存関係の明確化
`Set GetOrOpenDocument = Nothing`を明示的に行うことで、呼び出し元が「オープン失敗」を即座に検知できるようにしている。エラーを握りつぶさず、呼び出し側に判断を委ねるのが、疎結合な設計の基本だ。
—
4. 現場のリーダーから君たちへの提言
自動化ツールを作るとき、「ハッピーパス(正常系)」しか考えない開発者は、往々にしてプロジェクトの足を引っ張る。
「もしファイルが読み取り専用だったら?」「もしパスが間違っていたら?」「もし図面が破損していたら?」という「境界条件(エッジケース)」を常に想像しなさい。
この`GetOrOpenDocument`関数は、君たちが今後作成するあらゆるバッチ処理の「基盤(ボトムライン)」となる。これをコピー&ペーストするだけでなく、なぜこの実装が必要なのかを理解し、自身のライブラリに組み込んでほしい。
技術とは、単なる機能の実装ではない。システムを「落ちないもの」にするための、執念に近い配慮のことである。
さあ、次はエラーハンドリングのその先、トランザクション制御の世界へ足を踏み入れようではないか。準備はできているか?
