SaveAsメソッドでDWGをDXFへ:旧バージョン互換性を意識した保存設定 – レガシーシステム保守の鉄則
AutoCAD VBAの世界へようこそ。私は長年、この領域で幾多の自動化システムを設計・実装し、時にはレガシーアーキテクチャの延命にも尽力してきた者だ。君たちが今、直面しているであろう「DWGファイルを旧バージョンのDXF形式で保存する」という課題。これは一見、単純な `SaveAs` メソッドの利用に思えるかもしれない。しかし、その背後には、システム全体の安定性、データ交換の確実性、そして何よりも「動く」という絶対的な要件を担保するための、深い洞察と熟練した技術が求められる。
1. SaveAsメソッドの表層と深層
`ThisDrawing.SaveAs` メソッドは、ご存知の通り、現在の図面を新しいファイル名で保存するための基本的な機能だ。しかし、その真価は、引数に渡されるファイル形式の指定と、それによって暗黙的に、あるいは明示的に制御されるバージョン互換性に宿る。
1.1. ファイル形式の指定:単なる拡張子の問題ではない
`SaveAs` メソッドの第一引数には、保存したいファイルのフルパスを指定する。そして、第二引数には `AcSaveAsType` 列挙体で保存形式を指定する。DXF形式への変換であれば、`acR12DXF` や `ac2000DXF` といった値が選択肢となる。
‘ 最新DWGをR12 DXF形式で保存する例
ThisDrawing.SaveAs “C:\path\to\your\output.dxf”, acR12DXF
しかし、ここで重要なのは、単に `acR12DXF` を指定すれば万事解決するわけではない、ということだ。AutoCADは、指定されたDXFバージョンに対応するべく、内部的にデータ構造の変換、あるいは不要な情報のフィルタリングを行う。このプロセスは、特に複雑なオブジェクトや、最新のAutoCADで追加された機能を利用している場合に、思わぬ落とし穴を生む可能性がある。
1.2. バージョン互換性の深淵:レガシー環境の保守とシステム間連携
君たちが社内システム管理者や、長年稼働するAutoCADベースのシステム保守に携わるエンジニアであれば、この「バージョン互換性」の重要性は身に染みて理解しているはずだ。
- レガシー環境の保守: 古いバージョンのAutoCADや、DXFをサポートする他社製CADシステムとのデータ連携は、しばしば避けて通れない。これらのシステムは、最新のDXF仕様に完全には対応していない場合が多い。そのため、保存するDXFのバージョンを、連携先のシステムが確実に解釈できる範囲に限定する必要がある。
- システム間連携: 異なるシステム間でデータをやり取りする際、DXFはデファクトスタンダードとなりうる。しかし、その「標準」の解釈は、システムごとに微妙な差異を生むことがある。極力、汎用性の高い旧バージョンを指定することで、この差異に起因する問題を軽減できる。
1.3. パフォーマンスの重み:メモリとCPUの最適化
VBAにおける `SaveAs` メソッドは、単にディスクへの書き込み処理に留まらない。内部的には、ActiveXオブジェクトの操作、データ構造の変換、そして場合によってはWindows APIを介したファイル操作などが複合的に行われる。
- オブジェクトの明示的解放: 大規模な図面を扱う場合、VBAのオブジェクト管理はメモリリークの温床となりうる。`SaveAs` 実行前後に、不要になったオブジェクト(特に `AcadDocument` オブジェクトなど)を `Set obj = Nothing` で明示的に解放することは、メモリ使用量を抑制し、後続処理のパフォーマンスを維持するために不可欠だ。
- COMオブジェクトのライフサイクル: `ThisDrawing` オブジェクトのようなCOMオブジェクトは、AutoCADアプリケーション本体と密接に結びついている。`SaveAs` 実行時のCOMオブジェクトの生成・破棄は、AutoCADのプロセスに直接的な影響を与える。大量のファイルをバッチ処理する場合、COMオブジェクトの生成を最小限に抑え、効率的なループ処理を設計することが、CPU負荷の軽減に繋がる。
2. 実践:旧バージョンDXFへの保存と互換性確保のノウハウ
ここでは、具体的なVBAコード例を示しながら、旧バージョンDXFへの保存における実践的なテクニックと注意点を解説する。
2.1. 基本的なSaveAsメソッドによるDXF変換
まずは、最も基本的な`SaveAs`メソッドを使ったDXF変換から始めよう。
Sub SaveAsDXF_Basic()
Dim AutoCADApp As Object
Dim CurrentDrawing As AcadDocument
Dim OutputPath As String
Dim SaveVersion As AcSaveAsType
‘ AutoCADアプリケーションオブジェクトの取得
On Error Resume Next
Set AutoCADApp = GetObject(, “AutoCAD.Application”)
On Error GoTo 0
If AutoCADApp Is Nothing Then
MsgBox “AutoCADが起動していません。”, vbCritical
Exit Sub
End If
‘ 現在アクティブな図面を取得
Set CurrentDrawing = AutoCADApp.ActiveDocument
‘ 保存パスとバージョンを指定
OutputPath = “C:\Temp\MyDrawing_R12.dxf” ‘ 保存したいパスを指定
SaveVersion = acR12DXF ‘ 保存したいDXFバージョンを指定 (例: AutoCAD R12 DXF)
‘ SaveAsメソッドで保存を実行
On Error Resume Next ‘ エラーハンドリング
CurrentDrawing.SaveAs OutputPath, SaveVersion
If Err.Number <> 0 Then
MsgBox “ファイルの保存に失敗しました。” & vbCrLf & “エラー: ” & Err.Description, vbCritical
Err.Clear
Else
MsgBox “ファイルをDXF形式で保存しました。” & vbCrLf & OutputPath, vbInformation
End If
On Error GoTo 0
‘ オブジェクトの解放
Set CurrentDrawing = Nothing
Set AutoCADApp = Nothing
End Sub
【コード解説】
- `GetObject(, “AutoCAD.Application”)`: 既に起動しているAutoCADアプリケーションインスタンスを取得します。これにより、VBAマクロをAutoCAD上から実行している場合でも、外部からAutoCADを操作している場合でも対応できます。
- `Set CurrentDrawing = AutoCADApp.ActiveDocument`: 現在アクティブになっている図面オブジェクトを取得します。
- `SaveVersion = acR12DXF`: ここで保存したいDXFのバージョンを指定します。
- `acR12DXF`: AutoCAD Release 12 DXF
- `ac2000DXF`: AutoCAD 2000 DXF
- `ac2004DXF`: AutoCAD 2004 DXF
- `ac2007DXF`: AutoCAD 2007 DXF
- `ac2010DXF`: AutoCAD 2010 DXF
- `ac2013DXF`: AutoCAD 2013 DXF
- `ac2018DXF`: AutoCAD 2018 DXF (最新のAutoCAD VBAで利用可能な場合)
注意: 利用可能な`AcSaveAsType`の列挙体は、実行環境のAutoCADのバージョンに依存します。最新のAutoCAD VBAで、古いDXFバージョンを指定して保存することは可能ですが、その逆(古いAutoCAD VBAで新しいDXFバージョンを指定しても、それをサポートするファイル形式で保存できるとは限らない)は注意が必要です。
- `On Error Resume Next`: `SaveAs`処理中に発生する可能性のあるエラー(例:ファイルアクセス権限がない、ディスク容量不足など)を捕捉するために使用しています。
- `Set CurrentDrawing = Nothing`, `Set AutoCADApp = Nothing`: オブジェクト参照を解放し、メモリリークを防ぎます。
2.2. 複数ファイルの一括変換とバージョン選定の自動化
社内システムでは、しばしば多数のDWGファイルを一括で処理する必要があります。その際、どのDXFバージョンを選択すべきか、あるいはユーザーに選択させるかは、重要な設計判断となります。
【シナリオ】
ある部署では、特定の旧バージョンのCADシステム(例: AutoCAD 2000互換)と連携するため、常に`ac2000DXF`形式でDXFを出力する必要があるとします。
Sub BatchConvertDWGtoDXF_SpecificVersion()
Dim FSO As Object ‘ FileSystemObject
Dim Folder As Object ‘ Folder object
Dim FileItem As Object ‘ File object
Dim AutoCADApp As Object
Dim CurrentDrawing As AcadDocument
Dim SourceFolderPath As String
Dim TargetFolderPath As String
Dim OutputFileName As String
Dim SaveVersion As AcSaveAsType
‘ — 設定 —
SourceFolderPath = “C:\DWG_Source\” ‘ 元DWGファイルがあるフォルダ
TargetFolderPath = “C:\DXF_Output\” ‘ DXFファイルを出力するフォルダ
SaveVersion = ac2000DXF ‘ 変換後のDXFバージョン (例: AutoCAD 2000 DXF)
‘ — 設定ここまで —
‘ フォルダ存在チェックと作成
Set FSO = CreateObject(“Scripting.FileSystemObject”)
If Not FSO.FolderExists(TargetFolderPath) Then
FSO.CreateFolder TargetFolderPath
End If
‘ AutoCADアプリケーションオブジェクトの取得
On Error Resume Next
Set AutoCADApp = GetObject(, “AutoCAD.Application”)
On Error GoTo 0
If AutoCADApp Is Nothing Then
MsgBox “AutoCADが起動していません。マクロはAutoCAD上から実行してください。”, vbCritical
Exit Sub
End If
‘ 元DWGフォルダ内のファイルをループ処理
Set Folder = FSO.GetFolder(SourceFolderPath)
For Each FileItem In Folder.Files
‘ DWGファイルのみを対象とする
If LCase(FSO.GetExtensionName(FileItem.Name)) = “dwg” Then
‘ 保存ファイル名を生成
OutputFileName = TargetFolderPath & FSO.GetBaseName(FileItem.Name) & “.dxf”
‘ DWGファイルを開く (非表示で開くとパフォーマンス向上)
‘ acadUtility.OpenDocument (FileItem.Path) は使えないため、AutoCADオブジェクト経由で開く
Dim OpenedDoc As AcadDocument
Set OpenedDoc = AutoCADApp.Documents.Open(FileItem.Path)
If Not OpenedDoc Is Nothing Then
‘ DXF形式で保存
On Error Resume Next
OpenedDoc.SaveAs OutputFileName, SaveVersion
If Err.Number <> 0 Then
Debug.Print “Error saving ” & FileItem.Name & “: ” & Err.Description
Err.Clear
End If
On Error GoTo 0
‘ 開いた図面を閉じる (変更を保存しない)
OpenedDoc.Close False
Set OpenedDoc = Nothing
Else
Debug.Print “Failed to open document: ” & FileItem.Path
End If
End If
Next FileItem
MsgBox “一括変換が完了しました。”, vbInformation
‘ オブジェクトの解放
Set Folder = Nothing
Set FileItem = Nothing
Set FSO = Nothing
Set AutoCADApp = Nothing
End Sub
【コード解説】
- `FileSystemObject`: ファイルやフォルダの操作を容易にするためのCOMオブジェクトです。
- `FSO.GetExtensionName(FileItem.Name)`: ファイル名から拡張子を取得します。
- `FSO.GetBaseName(FileItem.Name)`: ファイル名から拡張子を除いた部分を取得します。
- `AutoCADApp.Documents.Open(FileItem.Path)`: 図面ファイルを開きます。この際、`Display = False` のように画面表示をオフにすると、バックグラウンドでの処理となり、ユーザーインターフェースのちらつきを防ぎ、パフォーマンスも向上します。ただし、VBAから直接 `Open` メソッドの表示オプションを制御するのは、少しトリッキーな場合があります。ここでは、デフォルトの開く動作としています。
- `OpenedDoc.Close False`: 開いた図面を、変更を保存せずに閉じます。DXF変換が目的であり、元のDWGファイルを変更する必要はないためです。
- バッチ処理におけるパフォーマンス: 多数のファイルを処理する場合、AutoCADアプリケーションを一度だけ起動し、その中で開閉を繰り返す方が、ファイルごとにAutoCADを起動・終了するよりも圧倒的に高速です。また、画面描画をオフにする、不要なオブジェクトを都度解放するといった工夫が、システム全体の応答性を劇的に改善します。
2.3. Windows APIによる詳細なバージョン制御(高度なテクニック)
VBAの `SaveAs` メソッドで指定できるDXFバージョンには限界があります。しかし、AutoCADの内部的なバージョン情報を直接操作したり、より詳細なファイルフォーマット制御を行いたい場合、Windows APIの呼び出しが有効になることがあります。
例えば、`RegOpenKeyEx` や `RegQueryValueEx` を使ってAutoCADの設定レジストリからDXFのデフォルト保存バージョンを取得したり、あるいは `RegSetValueEx` を使って意図的に書き換える(※非推奨。システム破壊のリスクあり)といった高度な操作も理論上は可能です。
‘ — Windows API を使用したレジストリ操作の例 (参考情報) —
‘ このコードは、AutoCADのDXF保存バージョン設定を直接操作するものであり、
‘ システムの安定性を損なう可能性があります。実行には十分な注意が必要です。
‘ 実際のDXFバージョン指定は、SaveAsメソッドの列挙体で行うのが安全です。
If VBA7 Then ‘ 64bit VBA
Declare PtrSafe Function RegOpenKeyEx Lib “advapi32.dll” Alias “RegOpenKeyExA” ( _
ByVal hKey As LongPtr, _
ByVal lpSubKey As String, _
ByVal ulOptions As Long, _
ByVal samDesired As Long, _
ByRef phkResult As LongPtr) As Long
Declare PtrSafe Function RegQueryValueEx Lib “advapi32.dll” Alias “RegQueryValueExA” ( _
ByVal hKey As LongPtr, _
ByVal lpValueName As String, _
ByVal lpReserved As LongPtr, _
ByRef lpType As Long, _
ByVal lpData As Any, _
ByRef lpcbData As Long) As Long
Declare PtrSafe Function RegCloseKey Lib “advapi32.dll” ( _
ByVal hKey As LongPtr) As Long
Else ‘ 32bit VBA
Declare Function RegOpenKeyEx Lib “advapi32.dll” Alias “RegOpenKeyExA” ( _
ByVal hKey As Long, _
ByVal lpSubKey As String, _
ByVal ulOptions As Long, _
ByVal samDesired As Long, _
ByRef phkResult As Long) As Long
Declare Function RegQueryValueEx Lib “advapi32.dll” Alias “RegQueryValueExA” ( _
ByVal hKey As Long, _
ByVal lpValueName As String, _
ByVal lpReserved As Long, _
ByRef lpType As Long, _
ByVal lpData As Any, _
ByRef lpcbData As Long) As Long
Declare Function RegCloseKey Lib “advapi32.dll” ( _
ByVal hKey As Long) As Long
End If
Const HKEY_CURRENT_USER As Long = &H80000001
Const KEY_READ As Long = &H20019
Const REG_SZ As Long = 1
Sub GetDxfSaveVersionFromRegistry()
Dim RegKeyPath As String
Dim ValueName As String
Dim RegValue As String
Dim DataSize As Long
Dim RegType As Long
Dim KeyHandle As LongPtr ‘ LongPtr for 64-bit compatibility
Dim RetVal As Long
‘ AutoCAD 2023 の DXF 保存バージョン設定パスの例
‘ 注意: このパスはAutoCADのバージョンによって異なります。
RegKeyPath = “Software\Autodesk\AutoCAD\R24.2\ACAD-0001:409\DXF\SaveAs”
ValueName = “CurrentVersion” ‘ または “DefaultVersion” など、実際の設定値に合わせてください
‘ レジストリキーを開く
RetVal = RegOpenKeyEx(HKEY_CURRENT_USER, RegKeyPath, 0, KEY_READ, KeyHandle)
If RetVal = 0 Then ‘ Success
‘ 値のバッファサイズを取得
RegQueryValueEx KeyHandle, ValueName, 0, RegType, ByVal 0&, DataSize
If DataSize > 0 Then
‘ 値を取得するためのバッファを確保
RegValue = String(DataSize / 2, Chr$(0)) ‘ 文字列バッファ (Unicodeの場合)
RetVal = RegQueryValueEx(KeyHandle, ValueName, 0, RegType, ByVal RegValue, DataSize)
If RetVal = 0 Then
‘ 取得した値の末尾にあるNull文字などを除去
RegValue = TrimNulls(RegValue)
Debug.Print “DXF Save Version from Registry: ” & RegValue ‘ 例: “AC1015” (AutoCAD 2000)
‘ この値に基づいて、SaveAsメソッドの引数を動的に決定するなどの処理が可能
Else
Debug.Print “Error querying registry value. RetVal: ” & RetVal
End If
Else
Debug.Print “Value ‘” & ValueName & “‘ not found or has zero size.”
End If
‘ レジストリキーを閉じる
RegCloseKey KeyHandle
Else
Debug.Print “Error opening registry key. RetVal: ” & RetVal
End If
End Sub
‘ 文字列末尾のNull文字などを除去するヘルパー関数
Private Function TrimNulls(strIn As String) As String
Dim i As Integer
For i = Len(strIn) To 1 Step -1
If AscW(Mid$(strIn, i, 1)) = 0 Then
strIn = Left$(strIn, i – 1)
Else
Exit For
End If
Next i
TrimNulls = strIn
End Function
【Windows API利用の極意】
- デバッグの難易度: Windows APIは、VBAのオブジェクトモデルに比べてデバッグが格段に困難です。APIの仕様、引数の型、戻り値の解釈などを正確に理解する必要があります。
- 互換性のリスク: レジストリ設定を直接操作することは、AutoCADのアップデートやOSの変更によってパスやキー名が変わるリスクが常に伴います。このアプローチは、あくまで「特定の環境下で、どうしても必要」な場合に限定し、十分なテストとドキュメント化を行うべきです。
- `SaveAs`メソッドの限界を超える: `SaveAs`メソッドで提供される列挙体だけでは対応できない、非常に古いDXFフォーマット(例: R10 DXF)への保存や、特定のエンティティのみをエクスポートしたい場合などに、API経由でのファイル操作や、DXFファイルフォーマットの直接解析・生成が検討されることがあります。しかし、これは極めて高度な領域であり、DXFフォーマット仕様書との格闘が避けられません。
3. 結論:安易な自動化の先に待つもの
`SaveAs`メソッドによるDWGからDXFへの変換は、一見単純なタスクです。しかし、その裏側には、レガシーシステムとの連携、データ交換の信頼性、そしてパフォーマンスといった、システムエンジニアが常に直面する現実的な課題が横たわっています。
今日、提示した知識は、単なるメソッドの使い方を超え、「なぜそうするのか」「何が起こりうるのか」という、システム全体のライフサイクルを見通すための洞察を提供したつもりだ。AutoCAD VBAの世界は、奥深く、そして時に残酷なほどに現実的だ。安易な自動化の先に待っているのは、予測不能なバグと、保守不能なシステムである。
君たちが、この技術を真に掌握し、堅牢で信頼性の高いシステムを構築していくことを願っている。健闘を祈る。
