SolidWorks VBAを掌握する極限の知見:【マルチドキュメント管理】Documentsファイルコレクションを巡回した複数図面の一括印刷自動化
こんにちは。長年、製造業のCAD/PLM統合と大規模な業務自動化の最前線に立ってきたチーフアーキテクトだ。
SolidWorksのAPIを活用する際、単一ドキュメントの操作で満足しているうちは、まだ初級の域を出ない。実務の現場では常に「数百枚の図面の一括処理」「メモリリークとの戦い」「裏で動作するCOMプロセスの完全制御」といった泥臭い課題が立ちはだかる。
特に、複数図面の一括印刷は、一見単純なループ処理に見えて、その実態はSolidWorksのオブジェクトライフサイクルとWindowsのメモリ管理の急所を突く危険な領域だ。今回は、`SldWorks.Application`が抱える`Documents`コレクションの真の挙動を暴き、破綻のない堅牢な一括印刷自動化アーキテクチャを解説する。
—
1. 現場を崩壊させる「メモリリーク」と「ゾンビプロセス」の正体
多くのVBAエンジニアが犯す最大の過ちは、開いた図面を閉じるときに`ModelDoc2`オブジェクトを適切に解放せず、`Set swModel = Nothing`だけで満足してしまうことだ。
SolidWorksのAPIアーキテクチャにおいて、COMオブジェクトの参照カウントと、SolidWorks内部のドキュメントバッファ(RAM上の実体)は完全に一致しない。特に`SldWorks.QuitDoc`や`IAssemblyDoc`、`IDrawingDoc`の操作を誤ると、裏で見えないプロセス(ゾンビプロセス)が残り、100枚もループを回した頃にはメモリが枯渇してSolidWorksが沈黙する。
これを防ぐための鉄則は以下の3点だ。
1. 暗黙のオープンを避ける: ディスクから読み込む際は、表示モード(サイレントモードや軽量モード)を明示的に制御する。
2. 完全なドキュメント破棄: 処理が終わったドキュメントは、メモリから完全にアンロード(`CloseDoc`)する。
3. エラーハンドリングの強制: 1枚の図面が破損していてエラーを起こしても、全体のバッチ処理が途中で止まらない堅牢なトランザクション構造にする。
—
2. 実装:複数図面一括印刷マクロの全貌
以下に、指定フォルダ内の図面(`.slddrw`)を巡回し、メモリを極限まで最適化しながらバックグラウンドに近い挙動で高速印刷を行う実用コードを提示する。
Option Explicit
‘ =================================================================================
‘ 伝説のアーキテクトが贈る:SolidWorks 複数図面高速一括印刷エンジン
‘ =================================================================================
Sub MasterBatchPrintEngine()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim targetFolder As String
Dim fileName As String
Dim fso As Object
Dim folderObj As Object
Dim fileObj As Object
‘ 処理カウンター
Long successCount As Long
Dim errorCount As Long
‘ 1. SldWorks アプリケーションの取得(新規起動はせず既存インスタンスにアタッチ)
On Error Resume Next
Set swApp = GetObject(, “SldWorks.Application”)
On Error GoTo 0
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。起動してから実行してください。”, vbCritical, “致命的エラー”
Exit Sub
End If
‘ 2. 処理対象フォルダの指定(実務ではINIファイルやダイアログから動的取得を推奨)
targetFolder = “C:\CAD_Data\Drawings_To_Print\”
If Right(targetFolder, 1) <> “\” Then targetFolder = targetFolder & “\”
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(targetFolder) Then
MsgBox “指定されたフォルダが存在しません: ” & targetFolder, vbCritical
Exit Sub
End If
Set folderObj = fso.GetFolder(targetFolder)
‘ 3. ユーザー操作の抑制(画面描画とイベントを殺すことでパフォーマンスを最大化)
swApp.UserControl = False
swApp.Visible = True ‘ 描画を完全に止めたい場合はFalseだが、フリーズと誤認されるためTrue推奨
successCount = 0
errorCount = 0
‘ 4. ファイルコレクションの巡回
For Each fileObj In folderObj.Files
If LCase(fso.GetExtensionName(fileObj.Name)) = “slddrw” Then
fileName = fileObj.Path
‘ トランザクション保護(1枚のエラーで全バッチを止めない)
On Error GoTo ErrorHandler
‘ 【極限知見】サイレントオープンによるメモリと描画の最適化
‘ 3番目の引数(Options)に 1 (swOpenDocOptions_Silent) を指定し、余計なダイアログを出させない
Dim errors As Long
Dim warnings As Long
Set swModel = swApp.OpenDoc6(fileName, 3, 1, “”, errors, warnings) ‘ 3 = swDocDRAWING
If Not swModel Is Nothing Then
‘ 印刷実行のプリミティブ設定
Dim pageSetup As SldWorks.PageSetup
Set pageSetup = swModel.PageSetup
‘ 必要に応じここで用紙サイズや向きをコードから強制上書き可能
‘ pageSetup.Orientation = 1 ‘ 0:縦, 1:横
‘ 図面ドキュメントとしての印刷処理
Dim printStatus As Boolean
printStatus = ExecuteDrawingPrint(swModel)
If printStatus Then
successCount = successCount + 1
Else
errorCount = errorCount + 1
End If
‘ 【最重要】ドキュメントを完全にメモリから解放して閉じる
‘ 第1引数はファイル名、第2引数は変更を破棄するかどうか (False = 変更破棄)
Dim docTitle As String
docTitle = swModel.GetTitle
‘ オブジェクトの明示的破棄
Set swModel = Nothing
swApp.CloseDoc docTitle
Else
‘ オープン失敗
errorCount = errorCount + 1
End If
GoTo NextFile
ErrorHandler:
‘ 異常系キャッチ
errorCount = errorCount + 1
If Not swModel Is Nothing Then
Set swModel = Nothing
End If
Resume Next
NextFile:
On Error GoTo 0
End If
Next fileObj
‘ 5. 後始末と復元
swApp.UserControl = True
‘ 完了レポート
MsgBox “一括印刷処理が完了しました。” & vbCrLf & _
“成功: ” & successCount & ” 件” & vbCrLf & _
“失敗/スキップ: ” & errorCount & ” 件”, vbInformation, “バッチ処理完了”
‘ オブジェクトの完全解放
Set swApp = Nothing
Set fso = Nothing
Set folderObj = Nothing
End Sub
‘ =================================================================================
‘ 補助関数:図面ドキュメントのプリンター出力カプセル化
‘ =================================================================================
Private Function ExecuteDrawingPrint(ByRef model As SldWorks.ModelDoc2) As Boolean
On Error GoTo PrintError
Dim drawDoc As SldWorks.DrawingDoc
Set drawDoc = model
‘ プリンター設定構造体の取得またはデフォルト印刷の実行
‘ ※環境に応じたプリンター名義や詳細設定が必要な場合はここで拡張する
‘ 例: 標準プリンターへの全シート出力
Dim status As Boolean
‘ 引数の仕様: PrintOut3( シート指定, 部数, 複数ページ設定, 等々… )
‘ 実際のプロダクション環境では PrinterSetup や PageSetup の詳細設定を挟むべき
status = model.PrintOut2(Empty) ‘ アクティブシートまたはデフォルト設定での印刷
ExecuteDrawingPrint = status
Exit Function
PrintError:
ExecuteDrawingPrint = False
End Function
—
3. シニアエンジニアが押さえておくべき「APIの急所」
上記のコードには、単なる「動くコード」を超えた、現場で生き残るための高度な設計思想が組み込まれている。
`OpenDoc6` の第3引数 (`swOpenDocOptions_Silent`) の活用
大規模な図面を普通に開くと、外部参照(アセンブリや部品)のロードパスエラーや、コンフィギュレーションの選択ダイアログがポップアップし、バッチ処理が完全に停止する。`Silent` モードで開くことにより、UIスレッドをブロックせずにバックグラウンド処理に近い挙動を実現できる。
`CloseDoc` と `Set swModel = Nothing` の順序
COMラッパーであるVBAにおいて、メモリリークの温床になるのは「参照の切り離し忘れ」だ。
必ず以下の順序を厳守すること。
1. `Set swModel = Nothing` (VBA側のポインタ参照を先に切る)
2. `swApp.CloseDoc docTitle` (SolidWorks側のドキュメントバッファを解放する)
この順序を逆にすると、COMの参照カウントが正しくデクリメントされず、SolidWorksのプロセス内にゾンビオブジェクトが残り続ける。
—
4. システム間連携への拡張:PLM/PDMとの融合
このマクロ単体でも強力だが、実務ではこれをさらに昇華させる必要がある。例えば、PDM(SolidWorks PDM)や外部の生産管理システム(ERP)から「本日の製造指示図面リスト(CSV/JSON)」を受け取り、ファイルコレクションを直接巡回するのではなく、リストに紐づく特定の版(Revision)の図面のみをピンポイントでバッチ印刷するアーキテクチャへの拡張だ。
その場合、ファイルパスのハードコーディングを廃し、データベースやAPIサーバーからのストリームをVBAのメモリ上で処理する、あるいはVBAから外販のVB.NET製コンソールアプリケーションをキックするハイブリッド構成をとるのが、シニアアーキテクトとしての正しい判断となる。
結びにかえて
SolidWorks VBAは、レガシーと言われることもある。しかし、その裏側にあるAPIの構造とメモリ管理のルールを完全に掌握していれば、数千万円規模市販システムのどの機能よりも高速で、現場のニーズにジャストフィットする自動化システムを構築できる。
妥協のないコードを書き上げ、非効率な手作業を根絶やしにしてほしい。それが、プロのエンジニアリングだ。
