【上級】AutoCAD 202x系における「読み取り専用」図面の強制回避と編集ロック解除の極意
AutoCADを用いた設計業務の自動化において、避けて通れない最大の障壁――それが「読み取り専用(ReadOnly)」という名のファイルロックです。
複数人が同じサーバ上の図面を同時に参照している、あるいはPDM(製品データ管理)システムやファイルサーバの排他制御によって「編集権限がない」状態で図面が開かれる。このとき、単純なバッチ処理や自動編集スクリプトは、保存(Save)のフェーズで沈黙するか、致命的なエラーを吐いて停止します。
「読み取り専用だから処理をスキップする」というのは、凡庸なエンジニアの妥協策に過ぎません。
プロフェッショナルが構築する自動化システムは、「読み取り専用であれば、背後で自律的に一時ファイル(テンポラリ)へ退避・別名保存し、ロックを解除した編集可能状態でドキュメントを再構成して処理を完遂する」という強靭な自律復旧(Self-Healing)機構を備えているべきです。
本稿では、AutoCAD 202x系のマルチドキュメント(MDI)環境において、VBAのライフサイクルとWindowsファイルシステムの挙動を完全に制御し、この高度なワークフローをバグなしで実現する極限の知見を伝授します。
—
1. なぜ、従来の「SaveAs」コードは実務で破綻するのか?
インターネット上で見つかる一般的なVBAコードは、以下のような甘い設計で書かれています。
‘ 典型的な「動かない」あるいは「危険な」コードの例
If ThisDrawing.ReadOnly Then
ThisDrawing.SaveAs “C:\Temp\temp.dwg”
End If
このコードは、スタンドアロンの単純な環境では動くように見えますが、実務のパイプラインに投入した瞬間に以下の致命的な問題(バグ)を引き起こします。
致命的欠陥1:Embedded VBA(図面内蔵マクロ)の即死
もしこのマクロが図面内に埋め込まれた(Embedded)状態、あるいはその図面に依存したコンテキストで実行されている場合、ドキュメントの「保存」や「クローズ(再オープン)」を実行した瞬間に、実行中のVBAコード自体のメモリ領域が破壊され、AutoCADが強制終了(クラッシュ)するか、コードが途中で消失します。
このワークフローを実装するには、必ずグローバルプロジェクト(.dvb)、あるいはドキュメントから完全に独立したコンテキストから統制しなければなりません。
致命的欠陥2:`SaveAs` メソッドの「アクティブドキュメント移行」の罠
AutoCADの `SaveAs` メソッドを呼び出すと、現在開いているドキュメント自体のパスが新しいテンポラリパスへと「移行」します。
しかし、元の読み取り専用ファイルに対するファイルロック(OSレベルのハンドル)がどのタイミングで解放されるか、また一時ファイル側の排他権限が正しく昇格しているかは、AutoCADの内部データベース(`AcDbDatabase`)のステートに依存します。解放処理と再オープン処理の「同期」が取れていないと、ファイルIOの競合でエラーを誘発します。
致命的欠陥3:AutoCAD 202xの非同期処理とダイアログの壁
AutoCAD 2021以降、マルチスレッド化とグラフィックスエンジンの刷新に伴い、ドキュメントのオープン/クローズ処理のタイミングが非同期化する傾向が強まっています。
VBAから連続して `Close` -> `Open` を叩くと、AutoCADが「前の図面を完全に閉じきる前」に次のコマンドを実行してしまい、内部リンクが破壊されます。また、ファイル上書き時の「同名ファイルが存在します。上書きしますか?」といったダイアログが背後でポップアップし、バッチ処理を完全にフリーズさせる原因になります。
—
2. 堅牢な自律復旧ワークフローのアーキテクチャ
これらの問題を完璧に回避するために、私たちが設計すべきアーキテクチャの全体像は以下の通りです。
[開始]
│
├─ 1. 対象図面が「ReadOnly」か厳密に判定
│ (ReadOnly = False なら通常の編集フローへ)
│
├─ 2. OSのテンポラリ領域に「一意な一時ファイル名」を生成
│ (Windows APIによる競合のないパス確保)
│
├─ 3. AutoCADのシステム変数と警告ダイアログを「完全抑制」
│
├─ 4. 現在の図面をテンポラリパスへ「SaveAs」
│ (この時点で編集ロックが解除された一時図面へと切り替わる)
│
├─ 5. 元の「読み取り専用」図面を一切の変更を破棄して閉じる
│
├─ 6. 編集可能となった「一時図面」に対して自動編集処理を実行
│
├─ 7. 処理完了後、指定の成果物フォルダへ正規保存
│
[終了]
この設計の肝は、「一時ファイル名に決して固定値(`temp.dwg`など)を使わないこと」、そして「警告ダイアログをOSレベル、AutoCADレベルの双方で完全にハンドリングすること」にあります。
—
3. 極限のプロダクションコード(VBA)
以下に、実務でそのまま利用できる、極めて堅牢にビルドされたVBAコードを示します。
このコードは、Windowsのシステム一時フォルダ(Temp)への書き込みを保証し、ファイル重複エラーを完全に排除したプロ仕様の実装です。
Option Explicit
‘ ==============================================================================
‘ Windows API 宣言(堅牢なテンポラリファイル名生成のため)
‘ ==============================================================================
If VBA7 Then
Private Declare PtrSafe Function GetTempPathLib Lib “kernel32” Alias “GetTempPathA” (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare PtrSafe Function GetTempFileNameLib Lib “kernel32” Alias “GetTempFileNameA” (ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal uUnique As Long, ByVal lpTempFileName As String) As Long
Else
Private Declare Function GetTempPathLib Lib “kernel32” Alias “GetTempPathA” (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long
Private Declare Function GetTempFileNameLib Lib “kernel32” Alias “GetTempFileNameA” (ByVal lpszPath As String, ByVal lpPrefixString As String, ByVal uUnique As Long, ByVal lpTempFileName As String) As Long
End If
”’
”’
Public Sub ForceEditReadOnlyDocument()
Dim targetDoc As AcadDocument
Set targetDoc = ThisDrawing ‘ もしくは Documents コレクションから取得した特定のドキュメント
Dim originalPath As String
originalPath = targetDoc.FullName
‘ 1. 読み取り専用判定
If Not targetDoc.ReadOnly Then
MsgBox “この図面は既に編集可能です。通常の処理に移行します。”, vbInformation, “処理スキップ”
Call ExecuteMainProcess(targetDoc)
Exit Sub
End If
‘ 2. 環境のバックアップとダイアログの抑制
Dim oldCmdEcho As Integer
Dim oldFileDia As Integer
Dim oldExpert As Integer
On Error Resume Next
oldCmdEcho = ThisDrawing.GetVariable(“CMDECHO”)
oldFileDia = ThisDrawing.GetVariable(“FILEDIA”)
oldExpert = ThisDrawing.GetVariable(“EXPERT”)
ThisDrawing.SetVariable “CMDECHO”, 0
ThisDrawing.SetVariable “FILEDIA”, 0
ThisDrawing.SetVariable “EXPERT”, 5 ‘ すべての確認プロンプトを自動的に「はい」にする
On Error GoTo 0
‘ 3. 衝突のないテンポラリファイルのフルパスを生成
Dim tempDwgPath As String
tempDwgPath = CreateSecureTempDwgPath()
If tempDwgPath = “” Then
Err.Raise vbObjectError + 1001, “ForceEditReadOnlyDocument”, “テンポラリファイルの生成に失敗しました。”
End If
‘ 4. 保存先と元ファイル情報のログ
Debug.Print “Original ReadOnly Path: ” & originalPath
Debug.Print “Temporary Editable Path: ” & tempDwgPath
‘ 5. トランザクション的別名保存
On Error GoTo ErrorHandler
‘ 読み取り専用図面を一時ファイルとして別名保存
‘ これにより、AutoCAD内のコンテキストが「一時ファイル(編集可能)」に切り替わる
targetDoc.SaveAs tempDwgPath, ac2018_dwg ‘ AutoCAD 2018以降のDWGフォーマット(環境に合わせて調整)
‘ 6. 編集可能となったテンポラリドキュメントに対する実際の自動処理
‘ (この時点で ReadOnly 属性は解除されている)
Call ExecuteMainProcess(targetDoc)
‘ 7. 成果物を最終出力先へ保存する(例:元のファイル名に “_edited” を付与してデスクトップ等に保存)
Dim finalOutputPath As String
finalOutputPath = Replace(originalPath, “.dwg”, “_processed.dwg”, , , vbTextCompare)
‘ もし元のフォルダが書き込み禁止の場合に備え、代替パスを設定できるようにする
‘ ここではデモとして、同じフォルダへの別名保存を試みる
targetDoc.SaveAs finalOutputPath, ac2018_dwg
‘ 8. テンポラリファイルのクリーンアップ
‘ ドキュメントを閉じた後にOSから削除する必要があるため、パスを控えておく
Dim docToClose As AcadDocument
Set docToClose = targetDoc
‘ 環境変数の復元
RestoreEnvironment oldCmdEcho, oldFileDia, oldExpert
MsgBox “処理が完了しました。” & vbCrLf & “出力先: ” & finalOutputPath, vbInformation, “成功”
Exit Sub
ErrorHandler:
Dim errDesc As String
errDesc = Err.Description
‘ 安全な環境復元
RestoreEnvironment oldCmdEcho, oldFileDia, oldExpert
MsgBox “致命的エラーが発生しました: ” & errDesc, vbCritical, “エラー終了”
End Sub
”’
”’
Private Function CreateSecureTempDwgPath() As String
Dim tempPath As String 260
Dim tempFileName As String 260
Dim result As Long
‘ WindowsのTempフォルダパスを取得
result = GetTempPathLib(260, tempPath)
If result = 0 Then Exit Function
‘ 一意なファイル名を生成(拡張子は一時的に .tmp になる)
result = GetTempFileNameLib(Left(tempPath, InStr(tempPath, Chr(0)) – 1), “ACD”, 0, tempFileName)
If result = 0 Then Exit Function
‘ .tmp 拡張子を .dwg に置換してパスを返す
Dim cleanPath As String
cleanPath = Left(tempFileName, InStr(tempFileName, Chr(0)) – 1)
If Right(cleanPath, 4) = “.tmp” Then
cleanPath = Left(cleanPath, Len(cleanPath) – 4) & “.dwg”
End If
CreateSecureTempDwgPath = cleanPath
End Function
”’
”’
Private Sub RestoreEnvironment(ByVal cmdEcho As Integer, ByVal fileDia As Integer, ByVal expert As Integer)
On Error Resume Next
ThisDrawing.SetVariable “CMDECHO”, cmdEcho
ThisDrawing.SetVariable “FILEDIA”, fileDia
ThisDrawing.SetVariable “EXPERT”, expert
On Error GoTo 0
End Sub
”’
”’
Private Sub ExecuteMainProcess(ByRef doc As AcadDocument)
‘ ————————————————————————–
‘ ここに、あなたが自動化したい具体的な編集コードを記述します。
‘ 例:画層の追加、ブロックの挿入、属性値の書き換えなど。
‘ ————————————————————————–
Dim testLayer As AcadLayer
Set testLayer = doc.Layers.Add(“AUTO_PROCESSED_LAYER”)
testLayer.color = acRed
‘ ログ出力
Debug.Print “Document ‘” & doc.Name & “‘ に ‘AUTO_PROCESSED_LAYER’ を追加しました。”
End Sub
—
4. プロフェッショナルが解説するコードの深淵
このコードが、なぜ他の「お遊びマクロ」と一線を画すのか、そのアーキテクチャの急所を解説します。
① Windows API `GetTempFileName` の採用
ファイルシステム上で「競合しない一意な名前」を作るために、VBAの `Timer` 関数や乱数を使った適当なファイル名生成は絶対に避けてください。マルチスレッド環境や、同一サーバ内で同時にバッチが走った際に必ず名前衝突を起こします。
Windowsカーネルが提供する `GetTempFileName` は、OSレベルで衝突しないことが保証されたファイル名を生成するため、最も堅牢です。
② `EXPERT` システム変数の制御(値: 5)
AutoCADでの自動化において、最も開発者を悩ませるのが「サイレントフリーズ」です。バックグラウンドで実行しているにもかかわらず、
- 「図面を古い形式で保存しますか?」
- 「同一名称のファイルが存在します。上書きしますか?」
といったダイアログが画面外で立ち上がり、ユーザーの入力を待ち続けます。
`EXPERT` 変数を `5` に設定することで、これらの「確認ダイアログ」をすべて「はい(肯定)」とみなし、完全に無視して処理を進行させることができます。
③ 戻り値チェックとエラーハンドリングの徹底
`On Error Resume Next` の乱用は、バグの温床です。本コードでは、環境変数の読み書きという「失敗しても大勢に影響がない箇所」にのみ局所的に `Resume Next` を適用し、本質的なファイルIOや `SaveAs` 処理に対しては厳密な `GoTo ErrorHandler` トラップを配置しています。これにより、万が一書き込み権限のないディレクトリを指定された場合でも、AutoCADをクラッシュさせることなく安全に終了・復元します。
—
5. 実務における「後処理(クリーンアップ)」とネットワーク運用の注意点
このアプローチを実務の運用パイプラインに組み込む際、さらに設計の品質を高めるための2つのアドバイスがあります。
1. テンポラリファイルのゾンビ化を防ぐ
上記のコードで生成された一時ファイル(`ACDxxxx.dwg`)は、処理が終了した後もWindowsのTempフォルダに残ります。
ストレージを圧迫しないよう、システム終了時や、すべてのドキュメント処理が完了したタイミングで、以下のクリーンアップコードを走らせることを推奨します。
‘ 処理終了後に一時ファイルを削除する(ドキュメントが閉じられている必要がある)
On Error Resume Next
Kill tempDwgPath
On Error GoTo 0
2. ネットワーク共有フォルダでの競合と「遅延書き込み」
保存先がローカルSSDではなく、社内のNASやクラウドストレージ(SharePoint / OneDrive等)の同期フォルダである場合、`SaveAs` が完了したとVBAが判断した瞬間には、まだOSレベルでのファイル同期(アップロード)が完了していない場合があります。
この「遅延書き込み」中に次のドキュメントを開こうとすると、ネットワーク共有ロックが発生します。
実務では、保存処理の直後に `DoEvents` を数回挟むか、一時的にファイルシステムが解放されるまでループで待機する「リトライ機構」を設けることで、このネットワーク起因のバグを極限まで減らすことができます。
—
まとめ:プラットフォームを支配する設計を
AutoCAD VBAは、一見すると古いテクノロジーに見えるかもしれません。しかし、その内部オブジェクトモデル、システム変数、そしてWindows APIとの連携を正しく理解し、ライフサイクルを完全に掌握すれば、最新の.NETアドインにも劣らない超高速かつ堅牢な自動化エンジンへと変貌します。
「読み取り専用だから処理できない」という言い訳をシステムから排除し、どんな過酷なファイル環境でも自律して処理を完遂する、本物のプロ品質のツールをぜひ構築してください。
