【テクニカル・上級編】【上級プロフェッショナル向け】バイナリ解析による「DWG保存バージョン」の高速特定:AutoCAD非起動での互換性チェック – AutoCAD VBA解析バイブル

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

思考のオーバーヘッドを削ぎ落とせ:バイナリ解析によるDWGバージョン高速特定術

エンジニアが陥る最も愚かな罠の一つは、「目的を達成するために、必要以上の重いオブジェクトを起動すること」だ。

数千、数万という図面ファイルをスキャンし、そのバージョン(互換性)を判別して処理を分岐させるシステムを構築しているとしよう。その際、もし君が `AutoCAD.Application` をインスタンス化し、`Documents.Open` メソッドを呼び出そうとしているなら、その設計は即座に破棄すべきだ。

AutoCADという巨大なアプリケーション・エンジンを起動するコストは、単なる「待ち時間」ではない。メモリの断片化、プロセスの制御権の奪い合い、そして予期せぬ例外によるシステム全体の不安定化を招く、致命的なリソースの浪費である。

真にプロフェッショナルなアーキテクトが取るべき道は、「図面の中身を見る前に、その『顔』だけを読み取る」ことだ。

1. DWGヘッダーの真実:AC10xx という魔術的シグネチャ

DWGファイルはバイナリ形式である。その構造は複雑怪奇だが、ファイル構造の最上部(ヘッダー)には、そのファイルの正体を示す「マジックナンバー」が刻印されている。

AutoCADの各バージョンは、このヘッダーに `AC10xx` という形式の識別子を保持している。
例えば、以下のような対応関係だ。

マジックナンバー AutoCAD バージョン (近似)
AC1015 AutoCAD 2000
AC1018 AutoCAD 2004
AC1021 AutoCAD 2010
AC1024 AutoCAD 2013 / 2014 / 2016
AC1032 AutoCAD 2018 / 2021 / 2024

この6バイト(`AC` + 4桁の16進数)を読み取るだけで、我々はAutoCADを一切起動することなく、そのファイルが自社のシステムで処理可能かどうかを、ミリ秒単位で判断できる。

2. 実装:極限の高速性を追求したバイナリ・インスペクター

VBAにおいて、ファイル操作を行う際、`FileSystemObject` を使うのは「便利」だが「最速」ではない。真のパフォーマンスを求めるなら、VBAネイティブの `Open … For Binary` ステートメント、あるいは Windows API を直接叩くべきだ。

ここでは、メモリ消費を最小限に抑え、オブジェクトのライフサイクルを完全に制御した、実戦投入可能な関数を提示する。

Option Explicit

' ==============================================================================
' Module: dwg_inspector
' Description: 高速DWGバージョン判定エンジン
' Author: Chief Architect
' ==============================================================================

''' <summary>
''' 指定されたDWGファイルのヘッダーを解析し、AutoCADのバージョン文字列を返す。
''' AutoCADを起動しないため、極めて高速かつ低リソース。
''' </summary>
''' <param name="filePath">対象のDWGファイルのフルパス</param>
''' <returns>識別子 (例: "AC1032")。判別不能な場合は "UNKNOWN" を返す。</returns>
Public Function GetDwgVersionFast(ByVal filePath As String) As String
    Dim fileNum As Integer
    Dim headerBuffer As String
    Dim versionCode As String
    
    ' 1. ファイルの存在確認(OSへの負荷を考慮し、最小限のチェック)
    If Dir(filePath) = "" Then
        GetDwgVersionFast = "FILE_NOT_FOUND"
        Exit Function
    End If

    On Error GoTo ErrorHandler

    ' 2. バイナリモードでのファイルオープン
    ' Access Read を指定することで、書き込みロックを回避し、読み取り専用として開く
    fileNum = FreeFile
    Open filePath For Binary Access Read As #fileNum

    ' 3. 先頭6バイトのみを読み取る
    ' 全体を読み込む愚行は避けること。メモリを汚染するだけだ。
    headerBuffer = Space$(6)
    Get #fileNum, , headerBuffer

    ' 4. ファイルのクローズ(リソース解放の徹底)
    ' エラーが発生する前に、必ずクローズする構造を維持する
    Close #fileNum

    ' 5. バリデーション
    ' 文字列が "AC" で始まっているか確認
    If Left(headerBuffer, 2) = "AC" Then
        GetDwgVersionFast = headerBuffer
    Else
        GetDwgVersionFast = "INVALID_FORMAT"
    End If

    Exit Function

ErrorHandler:
    ' 異常終了時も、ファイルハンドルを確実に解放する
    If fileNum > 0 Then Close #fileNum
    GetDwgVersionFast = "ERROR: " & Err.Description
End Function

''' <summary>
''' 解析したコードを人間が理解できる形式にマッピングする
''' </summary>
Public Function MapVersionCodeToName(ByVal versionCode As String) As String
    Select Case versionCode
        Case "AC1015": MapVersionCodeToName = "AutoCAD 2000"
        Case "AC1018": MapVersionCodeToName = "AutoCAD 2004"
        Case "AC1021": MapVersionCodeToName = "AutoCAD 2010"
        Case "AC1024": MapVersionCodeToName = "AutoCAD 2013/14/16"
        Case "AC1032": MapVersionCodeToName = "AutoCAD 2018/21/24"
        Case "FILE_NOT_FOUND": MapVersionCodeToName = "File Not Found"
        Case "INVALID_FORMAT": MapVersionCodeToName = "Not a valid DWG"
        Case Else: MapVersionCodeToName = "Unknown Version (" & versionCode & ")"
    End Select
End Function

' --- テスト用メインルーチン ---
Sub TestDwgInspector()
    Dim targetFile As String
    Dim vCode As String
    Dim vName As String
    
    ' テスト対象のパスを指定
    targetFile = "C:\Temp\Sample_Drawing.dwg"
    
    ' 高速解析実行
    vCode = GetDwgVersionFast(targetFile)
    vName = MapVersionCodeToName(vCode)
    
    ' 結果出力
    Debug.Print "--- DWG Analysis Report ---"
    Debug.Print "File: " & targetFile
    Debug.Print "Code: " & vCode
    Debug.Print "Name: " & vName
    Debug.Print "---------------------------"
End Sub

3. アーキテクトの視点:なぜこの実装なのか

このコードが、単なる「動くコード」ではなく「プロフェッショナルのコード」である理由を説明しよう。

1. メモリ・フットプリントの最小化

`Get #fileNum, , headerBuffer` を使用している点に注目してほしい。ファイル全体を `Input` や `Line Input` で読み込むことは、ファイルサイズが数百MBに及ぶDWGにおいて、致命的なメモリ消費を招く。我々は「必要な6バイト」だけをピンポイントで抜き取っている。これが計算機科学における「計算量」と「空間量」の最適化だ。

2. 決定論的なリソース管理

`On Error GoTo ErrorHandler` と、その中での `Close #fileNum`。これは、ファイルハンドルという貴重なOSリソースを、いかなるエラー状況下でも「確実に」解放することを保証している。ハンドルをリーク(漏洩)させれば、後続のプロセスがファイルにアクセスできなくなるという、システム全体のデッドロックを引き起こしかねない。

3. 疎結合な設計

`GetDwgVersionFast` は、バージョンの「解釈(マッピング)」を行わない。その関数は、純粋にバイナリデータを解析してコードを返すという単一責任(Single Responsibility)を果たしている。解釈のロジックを `MapVersionCodeToName` に分離することで、将来的に新しいAutoCADバージョン(例:AC1038など)が登場した際、解析エンジンを一切弄ることなく、マッピングテーブルを更新するだけで対応可能だ。

4. 実戦における応用:システム間連携への昇華

この技術は、単なる便利ツールに留まらない。

  • バックアップ・スクリプトの高速化: サーバー上の膨大なDWG群をスキャンし、特定のバージョン以降のものだけをクラウドへ同期する。
  • プリフライト・チェック: ユーザーが図面をアップロードした際、サーバー側でAutoCADを動かさずに、即座に互換性を判定してエラーを返す。
  • レガシー資産の棚卸し: 社内に散らばる古いバージョンの図面を特定し、一括変換プロジェクトの対象リストを作成する。

結論

「重いライブラリをロードすれば、すべて解決する」という考え方は、エンジニアの思考停止である。
真の力は、システムが提供する高レベルな抽象化レイヤーをあえて飛び越え、データの本質(バイナリ)に直接触れる勇気から生まれる。

AutoCADを起動させず、ただ6バイトを読み取る。
そのわずかな差が、数万個のファイルを扱う大規模システムにおいて、決定的なパフォーマンスの差となるのだ。

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