SolidWorks VBAの限界を突破する:アセンブリ構築におけるクラス設計とファクトリーパターンの実装
SolidWorksの自動化において、`swApp.ActivateDoc` を繰り返すだけの「場当たり的なスクリプト」は、もはやエンジニアリングとは呼べない。数千点の部品を扱う大規模アセンブリにおいて、モジュールレベルの変数が乱立し、エラーハンドリングが散逸したスパゲッティコードは、将来の保守コストを劇的に増大させる。
今日は、VBAというレガシーな枠組みの中で、いかにして「オブジェクト指向」の設計思想を注入し、拡張性の高いアセンブリ構築エンジンを設計するか、その極意を伝授する。
—
なぜ「手続き型」のVBAは破綻するのか
SolidWorks APIはCOMベースであり、オブジェクトの生成と破棄の管理が極めて重要だ。
`swApp` や `swModel` をグローバル変数に垂れ流し、`Set` 文を羅列するだけのコードでは、メモリリークや、不完全な合致(Mate)によるアセンブリの不安定化を回避できない。
我々が目指すべきは、部品(Component)を「データ」として扱うのではなく、振る舞いを持つ「オブジェクト」として定義することだ。
—
1. ファクトリーパターンによる「合致」の抽象化
複雑なアセンブリを構築する際、部品ごとに固有の合致ロジック(同心円、距離、角度など)をメインルーチンに書くのは愚策だ。`MateFactory` クラスを導入し、部品種別に応じた合致インターフェースを統一する。
実装例:IMateStrategy インターフェースの概念
VBAには厳密なインターフェース機能がないため、クラスモジュールをインターフェースとして定義し、ポリモーフィズムを擬似的に実現する。
‘ クラスモジュール: IMateStrategy (インターフェースの役割)
Public Sub ApplyMate(ByVal swAsm As SldWorks.AssemblyDoc, ByVal swComp As SldWorks.Component2)
‘ このメソッドは派生クラスで必ず実装する
Err.Raise 999, “IMateStrategy”, “メソッドが実装されていません。”
End Sub
具象クラス:ShaftMateStrategy
‘ クラスモジュール: ShaftMateStrategy
Implements IMateStrategy
Public Sub IMateStrategy_ApplyMate(swAsm As SldWorks.AssemblyDoc, swComp As SldWorks.Component2)
‘ ここに軸部品特有の同心円合致ロジックを記述
‘ swAsm.AddMate5 …
End Sub
—
2. メモリ最適化とオブジェクトのライフサイクル管理
VBAはガベージコレクションが脆弱だ。SolidWorks APIのオブジェクトは参照カウントで管理されているため、不要になった `Component` や `Feature` オブジェクトは、明示的に `Nothing` を代入してメモリを解放し、参照カウントを減らす必要がある。
特に、巨大アセンブリのループ処理では、以下の作法を徹底せよ。
‘ 推奨されるメモリ解放パターン
Dim swComp As SldWorks.Component2
For i = 0 To UBound(vComps)
Set swComp = vComps(i)
‘ 処理実行
Call ProcessComponent(swComp)
‘ 厳密なメモリ解放
Set swComp = Nothing
Next i
チーフアーキテクトの知見:
`DoEvents` をループ内に挟むことは必須だが、過度な呼び出しはパフォーマンスを劣化させる。`100回に1回` 程度の頻度で呼び出すのが、UIのフリーズを防ぐ最適解だ。
—
3. Windows APIによる「異常検知」の先制
SolidWorksの標準エラーハンドリングだけでは、バックグラウンドでのダイアログ表示による停止(モーダルダイアログによるハングアップ)を防げない。`User32.dll` を呼び出し、ウィンドウクラスを監視することで、自動化を中断させない堅牢なシステムを構築する。
‘ モジュール: WinAPI_Helper
Private Declare PtrSafe Function FindWindow Lib “user32” Alias “FindWindowA” _
(ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Public Sub ForceCloseDialog(ByVal dialogTitle As String)
Dim hWnd As LongPtr
hWnd = FindWindow(vbNullString, dialogTitle)
If hWnd <> 0 Then
‘ エラーダイアログを強制的に閉じる、またはスキップする処理
End If
End Sub
—
結論:コードは「資産」であれ
今回示した「クラスモジュールによる責務の分離」と「ファクトリーパターンによる拡張」は、一見するとコード量が増え、煩雑に感じるかもしれない。しかし、半年後に仕様変更が起きたとき、`Main` プロシージャを一行も書き換えず、新しい `MateStrategy` クラスを追加するだけで対応できるとしたらどうだろう?
優れたエンジニアは、動くものを作るのではない。仕様変更が起きたときに、最小限の修正で済む「構造」を作るのだ。
SolidWorks VBAというレガシーな環境であっても、設計思想をモダンに保つことで、それは強固な自動化資産へと昇華する。明日からの開発では、`Sub` の中身を空にしてでも、クラス設計から書き始めてほしい。それが、プロフェッショナルへの第一歩である。
