構成の迷宮を突破せよ:複数コンフィギュレーションの図面自動展開における極限の設計思想
SolidWorksの自動化において、多くのエンジニアが陥る罠がある。「APIリファレンスにある関数を組み合わせれば動く」という幻想だ。
単一の部品や単純なアセンブリであればそれで十分だろう。しかし、実務レベルの製品開発では、1つのアセンブリファイルに数十、数百のコンフィギュレーション(構成)が定義されている。これらをすべて個別のシートに展開し、ビューを配置し、フォーマットを制御する。この規模の処理を単純なループで回せば、メモリは肥大化し、COMオブジェクトの参照カウントは乱れ、最終的にSolidWorksは「予期せぬエラー」と共に静かに、しかし確実にクラッシュする。
本稿では、単なるコードの書き方ではなく、オブジェクトのライフサイクル管理とメモリ最適化に焦点を当てた、プロフェッショナルな自動展開アーキテクチャを解説する。
1. アーキテクチャの急所:なぜ「単純なループ」では破綻するのか
多くの初中級者が書くコードは、`ActiveDoc` に依存している。これは致命的な設計ミスだ。
COMオブジェクトの不可視な連鎖
SolidWorks VBAはCOM(Component Object Model)を介して動作している。`ModelDoc2` や `DrawingDoc` といったオブジェクトは、内部的に複雑な参照関係を持っており、明示的に解放しない限り、メモリ上に残存する。特にコンフィギュレーションを切り替えるたびにビューを生成する処理では、内部的に一時的なモデルインスタンスが生成され、それが蓄積することでリソースリークを引き起こす。
ビュー生成のコスト
`CreateDrawViewFromModelView3` などのメソッドは、内部的にモデルの再構築(Rebuild)をトリガーする。100シートの図面を作る際、毎回フルリビルドを走らせれば、計算時間は指数関数的に増大する。
結論として、我々が実装すべきは「状態の最小化」と「決定論的なリソース解放」を徹底したパイプラインである。
2. 極限の実装:全コンフィギュレーション自動展開エンジン
以下に、実務レベルで耐えうる実装例を示す。ここでは、Windows APIを利用したメモリ制御の視点と、オブジェクトの厳格なスコープ管理を導入している。
Option Explicit
' Windows API: メモリのワーキングセットを強制的に最小化し、
' 大量処理時のメモリ肥大化によるシステム不安定化を抑制する
Private Declare PtrSafe Function EmptyWorkingSet Lib "psapi.dll" (ByVal hProcess As LongPtr) As Long
Private Declare PtrSafe Function GetCurrentProcess As LongPtr () As LongPtr
Sub ExportAllConfigurationsToDrawing()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swDraw As SldWorks.DrawingDoc
Dim vConfigs As Variant
Dim configName As Variant
Dim i As Integer
' 初期化
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox "アセンブリファイルを開いてください。", vbCritical
Exit Sub
End If
If swModel.GetType <> swDocASSEMBLY Then
MsgBox "このマクロはアセンブリ専用です。", vbCritical
Exit Sub
End If
' 1. コンフィギュレーションリストの取得
vConfigs = swModel.GetConfigurationNames()
' 2. 図面ファイルの新規作成 (テンプレート指定)
' テンプレートパスは環境に合わせて最適化すること
Set swDraw = swApp.NewDocument("C:\SW_Templates\Drawing_Standard.drw", 0, 0, 0)
If swDraw Is Nothing Then
MsgBox "図面テンプレートの読み込みに失敗しました。", vbCritical
Exit Sub
End If
' 画面更新の停止 (パフォーマンス劇的向上)
swApp.UserControl = False
On Error GoTo ErrorHandler
For i = 0 To UBound(vConfigs)
configName = vConfigs(i)
' --- ライフサイクル管理の核心 ---
' 各コンフィギュレーションごとに独立したスコープで処理を行う
ProcessConfigurationSheet swApp, swModel, swDraw, CStr(configName), i + 1
' 10シートごとにメモリを強制解放し、OSにリソースを返す
If (i + 1) Mod 10 = 0 Then
EmptyWorkingSet GetCurrentProcess()
End If
Next i
' 後処理
swApp.UserControl = True
MsgBox "全コンフィギュレーションの展開が完了しました。", vbInformation
CleanUp:
' オブジェクトの明示的解放 (逆順に解放するのが鉄則)
Set swDraw = Nothing
Set swModel = Nothing
Set swApp = Nothing
Exit Sub
ErrorHandler:
MsgBox "エラー発生: " & Err.Description, vbCritical
Resume CleanUp
End Sub
' 各シートの生成とビュー配置をカプセル化したサブルーチン
Private Sub ProcessConfigurationSheet(ByRef swApp As SldWorks.SldWorks, _
ByRef swModel As SldWorks.ModelDoc2, _
ByRef swDraw As SldWorks.DrawingDoc, _
ByVal configName As String, _
ByVal sheetIndex As Integer)
Dim swSheet As SldWorks.Sheet
Dim swView As SldWorks.View
Dim sheetName As String
sheetName = "Config_" & configName
' 1. 新規シートの作成
' 既存のシートフォーマットを維持しつつ、名前をコンフィギュレーション名に設定
swDraw.CreateSheet sheetName, 0, 0, 1 ' 1 = 標準フォーマット
' 2. モデルのコンフィギュレーションを切り替え
' ここでモデル側の状態を確定させる
swModel.ShowConfiguration2 configName
' 3. ビューの配置 (例: 正面ビュー)
' CreateDrawViewFromModelView3 の引数は極めて重要
' ViewName: "*Front", X, Y, Z
Set swView = swDraw.CreateDrawViewFromModelView3("*Front", 0.1, 0.1, 0)
If Not swView Is Nothing Then
' ビューに紐づくコンフィギュレーションを明示的に指定
' これを怠ると、後でコンフィギュレーションを切り替えた際にビューが同期し、意図しない結果になる
swView.ReferencedConfiguration = configName
End If
' 4. ビューの再構築を最小限に抑える
swView.ForceRebuild
' ローカルオブジェクトの解放
Set swView = Nothing
Set swSheet = Nothing
End Sub
3. チーフアーキテクトによる技術的深掘り
3.1 `EmptyWorkingSet` APIの戦略的導入
VBAのガベージコレクションは極めて緩慢である。特にSolidWorksのような巨大なCOMオブジェクトを扱う場合、`Set obj = Nothing` だけでは十分ではない。`psapi.dll` の `EmptyWorkingSet` を呼び出すことで、プロセスの物理メモリ(ワーキングセット)を強制的にトリミングし、ページファイルへの退避を促す。これにより、数千ビューを生成するような極限環境でも、OSレベルでのメモリ枯渇(Out of Memory)を回避できる。
3.2 `ReferencedConfiguration` の決定論的制御
初心者が最も犯すミスは、`swModel.ShowConfiguration2` でモデルを切り替えてビューを作れば、そのビューはその構成で固定されると思い込むことだ。
しかし、SolidWorksのビューはデフォルトで「モデルの現在の状態」を参照する設定になっている場合がある。`swView.ReferencedConfiguration = configName` と明示的に書き込むことで、モデルの状態に依存しない決定論的な図面を構築できる。これはレガシー環境での保守において、再構築時にビューが勝手に切り替わる悪夢を防ぐ唯一の手法である。
3.3 パフォーマンスのボトルネック:`UserControl`
`swApp.UserControl = False` は、GUIの更新を抑制する。これを忘れると、シートが切り替わり、ビューが描画されるたびに画面がリフレッシュされ、CPUリソースの大半が描画処理に消費される。バックエンド処理においては、ユーザーインターフェースは「コスト」でしかない。
4. 保守とシステム連携への展望
このシステムをさらに拡張する場合、以下の3点を検討せよ。
1. エラーハンドリングの階層化: `On Error Resume Next` は禁忌である。各サブルーチンでエラーをキャッチし、どのコンフィギュレーションで失敗したかをログに出力するスタックトレースを実装せよ。
2. 外部定義ファイル(CSV/JSON)との連携: コンフィギュレーション名と配置すべきビュー名(例:正面、平面、詳細A)の対応表を外部に持たせることで、VBAコードを触らずに図面構成を変更可能にする。
3. マルチスレッドの限界: SolidWorks APIはシングルスレッド(STA)である。無理に並列処理をさせようとすれば、COMのマーシャリングエラーで確実に破綻する。速度を求めるなら、複数のSolidWorksインスタンスを別プロセスで立ち上げ、タスクを分散させる「プロセス並列化」を検討せよ。
結びに代えて
自動化とは、単に人間がやる作業をコードに置き換えることではない。「ソフトウェアの挙動を完全に制御下に置き、不確定要素を排除すること」である。
オブジェクトのライフサイクルを掌握し、メモリの挙動を予測し、APIの裏側に潜む仕様を理解したとき、VBAは単なるマクロから、堅牢なエンジニアリングシステムへと昇華する。
