【SolidWorks VBA極限の知見】マウス選択の呪縛からの解放:SelectionManagerによる「完全無欠のプログラム制御」
SolidWorksのマクロ開発において、最もナンセンスで、かつ最も排除すべき悪習は何か。
それは、「ユーザーに画面上のパーツを手動でクリックさせること」だ。
「アセンブリを開いたら、まず目的の部品をクリックしてください」
「合致させたい面を2つ選択してからマクロを実行してください」
もし、あなたの社内システムや自動化スクリプトが、このようなオペレーションをユーザーに要求しているならば、それは自動化ではなく、単なる「作業の分断」にすぎない。真のエンジニアリングとは、人間に依存したヒューマンエラーの余地を徹底的に削ぎ落とすことにある。
今回は、SelectionManagerとComponent2オブジェクトの深淵を暴き、画面上のマウス操作を一切介在させずに、VBAコードだけでアセンブリ内のパーツをミリ秒単位で特定、トラバース(走査)、そしてハイライトする極限の知見を授ける。
—
1. 選択(Selection)のメカニズムとSelectionManagerの正体
多くの初学者は、`SldWorks.ModelDoc2.Extension.SelectByID2` を呼び出せばパーツが選択できることを知る。しかし、それが「なぜ成功するのか」「内部でメモリとSolidWorksのポインタがどう動いているのか」を理解している者は少ない。
SolidWorksのGUI環境において、選択状態(Selected)とは、単なるフラグではない。SelectionManagerが保持するアクティブなセレクションリスト(SelectionList)に対するポインタの登録を意味する。
コードからパーツを特定し、ハイライトするアプローチには、以下の2つのルートが存在する。
1. 文字列ベースのパス指定(`SelectByID2`):
最も手軽だが、コンポーネント階層が深くなるとパス文字列の構築に失敗するリスクがある。
2. コンポーネントオブジェクトからの直接選択(`Component2.Select4`):
実務において最強かつ唯一信頼すべきアプローチ。メモリ上のアセンブリ構造から直接オブジェクトをハンドリングするため、GUIの描画状態に依存しない。
—
2. 【実践】マウス選択を完全排除するVBAコード
以下のコードは、アセンブリルートから指定したパーツ名(コンポーネント名)をプログラム側で完全自動検索し、画面上のクリックを一切必要とせずに、そのパーツを強制選択(ハイライト)させる実用コードである。
レガシーなVBA環境であっても、メモリリークを確実に防ぐためのオブジェクト解放のイディオム(`Set xxx = Nothing`)を完備している。
‘ ==============================================================================
‘ 伝説のチーフアーキテクトによる実装:マウスレス・コンポーネント特定&ハイライト
‘ ==============================================================================
Sub SelectComponentProgrammatically()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssm As SldWorks.AssemblyDoc
Dim swSelMgr As SldWorks.SelectionMgr
Dim swComp As SldWorks.Component2
‘ ターゲットとするコンポーネント名(拡張子なし、またはインスタンス名を含む)
‘ 例: “Casing_Base-1” など
Const TARGET_COMP_NAME As String = “Casing_Base-1”
Dim bRet As Boolean
‘ 1. アプリケーションおよびドキュメントの取得
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “致命的エラー”
Exit Sub
End If
‘ アセンブリドキュメントかどうかの型チェック(Guard Clause)
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “このマクロはアセンブリドキュメントでのみ実行可能です。”, vbCritical, “型不一致”
Exit Sub
End If
Set swAssm = swModel
‘ 2. SelectionManagerの取得
Set swSelMgr = swModel.SelectionManager
‘ 3. 既存の選択状態をクリア(クリーンな状態からのスタートは鉄則)
swModel.ClearSelection2 True
‘ 4. コンポーネントの直接取得(トラバース or ルート直下検索)
‘ ※今回は堅牢性を考慮し、アセンブリ内の全コンポーネント配列を取得して走査する
Dim vComps As Variant
vComps = swAssm.GetComponents(False) ‘ False = トップレベルのみではなく全階層を取得
If IsEmpty(vComps) Then
MsgBox “アセンブリ内にコンポーネントが見つかりません。”, vbExclamation
GoTo CleanUp
End If
Dim i As Long
Dim foundComp As SldWorks.Component2
Set foundComp = Nothing
For i = LBound(vComps) To UBound(vComps)
Set swComp = vComps(i)
‘ コンポーネントの名称を比較 (Name2プロパティを使用)
‘ 例: “Casing_Base-1” や “SubAssembly1-1/Part1-2” など
If UCase(swComp.Name2) = UCase(TARGET_COMP_NAME) Then
Set foundComp = swComp
Exit For
End If
‘ ループ内でのメモリ解放
Set swComp = Nothing
Next i
‘ 5. 発見したパーツのプログラム的選択(ハイライト)
If Not foundComp Is Nothing Then
‘ Select4の引数解説:
‘ Mark = 1 (通常選択), Append = False (既存選択を置き換えるか、Trueで追加)
bRet = foundComp.Select4(False, Nothing, False)
If bRet Then
Debug.Print “成功: [” & TARGET_COMP_NAME & “] をプログラム側で選択しました。”
Else
MsgBox “コンポーネントの選択APIの呼び出しに失敗しました。”, vbExclamation
End If
Else
MsgBox “指定されたコンポーネント [” & TARGET_COMP_NAME & “] はアセンブリ内に存在しません。”, vbExclamation
End If
CleanUp:
‘ 6. 厳格なオブジェクトの明示的解放(メモリ最適化)
‘ VBAのCOMラッパーはガベージコレクションを信用するな。自分で刈り取れ。
Set foundComp = Nothing
Set swComp = Nothing
Set swSelMgr = Nothing
Set swAssm = Nothing
Set swModel = Nothing
Set swApp = Nothing
End Sub
—
3. シニアエンジニアが知るべき「裏側の真実」とパフォーマンス最適化
上記のコードを見て、「ただ動くだけの初歩的な内容だ」と思ったならば、まだSolidWorks APIの本質を理解していない。以下の3つの極限の知見を記憶に刻んでほしい。
① `GetComponents(False)` のコストとメモリ消費
大規模アセンブリ(部品点数が数万点に及ぶような環境)において、`GetComponents(False)` を安易に呼ぶと、バリアント配列の生成とCOMオブジェクトのラップにより、数秒の硬直(フリーズ)を引き起こす。
もしターゲットの階層構造が決まっている、あるいはトップレベル(直下)にしか存在しないことが分かっているならば、`GetComponents(True)` を使用するか、`GetChildren` メソッドを用いた再帰的トラバース(Recursive Traversal)を自作し、メモリフットプリントを最小限に抑えるべきだ。
② `Name2` と `GetPathName` の違い
コンポーネントを特定する際、`Name2` プロパティ(例: `Casing_Base-1`)はインスタンス名を返す。アセンブリ内に同一のボルトが100本ある場合、それぞれ `Bolt-1`, `Bolt-2`… と名前が変わる。
もし「どのインスタンスでもいいから特定の部品ファイルを一括選択したい」という場合は、コンポーネントからマスタードキュメント(`GetModelDoc`)を手繰り寄せ、ファイル名で判定するロジックに拡張する必要がある。
③ COMオブジェクトの解放(`Set xxx = Nothing`)の重要性
VBAの裏側では、SolidWorksのC++製COMオブジェクトが動いている。VBA側で変数がスコープを抜けても、COMの参照カウント(Reference Count)が即座に解放されないケースが多々ある。
これを放置すると、マクロを数回実行しただけでメモリリークを起こし、最悪の場合 SolidWorks本体が強制終了(クラッシュ)する。「取得したオブジェクトは、処理の最後に必ず `Nothing` を代入して参照を断ち切る」。これがプロとアマを分ける絶対の掟である。
—
4. 結びにかえて:システム間連携への飛躍
今回マスターした「マウスを使わずにコードだけでパーツを特定・選択する技術」は、単なるマクロの効率化に留まらない。
例えば、
- 外部の生産管理システム(ERP)からWebSocketやDB経由で飛んできた「変更対象パーツのID」をトリガーに、SolidWorks上の該当部位を自動でハイライトする。
- 独自の設計チェッカー(BOM検証ツール)が、不適合パーツを検出した瞬間に画面上でそれを赤く点滅(選択状態に)させる。
このような、「人間が画面をマウスで触る必要のない、完全自動化されたエンジニアリングパイプライン」の基盤技術となる。
レガシーなVBAであっても、アーキテクチャの理を理解し、メモリとポインタの動きを支配すれば、最新のデスクトップアプリケーションに匹敵する堅牢なシステムを構築できる。
マウスから手を離せ。コードにすべてを語らせろ。
