1. DWG単体保存の限界と「三位一体同期」の必然性
設計資産の真価は、その検索性と流通性にある。しかし、製造業や建設業の現場において、図面管理の実態は今なお「DWGファイル名と更新日時だけを頼りに手探りで開く」という極めて非効率な運用に縛られている。
DWGファイル内部のサムネイルバイナリは低解像度であり、専用ビューアを導入していない非CAD部門(購買、製造、積算、施工管理)との連携においては何の役にも立たない。結果として、「最新版の確認のためにCADライセンスを消費して開く」「他部門への出図のたびに手動でPDF化する」という、無価値な工数が日々垂れ流されている。
このボトルネックを根絶するのが、今回解説する「統合セーブ(Integrated Save)アーキテクチャ」だ。
設計者が意識することなく、`Ctrl+S` あるいは専用コマンドを実行した瞬間、バックグラウンドで以下の3つを完全同期で生成・固定化する。
1. 整合性を担保したDWGマスターファイル(最新バージョン保存)
2. 全社回覧・印刷承認用のベクターPDF(DWG To PDF)
3. 管理DB・Web UI連携用の高精細JPGプレビュー(Publish To Web JPG)
本稿では、AutoCAD ActiveX/COMオブジェクトのライフサイクルを完全に手中に収め、Windows APIによるファイルシステムレベルのハンドリングを組み込んだ、エンタープライズ品質の統合セーブマクロを提示する。
—
2. 内部設計とアーキテクチャの急所
単に「保存して、PDFを出して、画像を出す」というスクリプトを書くだけなら初級者でも可能だ。しかし、実務で数十MBを超える図面や外部参照(Xref)が絡み合うプロジェクトでそれを実行すると、AutoCADは沈黙し、最悪の場合はクラッシュする。
本設計においてプロが考慮すべき急所は3点ある。
① プロットエンジンの同期制御とバックグラウンド処理の排他
AutoCADのプロットエンジンはデフォルトでバックグラウンド実行(マルチスレッド)を試みる。しかし、DWG保存と同時に連続プロット(PDF生成 → JPG生成)を実行する場合、前のプロットジョブが完了する前に次のI/Oが走り、ファイルロックの競合(Access Violation)や出力の欠落を引き起こす。
システム変数 `BACKGROUNDPLOT` を強制的に `0` に倒し、完全な同期的シーケンス(Single-Thread Synchronous Execution)を保証しなければならない。
② ダイアログ抑制とFILEDIAの完全カプセル化
外部プリンタドライバや内蔵PC3がファイル保存ダイアログを要求した瞬間、バッチ処理やシームレスな操作性は破綻する。`CMDDIA` および `FILEDIA` の局所的制御はもちろん、エラー発生時にこれらのシステム変数が戻らない「CADの文脈汚染」を防止する厳格なフェイルセーフが不可欠だ。
③ COMオブジェクトの明示的解放とメモリフットプリント
ActiveX経由での連続プロット操作は、内部で大量のラッパーインスタンスを生成する。VBAのガベージコレクションは貧弱であり、オブジェクト参照をスコープアウト任せにするとメモリリークの原因となる。すべてのCOMオブジェクト(`AcadPlot`、`AcadPlotConfiguration` 等)は、スコープ終端で明示的に `Set obj = Nothing` を実行し、参照カウンタをゼロクリアする必要がある。
—
3. 実装のコア:完全同期型 統合セーブマクロ
以下のコードは、現在のモデル空間またはアクティブなレイアウトを対象に、DWG保存、PDF生成、JPG生成を同一ディレクトリに一意の命名規則でアトミックに書き出す統合マクロである。
標準モジュール:`Mod_IntegratedSave.bas`
Option Explicit
‘ ==============================================================================
‘ Windows API 定義: 高精度パス処理およびファイルシステム監視
‘ ==============================================================================
Private Declare PtrSafe Function PathFileExists Lib “shlwapi.dll” Alias “PathFileExistsA” ( _
ByVal pszPath As String) As Long
Private Declare PtrSafe Function GetTempPath Lib “kernel32” Alias “GetTempPathA” ( _
ByVal nBufferLength As Long, _
ByVal lpBuffer As String) As Long
‘ ==============================================================================
‘ 統合セーブ メインエントリポイント
‘ ==============================================================================
Public Sub ExecuteIntegratedSave()
On Error GoTo ErrorHandler
Dim acadDoc As AcadDocument
Set acadDoc = ThisDrawing
‘ 未保存図面(新規作成直後)のチェック
If acadDoc.Path = “” Then
MsgBox “図面が一度も保存されていません。初回は「名前を付けて保存」を行ってください。”, _
vbExclamation + vbSystemModal, “実行不可”
Exit Sub
End If
‘ システム環境退避用変数
Dim prevBackgroundPlot As Variant
Dim prevFileDia As Variant
Dim prevCmdDia As Variant
‘ 1. システム変数のキャプチャと同期化設定
prevBackgroundPlot = acadDoc.GetVariable(“BACKGROUNDPLOT”)
prevFileDia = acadDoc.GetVariable(“FILEDIA”)
prevCmdDia = acadDoc.GetVariable(“CMDDIA”)
‘ フォアグラウンド同期プロットを強制(ファイル競合防止)
acadDoc.SetVariable “BACKGROUNDPLOT”, 0
acadDoc.SetVariable “FILEDIA”, 0
acadDoc.SetVariable “CMDDIA”, 0
‘ 2. ファイルパスの算出
Dim dwgFullPath As String
Dim baseDir As String
Dim baseName As String
dwgFullPath = acadDoc.FullName
baseDir = acadDoc.Path & “\”
‘ 拡張子を除去したベースファイル名の取得
baseName = Mid(acadDoc.Name, 1, InStrRev(acadDoc.Name, “.”) – 1)
Dim pdfFullPath As String
Dim jpgFullPath As String
pdfFullPath = baseDir & baseName & “.pdf”
jpgFullPath = baseDir & baseName & “.jpg”
‘ 3. DWG本体のコミット(保存)
acadDoc.Save
acadDoc.Utility.Prompt vbCrLf & “[統合セーブ] DWG を保存しました: ” & dwgFullPath
‘ 4. PDF生成(DWG to PDF.pc3 の同期プロット)
Call GeneratePlotOutput(acadDoc, “DWG To PDF.pc3”, “ISO_full_bleed_A3_(420.00_x_297.00_MM)”, pdfFullPath)
acadDoc.Utility.Prompt vbCrLf & “[統合セーブ] PDF を同期出力しました: ” & pdfFullPath
‘ 5. JPGプレビュー生成(PublishToWeb JPG.pc3 によるラスタライズ)
‘ 解像度: 1600×1280 (XGA超の視認性を確保)
Call GeneratePlotOutput(acadDoc, “PublishToWeb JPG.pc3”, “Sun_Hi-Res_(1600.00_x_1280.00_Pixels)”, jpgFullPath)
acadDoc.Utility.Prompt vbCrLf & “[統合セーブ] JPG プレビューを同期出力しました: ” & jpgFullPath
acadDoc.Utility.Prompt vbCrLf & “[統合セーブ] すべての同期処理が正常に完了しました。”
Cleanup:
‘ システム変数の厳格な原状復帰
On Error Resume Next
If Not acadDoc Is Nothing Then
acadDoc.SetVariable “BACKGROUNDPLOT”, prevBackgroundPlot
acadDoc.SetVariable “FILEDIA”, prevFileDia
acadDoc.SetVariable “CMDDIA”, prevCmdDia
End If
Exit Sub
ErrorHandler:
Dim errDesc As String
errDesc = Err.Description
acadDoc.Utility.Prompt vbCrLf & “[致命的エラー] 統合セーブ失敗: ” & errDesc
Resume Cleanup
End Sub
‘ ==============================================================================
‘ プロットエンジン制御コア
‘ Layout単位でのプロット構成をオーバーライドし、ファイルへ送出する
‘ ==============================================================================
Private Sub GeneratePlotOutput( _
ByRef targetDoc As AcadDocument, _
ByVal pc3Name As String, _
ByVal mediaName As String, _
ByVal outputFilePath As String)
Dim plotObj As AcadPlot
Dim layoutObj As AcadLayout
Dim plotConfig As AcadPlotConfiguration
Set plotObj = targetDoc.Plot
Set layoutObj = targetDoc.ActiveLayout
‘ 一時的なプロット構成(PlotConfiguration)を生成して適用
Set plotConfig = targetDoc.PlotConfigurations.Add(“TEMP_INTEGRATED_CONFIG”, layoutObj.ModelType)
With plotConfig
‘ プロッタドライバと用紙サイズの設定
.ConfigName = pc3Name
.CanonicalMediaName = mediaName
‘ プロット領域:オブジェクト範囲(Extents)
.PlotType = acExtents
‘ プロットスケール:用紙にフィット
.StandardScale = acFit
‘ 図面の中心に配置
.CenterPlot = True
‘ 印刷スタイルテーブルの適用(モノクロ標準:必要に応じて変更)
.StyleSheet = “monochrome.ctb”
.PlotWithStyles = True
‘ 線幅の反映
.PlotWithLineweights = True
‘ 構成の更新を確定
.RefreshPlotDeviceInfo
End With
‘ カレントレイアウトに構成を転写
layoutObj.CopyFrom plotConfig
‘ 既存ファイルが存在する場合の保護処理(ファイル排他ロックの早期検知)
If PathFileExists(outputFilePath) <> 0 Then
On Error Resume Next
Kill outputFilePath
If Err.Number <> 0 Then
Err.Raise vbObjectError + 1001, , “出力ファイルがロックされています (別プロセスで使用中): ” & outputFilePath
End If
On Error GoTo 0
End If
‘ 同期プロット実行
‘ PlotToFile: 第2引数を空文字にすることで、第1引数の絶対パスへ直接書き出す
plotObj.PlotToFile outputFilePath, pc3Name
‘ 後始末: 作成したテンポラリ構成の破棄
plotConfig.Delete
‘ COM オブジェクトの明示的解放
Set plotConfig = Nothing
Set layoutObj = Nothing
Set plotObj = Nothing
End Sub
—
4. アーキテクチャの解説と極限運用のポイント
上記の実装には、エンタープライズ開発で踏むべき「泥臭いノウハウ」が凝縮されている。
① `PathFileExists` による排他アクセスの事前検知
プロット処理を流す前に、Windows APIである `PathFileExists` でファイルの存在を確認し、VBAの `Kill` で削除を試行している点に注目してほしい。
PDFやJPGがAdobe AcrobatやWindowsフォトビューアなどで開かれている場合、AutoCADのプロットエンジンは書き込みエラーを即座に感知できず、内部でリトライを繰り返した末にハングアップするか、意味不明なHRESULTエラーを返す。これを事前の排他検証によってミリ秒単位で検知・トラップしている。
② Layoutオブジェクトへの「動的構成転写」
図面内のレイアウト設定を直接破壊(恒久変更)することは、設計者の意図した印刷設定を上書きするリスクを孕む。
本コードでは `PlotConfigurations.Add` でメモリ上に仮想構成を作成し、それを `layoutObj.CopyFrom` で一時的に適用したのちにプロットし、即座に一時構成を `Delete` している。これにより、マスター図面側のプロット設定を汚染することなく、常に規格化されたPDF/JPGを出力できる。
③ CanonicalMediaName の厳密な指定
`DWG To PDF.pc3` や `PublishToWeb JPG.pc3` の用紙名(`CanonicalMediaName`)は、言語環境やドライババージョンによって微妙に異なる場合がある。
例えば、上記コードの `”ISO_full_bleed_A3_(420.00_x_297.00_MM)”` は標準的なメトリック環境の定義だ。もし環境依存を極限まで排除したい場合は、実行時に `plotConfig.GetCanonicalMediaNames` メソッドで配列を取得し、対象とするサイズ(”A3″ や “1600” など)を文字列検索(InStr)して動的にバインドするロジックを挟むのが最も堅牢である。
—
5. レガシー環境と基幹システム(EDMS)連携への拡張
このマクロが真の威力を発揮するのは、ファイルサーバや社内EDMS(図面管理システム)と連携させた瞬間である。
Webサムネイル用のメタデータ埋め込み
出力されたJPGは、そのまま社内イントラネットの図面検索ポータルのサムネイルとして使用できる。
WindowsタスクスケジューラやPython等のウォッチャー(Watchdog)を走らせておけば、該当ディレクトリに `~.dwg` と `~.jpg` が生成された瞬間をフックし、図面管理DBに画像バイナリを自動インデックスさせることが可能だ。
ショートカットキー(Ctrl+S)へのバインド
社内運用を徹底させる場合、ACAD.PGPやCUI(カスタムユーザーインターフェース)を用いて、標準の `QSAVE` コマンドをこのマクロにリダイレクトする手法が極めて有効だ。
// CUIマクロ登録例
^C^C_-vbarun “Mod_IntegratedSave.ExecuteIntegratedSave”;
設計者は「単にいつも通り保存した」という認知のまま、背後では完全に同期されたPDFとJPGが整然と生成され続ける。
—
6. 結論:同期性の維持がシステム資産の寿命を決める
図面管理の破綻は、常に「図面を修正したのに、PDFの更新を忘れた」「プレビューが古くて誤作動を招いた」というデータの非同期性から始まる。
AutoCAD VBAは古き良きテクノロジーだが、COMインターフェースの深層を理解し、ActiveXオブジェクトを正確に調教すれば、最新のクラウドPLM/PIMシステムに匹敵する堅牢なパイプラインをローカル/オンプレミス環境で構築できる。
ツールをただ動かすエンジニアから、データの整合性をアーキテクチャレベルで保証するシステムアーキテクトへ。本稿のコードを土台に、現場の不整合をゼロへと追い込んでいただきたい。
