【入門編】【上級プロフェッショナル向け】ObjectDBXを用いた「図面を開かずに」外部参照(Xref)のパスを絶対から相対へ一括変換・保存 – AutoCAD VBA解析バイブル

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

【上級プロフェッショナル向け】ObjectDBXを用いた「図面を開かずに」外部参照(Xref)のパスを絶対から相対へ一括変換・保存

こんにちは。業務自動化の世界へようこそ。

皆さんは、こんな経験はありませんか?
「大量の図面ファイルがあるけれど、外部参照(Xref)のパスが『絶対パス』になっていて、プロジェクトフォルダを移動するたびにリンク切れが起きる……。これを一つずつ手作業で『相対パス』に直していくなんて、気が遠くなる……」

もし、あなたが今「図面を一つずつ `Documents.Open` で開き、画面に表示させ、パスを書き換えて、保存して、閉じる」というマクロを書いていたとしたら――。

おめでとうございます。あなたは、プロフェッショナルへの入り口に立っています。

しかし、同時にこうも言わせてください。「そのやり方では、いつか限界が来ます」と。

今日は、AutoCAD VBAの真髄であり、大量の図面を「神速」で処理するための魔法の技術、ObjectDBX を使った、外部参照パスの一括変換プログラムをマスターしていきましょう。

1. なぜ「図面を開く」のがいけないのか?

プログラミングにおけるパフォーマンスの敵、それは「オーバーヘッド」です。

AutoCADで図面を開くという行為は、単にファイルを読むだけではありません。

  • グラフィックスエンジンを起動し、画面を描画する準備をする。
  • ユーザーインターフェース(UI)を更新する。
  • メモリ上に膨大なオブジェクトを展開し、表示用のリソースを確保する。

これらすべてが、処理速度を劇的に低下させる原因になります。100枚の図面を処理する場合、この「画面表示の準備」が100回繰り返されるのです。

ここで登場するのが ObjectDBX です。

ObjectDBXとは何か?

ObjectDBXは、AutoCADのGUI(画面)を一切介さず、「メモリ上で直接DWGデータの構造にアクセスする」ための専用エンジンです。

例えるなら、本を読みたければ「図書館に行って、本を机に広げて、ページをめくる(通常のOpen)」のではなく、「本のデータをデジタルデータとして直接スキャンして読み取る(ObjectDBX)」ようなものです。

画面に何も表示されません。しかし、データの書き換えは完璧に行えます。これが、プロが「バックグラウンド処理」と呼ばれる所以です。

2. 実装の設計図:何をどう書き換えるのか?

外部参照(Xref)のパスを制御するために、私たちは何を操作すべきでしょうか?

AutoCADの内部構造において、外部参照は「Block(ブロック)」の一種として管理されています。
具体的には、`Blocks` コレクションの中に、その図面が参照している外部ファイルのデータが格納されています。

私たちのミッションは以下の通りです:
1. ObjectDBXのインスタンスを作成する。
2. 対象となるDWGファイルを「バックグラウンドで」開く。
3. `Blocks` コレクションを走査し、`IsXref` プロパティが `True` であるものを見つける。
4. そのブロックの `PathType` を `acRelativePath`(相対パス)に書き換える。
5. 上書き保存して、次のファイルへ。

3. 極限のコード例:Xrefパス一括変換マクロ

それでは、実際に動作するコードを見てみましょう。このコードは、フォルダ内の全てのDWGファイルを対象に、外部参照を相対パスへ一括変換します。

' ==========================================================================
' プログラム名: XrefPathConverter_ObjectDBX
' 概要: ObjectDBXを使用して、図面を開かずに外部参照を相対パスへ一括変換する
' 注意: 実行前に必ず図面のバックアップを取ってください。
' ==========================================================================

Option Explicit

Sub ConvertXrefsToRelativePath()
    Dim shellApp As Object
    Dim targetFolder As Object
    Dim folderPath As String
    Dim fileName As String
    
    ' --- 1. フォルダ選択ダイアログ ---
    Set shellApp = CreateObject("Shell.Application")
    Set targetFolder = shellApp.BrowseForFolder(0, "処理したい図面が入ったフォルダを選択してください", 0)
    
    If targetFolder Is Nothing Then Exit Sub
    folderPath = targetFolder.Self.Path & "\"
    
    ' --- 2. ObjectDBXの準備 ---
    ' AutoCADのバージョンに合わせて適切なDBXオブジェクトを生成します
    Dim dbxDoc As Object
    Dim dbxVersion As String
    
    ' Application.Versionから適切なインターフェース名を取得(例: "ObjectDBX.AxDbDocument.24")
    ' ※バージョン番号はAutoCADの内部バージョンに依存します
    On Error Resume Next
    dbxVersion = "ObjectDBX.AxDbDocument." & Val(Replace(Application.Version, ".", ""))
    Set dbxDoc = Application.GetInterfaceObject(dbxVersion)
    On Error GoTo 0
    
    If dbxDoc Is Nothing Then
        MsgBox "ObjectDBXの初期化に失敗しました。AutoCADのバージョンを確認してください。", vbCritical
        Exit Sub
    End If
    
    ' --- 3. ファイルループ処理 ---
    fileName = Dir(folderPath & "*.dwg")
    
    Dim count As Integer: count = 0
    Dim processedCount As Integer: processedCount = 0
    
    Do While fileName <> ""
        ' 自身のファイルはスキップ
        If fileName <> ThisDrawing.Name Then
            count = count + 1
            Debug.Print "処理中 (" & count & "): " & fileName
            
            ' エラーハンドリング(破損ファイル対策)
            On Error Resume Next
            
            ' --- ObjectDBXで図面を読み込む (画面には出ない) ---
            dbxDoc.Open folderPath & fileName
            
            If Err.Number = 0 Then
                Dim blk As Object
                Dim isChanged As Boolean: isChanged = False
                
                ' --- Blocksコレクションを走査 ---
                For Each blk In dbxDoc.Blocks
                    ' そのブロックが外部参照(Xref)かどうかを判定
                    If blk.IsXref Then
                        ' PathTypeを相対パス(acRelativePath = 1)に変更
                        ' ※ acRelativePathの定数は通常1です
                        If blk.PathType <> 1 Then
                            blk.PathType = 1
                            isChanged = True
                        End If
                    End If
                Next blk
                
                ' 変更があった場合のみ保存
                If isChanged Then
                    dbxDoc.SaveAs folderPath & fileName
                    processedCount = processedCount + 1
                End If
            Else
                Debug.Print "エラー発生 (" & fileName & "): " & Err.Description
            End If
            
            On Error GoTo 0
        End If
        
        fileName = Dir() ' 次のファイルへ
    Loop
    
    ' --- 4. 完了報告 ---
    MsgBox "処理が完了しました!" & vbCrLf & _
           "スキャンしたファイル数: " & count & vbCrLf & _
           "パスを更新したファイル数: " & processedCount, vbInformation
End Sub

4. ここをクリアすれば、あなたはもう初心者じゃない

このコードをただコピペするだけでは、本当の意味での「掌握」とは言えません。以下の3つのポイントを理解することが、エンジニアとしての成長に直結します。

① `GetInterfaceObject` の重要性

`Set dbxDoc = Application.GetInterfaceObject(…)` の部分を見てください。
ObjectDBXは、通常の `Dim dbxDoc As AcadDbxDocument` のような「事前バインディング」ではなく、実行時にオブジェクトを生成する「遅延バインディング」に近い手法をとります。これは、AutoCADのバージョンが変わっても、プログラムが壊れにくくするための、プロフェッショナルな作法です。

② `IsXref` という判定基準

図面の中には、ユーザーが作成した「ブロック」が無数にあります。それら全てに対してパスを書き換えようとするのは非効率ですし、エラーの元です。`blk.IsXref` というプロパティを使うことで、「外部参照として定義されているデータだけ」をピンポイントで狙い撃ちしています。

③ エラーハンドリング(`On Error Resume Next` の使い方)

大量のファイルを処理する場合、「1枚のファイルが壊れているだけで、100枚の処理が止まってしまう」という事態を避ける必要があります。
私はあえて、ファイル読み込み部分にエラーハンドリングを組み込みました。これにより、壊れたファイルがあっても、それをスキップして次のファイルへ進む「強靭な(Robustな)プログラム」になっています。

5. 陥りやすい落とし穴(プロからのアドバイス)

最後に、現場でよく遭遇するトラブルを共有しておきます。

  • 読み取り専用ファイル:

ファイルが他のユーザーによって開かれている(読み取り専用)場合、`dbxDoc.SaveAs` でエラーになります。実運用では、ファイルの属性チェックを入れるのが理想です。

  • 相対パスの整合性:

パスを「相対」に変えたとしても、図面同士の階層構造(フォルダの深さ)がバラバラだと、結局リンク切れになります。このマクロを実行する際は、「あらかじめフォルダ構成を整理しておく」ことがセットの作業だと覚えておいてください。

  • バージョン番号の不一致:

`Application.Version` を使った実装はスマートですが、極端に古いAutoCADから最新版へ移行した際、オブジェクト名が変わることが稀にあります。動かないときは、まず `Debug.Print` で `dbxVersion` の中身を確認してください。

結びに

「図面を開かずに処理する」という感覚は、最初は少し怖く感じるかもしれません。画面に何も映らないのですから。

しかし、この ObjectDBX を使いこなせるようになれば、あなたの作業効率は、これまでの「手作業」や「通常のVBA」とは比較にならない次元へと跳ね上がります。

一歩ずつ、オブジェクトの構造を理解し、コードの背後にあるロジックを掴んでいってください。その先には、AutoCADを自由自在に操る、素晴らしい景色が待っていますよ。

応援しています。頑張ってくださいね!

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