伝説のコード:SolidWorksアセンブリにおける「名無しのコンポーネント」を狩り尽くす最適化術
現場で戦い続けるエンジニア諸君。SolidWorks APIの海を漂う時、最も恐ろしいのは「不確定なコンポーネントへのアクセス」だ。何千もの部品で構成されたアセンブリにおいて、ツリーを一つずつ手繰り寄せ、名前を照合するなどという作業は、自動化の時代には滑稽でしかない。
今日は、アセンブリ内のコンポーネントを名前の部分一致(ワイルドカード)で一括特定し、メモリを浪費せずに制御下に置くための「極限の知見」を授ける。
—
1. なぜ「単純なループ」がシステムを殺すのか
初心者は `RootComponent` から `GetChildren` を再帰的に呼び出すだけのコードを書く。だが、大規模アセンブリでこれをやれば、オブジェクトの生成コストとガーベジコレクションのタイミングにより、SolidWorksは容易にフリーズする。
我々アーキテクトが重視するのは以下の3点だ。
- Late Bindingの回避: 速度を求めるなら初期バインディング一択だが、レガシー環境の差異を吸収するなら例外処理を組み込んだ制御が必要。
- メモリ解放の徹底: `Set swComp = Nothing` は単なる儀式ではない。COMオブジェクトの参照カウントを管理しない者は、APIを扱う資格がない。
- ワイルドカードの抽象化: ユーザーが欲しているのは「名前の一部」だ。これを最適化されたメモリ空間で高速に照合する。
—
2. 実践:アセンブリ・コンポーネント一括選択スクリプト
以下に、再帰処理を極限まで最適化し、かつ安全にコンポーネントをハンドルするコードを記す。
Option Explicit
‘ SolidWorks APIを扱う際の鉄則:オブジェクトは必要最小限の生存期間にする
Public Sub SelectComponentsByWildcard(ByVal targetPattern As String)
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim swRootComp As SldWorks.Component2
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
‘ モデルタイプチェック(防御的プログラミングの基本)
If swModel Is Nothing Or swModel.GetType <> swDocASSEMBLY Then
MsgBox “アセンブリを開いてください。”, vbCritical
Exit Sub
End If
Set swAssy = swModel
Set swRootComp = swAssy.GetRootComponent3(True)
‘ 選択状態をクリア(パフォーマンスのために重要)
swModel.ClearSelection2 True
‘ 再帰検索開始
SearchAndSelect swRootComp, targetPattern, swModel
Set swRootComp = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
End Sub
Private Sub SearchAndSelect(ByVal swComp As SldWorks.Component2, ByVal pattern As String, ByVal swModel As SldWorks.ModelDoc2)
Dim vChildren As Variant
Dim swChild As SldWorks.Component2
Dim i As Long
vChildren = swComp.GetChildren
If IsEmpty(vChildren) Then Exit Sub
For i = LBound(vChildren) To UBound(vChildren)
Set swChild = vChildren(i)
‘ 名前の一致チェック(Like演算子はVBAの最強の武器の一つ)
‘ ※ “” & pattern & “” で部分一致
If swChild.Name2 Like “” & pattern & “” Then
‘ 選択(AddはTrueで蓄積、Falseで新規)
swChild.Select4 True, Nothing, False
End If
‘ サブアセンブリへの再帰
SearchAndSelect swChild, pattern, swModel
‘ メモリ解放:深い再帰でのスタックオーバーフローとリークを防ぐ
Set swChild = Nothing
Next i
End Sub
—
3. シニアエンジニアが押さえるべき「最適化の要諦」
1. `GetChildren` の挙動を理解せよ
大規模アセンブリにおいて、`GetChildren` は配列を返す。配列のサイズを毎回取得するのではなく、一度の代入で処理を行う。また、非表示コンポーネントを含めるかどうかのフラグは状況に応じて適切に使い分けろ。
2. コンテキストメニューへの統合
このマクロを単体で動かすのは、あくまでテスト段階までだ。実際の現場では、SolidWorksのコマンドマネージャーにボタンとして配置し、かつマクロ実行前に必ず `SelectionManager` で現在の選択セットをクリーンアップする処理を組み込むべきだ。
3. レガシー環境とWindows APIの連携
もし、このツールを「社内共通ライブラリ」として配布するなら、`GetOpenFileName` などのAPIを呼び出し、コンポーネント名を外部CSVやExcelから一括読み込みして処理する拡張性を持たせることを推奨する。VBAは単体で動くものではなく、システム全体のデータフローの一部であるべきだからだ。
終わりに
プログラミングは「書くこと」よりも「いかに不要な処理を削ぎ落とすか」に真髄がある。このコードをベースに、君たちの現場の要件に合わせてカスタマイズしてほしい。
だが忘れるな。「自動化とは、手作業を機械に置き換えることではなく、手作業そのものを不要にするアーキテクチャを構築することである」。
健闘を祈る。
