【テクニカル・上級編】【実務中級】サブアセンブリ(下位アセンブリ)の動的挿入と階層構造を意識したコンポーネント制御 – SolidWorks VBA解析バイブル

スポンサーリンク

【SolidWorks VBA極限解説】サブアセンブリの動的挿入と階層構造制御:メモリリークを断つコンポーネント自動化の極意

SolidWorks APIを用いたアセンブリ自動化において、単体部品(Part)の配置は基本に過ぎない。実務の現場で真に要求されるのは、すでに何重にも階層化されたサブアセンブリ(Sub-Assembly)をプログラムから動的にインポートし、正確に合致(Mate)を定義し、かつ巨大なアセンブリツリー構造を破綻させずにメモリを最適化し続けることだ。

今回は、レガシーなVBA環境であっても、COMのライフサイクルを完全に掌握し、実務の巨大モデルに耐えうる「サブアセンブリ動的挿入の極意」を授ける。

—

1. 階層構造制御とオブジェクトライフサイクルの真実

VBAからSolidWorksを操作する際、多くのプログラマが陥る最大の罠が「COMオブジェクトの解放漏れとコンテキストの迷子」である。
サブアセンブリをアセンブリ内に挿入する時、内部では以下の重厚な処理が走っている。

1. サブアセンブリファイルのメモリ上へのロード(非表示またはバックグラウンド)。
2. メインアセンブリのコンポーネントツリー(`Component2` オブジェクト)へのインスタンス追加。
3. 参照パスの解決とコンフィギュレーション(Configuration)の適用。

これを雑なコードで実装すると、SolidWorksのプロセス内にゾンビオブジェクトが残り、やがて「HRESULT: 0x8001010A (RPC_S_SERVER_CALL_REJECTED)」などのサーバービジーエラーを引き起こす。

シニアが守るべき鉄則

  • インスタンスの連鎖取得を避ける:`swApp.ActiveDoc.Extension…` のようにドットで繋ぎまくるコードは、中間オブジェクトの参照が解放できなくなるため厳禁。
  • 変数のスコープと明示的Nothing:取得した `ModelDoc2` や `Component2` は、用済みになった瞬間に `Set xxx = Nothing` で参照カウントを確実に落とせ。

—

2. 実践:サブアセンブリ動的挿入と合致定義のフルコード

以下のコードは、指定したサブアセンブリをメインアセンブリに動的に挿入し、原点同士を一致(Coincident)させた上で、特定の面同士を合致させる実務直結のプロシージャだ。

‘ Option Explicitは必須。暗黙の変数宣言はVBAにおける万死に値する。
Option Explicit

Sub InsertAndMateSubAssembly()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim swComp As SldWorks.Component2

‘ パス定義(実務ではINIファイルやDBから動的に取得すること)
Const MAIN_ASSY_PATH As String = “C:\Data\MainAssembly.sldasm”
Const SUB_ASSY_PATH As String = “C:\Data\SubAssembly.sldasm”

‘ 1. アプリケーションインスタンスの取得
Set swApp = Application.SldWorks
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。”, vbCritical
Exit Sub
End If

‘ 2. メインアセンブリを開く(すでを開かれている場合はアクティブドキュメントを取得)
Set swModel = swApp.ActivateDoc3(MAIN_ASSY_PATH, False, 0, 0)
If swModel Is Nothing Then
MsgBox “メインアセンブリを開けませんでした: ” & MAIN_ASSY_PATH, vbCritical
Exit Sub
End If

‘ アセンブリドキュメントインターフェースへキャスト
Set swAssy = swModel

‘ 3. サブアセンブリの動的挿入
‘ 引数: FileName, X, Y, Z
Dim transform As SldWorks.MathTransform
Set swComp = swAssy.AddComponent5(SUB_ASSY_PATH, swConfigurationOptDefault_Current, “”, False, “”, 0#, 0#, 0#)

If swComp Is Nothing Then
MsgBox “サブアセンブリの挿入に失敗しました。”, vbCritical
GoTo CleanUp
End If

‘ 4. 挿入されたサブアセンブリのコンテキストを強制再構築(重要)
‘ 階層構造を正確にツリーに反映させるため、FeatureManagerを更新
swModel.EditRebuild3

‘ 5. 合致(Mate)のプログラム的定義
‘ ここではメインアセンブリの原点とサブアセンブリの原点を一致させる例
Call DefineOriginMate(swModel, swAssy, swComp)

MsgBox “サブアセンブリの挿入と合致定義が完了しました。”, vbInformation

CleanUp:
‘ 6. 徹底的なメモリ解放(COM参照の切断)
Set swComp = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
End Sub

Private Sub DefineOriginMate(swModel As SldWorks.ModelDoc2, swAssy As SldWorks.AssemblyDoc, swComp As SldWorks.Component2)
Dim swMateRet As Long

‘ 選択バッファをクリア(前回の選択状態が残っていると合致がバグる)
swModel.ClearSelection2 True

‘ メインアセンブリの原点を選択するため、名前でエンティティを取得して選択
‘ 注意: 実務ではコンポーネント内部のエンティティ (FaceやPlane) を名前解決して選択する
Dim bRet As Boolean
bRet = swModel.Extension.SelectByID2(“原点”, “EXTERIOR”, 0, 0, 0, True, 1, Nothing, 0)

‘ サブアセンブリ側の原点(または特定面)を選択
‘ サブコンポーネント経由でエンティティを選択する場合は PathNames を用いる
Dim compName As String
compName = swComp.Name2

bRet = swModel.Extension.SelectByID2(“原点@” & compName, “EXTERIOR”, 0, 0, 0, True, 1, Nothing, 0)

‘ 一致合致(Coincident: swMateCOINCIDENT = 0)の追加
swMateRet = swAssy.AddMate(swMateType_e.swMateCOINCIDENT, swMateAlign_e.swMateAlignCLOSEST, False, 0#, 0#, 0#, 0#, 0#, 0#, 0#, 0#, False, 0)

‘ 選択解除
swModel.ClearSelection2 True
End Sub

—

3. 実務で直面する「深淵」とシニアの回避策

A. コンポーネント名(Name2)の動的変動と一意性の担保

アセンブリ内に同じサブアセンブリを複数個(例: `SubAssembly-1`, `SubAssembly-2`)配置する場合、`swComp.Name2` の文字列は動的に変化する。
ハードコーディングされた名称で合致を定義しようとすると、2個目以降の配置で必ず破綻する。
解決策:`AddComponent5` の戻り値として返る `Component2` オブジェクトそのものをメモリ上に保持し、文字列による逆引き(`SelectByID2`)に頼らず、オブジェクトポインタ経由で面や参照ジオメトリを取得する設計に昇華させよ。

B. 巨大アセンブリにおける「軽量モード(Lightweight)」の罠

大規模なプラントや自動車の設計データでは、サブアセンブリが「軽量モード」で開かれることがある。軽量状態のコンポーネントに対してAPIから面(Face)のエンティティを取得しようとすると、ポインタが `Nothing` を返し、VBAが容赦なくクラッシュする。

シニアの防衛的プログラミング:
プログラム実行前に、対象のサブアセンブリを強制的に解決(Resolve)状態にするコードを挟むのがプロの作法だ。

.net
‘ コンポーネントが軽量であれば解決する
If swComp.IsLightWeight Then
Dim resolved As Boolean
resolved = swComp.SetResolved()
End If

—

4. 総括:レガシーの殻を破るシステム連携へ

VBAというレガシーな実行環境であっても、SolidWorks APIのメモリモデル、COMの参照ルール、そしてアセンブリのツリー構造(階層)の本質を理解していれば、完全自動化された設計基盤を構築することは十分に可能だ。

単に「動けばいい」というコードは、1000部品を超える大規模アセンブリの前に沈黙する。
オブジェクトを制し、メモリを制する者だけが、真のSolidWorks自動化エンジニアと名乗ることを許される。次のシステム構築では、ぜひこのアーキテクチャを導入してほしい。

タイトルとURLをコピーしました