SolidWorks VBAの墓場を浄化せよ:アセンブリ自動化におけるクラスモジュール設計の極意
SolidWorks APIを長年叩いてきた者なら誰もが一度は遭遇する「スパゲッティ・コードの悪夢」。`swApp` や `swModel` をグローバル変数として野放しにし、`DoEvents` で誤魔化しながら力技で合致(Mate)をねじ込む――。そんなコードは、数年後の自分自身を苦しめる呪縛に他ならない。
本稿では、VBAという制約の多い環境下で、いかにして「オブジェクト指向の作法」を持ち込み、アセンブリ構築の保守性を極限まで高めるかを伝授する。
—
1. なぜ「グローバル変数依存」は死を招くのか
標準モジュールに `Public swApp As SldWorks.SldWorks` を書くのは、プログラミングにおける「地雷原」を自ら設置する行為だ。
- 状態の汚染: どこでオブジェクトが解放されたか追跡不能になる。
- 再入可能性の欠如: 複数のアセンブリを同時に扱うプロセスで、参照の衝突が起きる。
- テスト不能性: ユニットテストが不可能な構造は、将来のOSアップデートで必ず崩壊する。
我々が目指すべきは、「SolidWorksの操作をカプセル化し、呼び出し側から詳細を隠蔽する」アーキテクチャだ。
—
2. 実践:アセンブリ構築をクラスへ昇華させる
まずは、アセンブリ操作の責務を持つクラス `AssemblyManager` を作成する。ここで重要なのは、外部との依存関係をコンストラクタ(的な初期化メソッド)で制御することだ。
クラスモジュール: `AssemblyManager.cls`
Option Explicit
‘ 内部で保持する参照をPrivateで隠蔽(カプセル化)
Private m_swApp As SldWorks.SldWorks
Private m_swAssy As SldWorks.AssemblyDoc
‘ 初期化時に参照を注入(依存性の注入)
Public Sub Initialize(ByVal swApp As SldWorks.SldWorks, ByVal swAssy As SldWorks.AssemblyDoc)
Set m_swApp = swApp
Set m_swAssy = swAssy
End Sub
‘ 責任分界点:部品追加と合致作成をメソッド化
Public Function AddAndMate(ByVal filePath As String, ByVal mateName As String) As Boolean
Dim swComp As SldWorks.Component2
‘ 部品の追加
Set swComp = m_swAssy.AddComponent6(filePath, “0”, 0, 0, 0, False, False)
If swComp Is Nothing Then Exit Function
‘ 合致の作成(ここでは簡易的に同軸合致を想定)
‘ ※本来はここでSelectionManagerを経由して面を選択する
‘ 複雑な選択ロジックをここに閉じ込めることで、メイン処理が劇的にスリム化される
AddAndMate = True
End Function
‘ メモリ最適化:明示的な参照解放
Private Sub Class_Terminate()
Set m_swAssy = Nothing
Set m_swApp = Nothing
End Sub
—
3. メモリ管理とパフォーマンスの真実
VBAはガベージコレクションが脆弱だ。SolidWorks APIで特に注意すべきは、`SelectionManager` のような一時的なオブジェクトがメモリ上に残留し、次の処理の挙動を不安定にさせることである。
- `Set Nothing` の徹底: クラスの `Terminate` イベントや、ループ処理の終了時に必ず明示的に解放せよ。
- `DoEvents` の禁忌: 画面描画を更新したいがために `DoEvents` を多用するのは素人だ。`swModel.ViewZoomtofit2` などが必要な場合を除き、API実行時は描画をサスペンド(`swApp.Visible = False` 等)させることが、高速化の鉄則である。
—
4. 呼び出し側のモダンなアーキテクチャ
標準モジュールは、ただクラスを呼び出す「指揮官」に徹するべきだ。
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swAssy As SldWorks.AssemblyDoc
Dim manager As AssemblyManager
Set swApp = Application.SldWorks
Set swAssy = swApp.ActiveDoc
‘ インスタンス生成
Set manager = New AssemblyManager
manager.Initialize swApp, swAssy
‘ スパゲッティが消えたクリーンなメイン処理
If manager.AddAndMate(“C:\Parts\Bolt.sldprt”, “Mate_Bolt_01”) Then
Debug.Print “Success”
End If
‘ 明示的破棄
Set manager = Nothing
End Sub
—
5. シニアエンジニアへの提言:レガシーとの共存
既存の数万行のレガシーコードを書き換えるのは現実的ではないかもしれない。その場合、「ストラングラー(絞殺)パターン」を採用せよ。
1. 新しく追加する機能だけをクラスモジュール化する。
2. 古い標準モジュールのメソッドから、新しいクラスを呼び出すように書き換える。
3. 少しずつ古い処理を新しいクラスへ移行する。
最後に
VBAは「時代遅れの言語」ではない。SolidWorksという巨大なエンジンの心臓部に直接アクセスできる、極めて強力なインターフェースだ。そのポテンシャルを引き出すのは、言語の限界ではなく、設計者の知性と規律である。
コードが「動く」ことは最低条件だ。我々が目指すべきは、「誰がメンテナンスしても壊れない、堅牢なシステム」である。今日から、`Public`変数を排除し、クラスの海へ飛び込む勇気を持ってほしい。
