【実務・中級編】【上級プロフェッショナル向け】バイナリ解析によるDWGヘッダー情報の直接取得:AutoCADを起動せずに図面の保存バージョンを判定する – AutoCAD VBA解析バイブル

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

AutoCADを起動するな:バイナリ解析によるDWGバージョン判定の極致

業務自動化の現場において、多くの開発者が陥る「致命的なアンチパターン」がある。それは、「単にファイルの情報を知りたいだけなのに、AutoCADのインスタンスを立ち上げてファイルを開く」という行為だ。

数千、数万という図面ファイルをスキャンし、バージョンごとに処理を分岐させるツールを設計する場合、この設計ミスはパフォーマンスの致命的な低下を招くだけでなく、メモリリーク、AutoCADのプロセス残留、そして予期せぬクラッシュという、地獄のような運用コストを現場に強いることになる。

プロフェッショナルなアーキテクトであれば、目的と手段を峻別せよ。図面のバージョン判定に、重厚なAutoCAD COMオブジェクトなど必要ない。必要なのは、ファイルの先頭数バイトを読み取る、極めて軽量なバイナリファイル操作だけだ。

本稿では、AutoCADを一切起動せずに、DWGファイルのヘッダー情報を直接解析し、超高速かつ堅牢にバージョンを特定する手法を伝授する。

1. 核心的知見:DWGヘッダーの構造

DWGファイルはバイナリ形式であり、そのファイル構造の冒頭(Magic Numberと呼ばれる領域)には、必ずそのファイルがどのAutoCADバージョンで作成されたかを示す識別コードが刻印されている。

具体的には、ファイルの先頭6バイトに `AC10xx` という形式の文字列が存在する。

ヘッダーコード AutoCAD バージョン
`AC1015` AutoCAD 2000
`AC1018` AutoCAD 2004
`AC1021` AutoCAD 2007
`AC1024` AutoCAD 2010
`AC1027` AutoCAD 2013
`AC1032` AutoCAD 2018

この「6バイト」さえ読み取れば、図面の内容を一切ロードすることなく、そのファイルが「現在のシステムで開けるものか」「変換が必要な古いものか」をミリ秒単位で判定できる。

2. 設計指針:堅牢なツールを作るために

単なる「コードの書き写し」で終わらせないために、以下の3点を設計原則として組み込む。

1. リソースの厳格な管理: `Open` ステートメントを使用する場合、エラーが発生しても必ず `Close` が呼ばれる構造(エラーハンドリング)を徹底する。ファイルハンドルをリークさせることは、自動化ツールにおける死を意味する。
2. IOオーバーヘッドの最小化: ファイル全体を読み込むような愚行は避け、必要な先頭数バイトのみをピンポイントで取得する。
3. 例外への耐性: ファイルが存在しない、アクセス権限がない、あるいはDWGではないファイル(壊れたファイル)を読み込んだ場合に、アプリケーション全体が停止しないよう、例外を適切にキャッチする。

3. 実装:プロダクション・クオリティのVBAコード

以下に、そのまま実務に投入可能なレベルのモジュールを示す。このコードは、AutoCADの参照設定すら不要である。純粋なVBA(ExcelやAccess等)から動作する。

Option Explicit

'==============================================================================
' Module: dwg_analyzer
' Description: DWGファイルのバイナリヘッダーを解析し、バージョンを判定する
' Author: Legendary Chief Architect
'==============================================================================

''' <summary>
''' 指定されたDWGファイルのバージョンヘッダー(AC10xx)を取得する
''' </summary>
''' <param name="filePath">対象ファイルのフルパス</param>
''' <returns>ヘッダー文字列(例: "AC1032")。取得失敗時は空文字</returns>
Public Function GetDWGHeader(ByVal filePath As String) As String
    Dim fileNum As Integer
    Dim headerBuffer As String
    Dim bufferSize As Integer: bufferSize = 6 ' AC10xx の長さ
    
    ' 1. ファイルの存在確認
    If Dir(filePath) = "" Then
        Debug.Print "Error: File not found -> " & filePath
        GetDWGHeader = ""
        Exit Function
    End If

    On Error GoTo ErrorHandler

    ' 2. バイナリモードでファイルを開く
    ' Access Read を指定することで、他のプロセスが書き込み中でも読み取りを試みる
    fileNum = FreeFile
    Open filePath For Binary Access Read As #fileNum
    
    ' 3. 先頭6バイトを読み込む
    ' Getステートメントを使用して、指定位置からバイナリデータを直接取得
    headerBuffer = Space$(bufferSize)
    Get #fileNum, 1, headerBuffer
    
    ' 4. ファイルを即座に閉じる(リソース解放の鉄則)
    Close #fileNum
    
    ' 5. 結果を返す
    GetDWGHeader = UCase(Trim(headerBuffer))
    Exit Function

ErrorHandler:
    ' エラー発生時も必ずファイルを閉じる
    If fileNum > 0 Then Close #fileNum
    Debug.Print "Error: Failed to read header for " & filePath & " - " & Err.Description
    GetDWGHeader = ""
End Function

''' <summary>
''' ヘッダーコードから人間が理解可能なバージョン名を返す
''' </summary>
Public Function MapHeaderToVersion(ByVal header As String) As String
    Select Case header
        Case "AC1015": MapHeaderToVersion = "AutoCAD 2000"
        Case "AC1018": MapHeaderToVersion = "AutoCAD 2004"
        Case "AC1021": MapHeaderToVersion = "AutoCAD 2007"
        Case "AC1024": MapHeaderToVersion = "AutoCAD 2010"
        Case "AC1027": MapHeaderToVersion = "AutoCAD 2013"
        Case "AC1032": MapHeaderToVersion = "AutoCAD 2018"
        Case Else:    MapHeaderToVersion = "Unknown (" & header & ")"
    End Select
End Function

''' <summary>
''' 実装テスト用メインルーチン
''' </summary>
Public Sub TestDWGAnalysis()
    Dim targetFile As String
    Dim header As String
    Dim version As String
    
    ' テスト対象のパスを指定
    targetFile = "C:\Temp\test_drawing.dwg"
    
    ' 実行
    header = GetDWGHeader(targetFile)
    
    If header <> "" Then
        version = MapHeaderToVersion(header)
        Debug.Print "--- Analysis Result ---"
        Debug.Print "File: " & targetFile
        Debug.Print "Header: " & header
        Debug.Print "Version: " & version
        Debug.Print "-----------------------"
    Else
        Debug.Print "Analysis failed. Check file path or format."
    End If
End Sub

4. 実務におけるデータベース・連携の注意点

この手法を大規模なシステム(例えば、図面管理サーバーのインデックス作成など)に組み込む場合、以下の設計的配慮が求められる。

データベースへの格納

解析結果をSQL ServerやAccessなどのデータベースに保存する場合、`AC10xx` という生の値(Raw Header)と、`AutoCAD 2018` という表示用名称(Mapped Name)の両方を保持することを強く推奨する。
理由は、将来的に新しいAutoCADバージョンが登場した際、マッピングロジックを更新するだけで済み、過去のデータ(Raw Header)を再定義できるからだ。

ファイルロックの回避

`Open … For Binary Access Read` を使用している点に注目してほしい。`Access Read` を明示することで、他のユーザーがその図面をAutoCADで開いて編集中であっても、共有モードでの読み取りが可能になる。これは、複数人が稼働するサーバー環境での自動化において、極めて重要なテクニックである。

パフォーマンスの比較

  • 手法A (AutoCAD API使用): 起動 5〜10秒 + ファイルロード 1〜3秒 = 約10秒/ファイル
  • 手法B (本手法: バイナリ解析): ファイルオープン 0.001秒 = 約0.001秒/ファイル

1,000個のファイルを処理する場合、手法Aでは約3時間かかるが、手法Bなら数秒で終わる。この差が、エンジニアとしての「設計力の差」である。

結論

AutoCAD VBAの真価は、AutoCADを操作することだけにあるのではない。「AutoCADに仕事をさせずに、AutoCADの情報をいかに効率よく抜き出すか」。この逆転の発想こそが、世界最高峰の自動化エンジニアへの入り口である。

バイナリを恐れるな。構造を理解せよ。それが、堅牢で高速なシステムを構築するための唯一の道である。

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