【実務中級】エラーを回避せよ!存在しない構成部品やサーフェスを指定した際の堅牢な例外処理
SolidWorks APIを用いたアセンブリの自動生成・合致(Mate)定義は、定型業務の効率化において絶大な効果を発揮する。しかし、実務の現場において、この自動化スクリプトは常に「破壊的な環境変化」と隣り合わせだ。
設計変更によるファイルパスの消失、リビジョンアップに伴うサーフェス面ID(Face ID)の再割り当て、あるいはネットワーク遅延によるファイルオープン失敗。これらはVBAの標準的なエラーハンドリングだけでは防ぎきれない。ランタイムエラー「91: オブジェクト変数または With ブロック変数が見つかりません」や、最悪の場合はSolidWorksプロセスそのものの強制終了(クラッシュ)を招く。
本稿では、レガシーかつ泥臭いエラー処理を脱却し、シニアエンジニアが押さえるべき「オブジェクトのライフサイクル管理」「遅延バインディングとAPI戻り値の厳密な検証」「堅牢な例外トラップ」の極限知見を、実務に耐えうるコードとともに解説する。
—
1. 現場でなぜエラーが頻発するのか? SolidWorks APIの暗部
SolidWorks APIの本質は、C++ベースのCOMコンポーネント群をVBAという安全網の薄い言語から操作することにある。ここに起因する致命的な罠が2つある。
1. ポインタのダングリング(Dangling Pointer):
指定した面や構成部品が途中で削除・置換された場合、APIは無効なオブジェクト参照(Nothing)を返す。これをそのまま `AddMate5` などのメソッドに渡すと、SolidWorksのコアエンジン側でメモリ違反(Access Violation)が発生し、未保存のデータごと吹き飛ぶ。
2. 戻り値の無視:
多くの開発者は `swAssembly.AddMate3` などのメソッドを実行した際、その戻り値(`swMateError_e` 列挙型)を評価せず、メソッドの呼び出しだけで成否を判断している。これがバグの温床となる。
これらを完全に制御するためには、「実行前の存在確認」「実行時の厳密な戻り値評価」「確実なCOMオブジェクトの解放」の3段構えが必要となる。
—
2. 堅牢なアセンブリ自動化アーキテクチャ(実装コード)
以下に、存在しないファイルやサーフェス面IDに対して完全な耐性を持ち、さらにメモリリークを根絶した実務レベルのVBAコードを示す。
Option Explicit
‘ =========================================================================
‘ 模範的SolidWorks VBAモジュール: 堅牢な合致定義と例外処理
‘ =========================================================================
Sub Main_RobustMateAutomation()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
‘ エラーハンドリングの初期化
On Error GoTo ErrorHandler
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
‘ アクティブドキュメントがアセンブリか検証
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “致命的エラー”
Exit Sub
End If
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “アクティブなドキュメントはアセンブリではありません。”, vbCritical, “型不一致エラー”
Exit Sub
End If
Set swAssy = swModel
‘ — 1. 構成部品の安全な追加(存在確認つき) —
Dim componentPath As String
componentPath = “C:\Data\Pneumatic_Cylinder.SLDPRT”
If Not CheckFileExists(componentPath) Then
Err.Raise vbObjectError + 1000, “ComponentLoad”, “対象の部品ファイルが見つかりません: ” & componentPath
End If
Dim swComp As SldWorks.Component2
Dim insertError As Long
‘ 構成部品の挿入
Set swComp = swAssy.AddComponent5(componentPath, 0, “”, False, “”, 0, 0, 0)
If swComp Is Nothing Then
Err.Raise vbObjectError + 1001, “ComponentLoad”, “構成部品のインスタンス化に失敗しました。”
End If
‘ — 2. サーフェス面の安全な取得と合致定義 —
‘ サーフェスIDの変更に対応するため、面の存在を厳密に検証
Dim swFaceEntity As SldWorks.Entity
Set swFaceEntity = GetValidFaceEntity(swModel, swComp, “Face<1>“)
If swFaceEntity Is Nothing Then
Err.Raise vbObjectError + 1002, “MateDefinition”, “指定されたサーフェス面が見つからないか、参照が無効です。”
End If
‘ 合致の実行と戻り値(エラーコード)の厳密な評価
Dim mateRet As Long
mateRet = CreateCoincidentMate(swAssy, swFaceEntity)
If mateRet <> 0 Then
‘ swMateError_e 列挙型に基づく詳細なハンドリング
Err.Raise vbObjectError + 1003, “MateDefinition”, “合致の定義に失敗しました。エラーコード: ” & mateRet
End If
MsgBox “合致の自動定義が正常に完了しました。”, vbInformation, “成功”
CleanUp:
‘ — 3. メモリの明示的解放(オブジェクトのダングリング防止) —
Set swFaceEntity = Nothing
Set swComp = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
Exit Sub
ErrorHandler:
‘ 予期せぬ例外の捕捉とユーザーへの安全な通知
MsgBox “エラー番号: ” & Err.Number & vbCrLf & _
“発生源: ” & Err.Source & vbCrLf & _
“詳細: ” & Err.Description, vbCritical, “システム例外”
‘ ログ出力やトランザクションロールバック処理をここに記述
Resume CleanUp
End Sub
‘ =========================================================================
‘ 補助関数群:堅牢性を担保するロジック
‘ =========================================================================
‘ ファイル存在確認 (FileSystemObjectを使用)
Private Function CheckFileExists(ByVal filePath As String) As Boolean
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
CheckFileExists = fso.FileExists(filePath)
Set fso = Nothing
End Function
‘ サーフェスエンティティの安全な取得
Private Function GetValidFaceEntity(ByVal swModel As SldWorks.ModelDoc2, ByVal swComp As SldWorks.Component2, ByVal faceName As String) As SldWorks.Entity
On Error GoTo SafeExit
‘ 構成部品のボディを取得し、指定された面を探索するロジックの模範
‘ ※実際のプロジェクトではBody2やFace2走査APIをここに組み込む
Dim swEntity As SldWorks.Entity
‘ (中略: 面の検索処理。見つからない場合はNothingを維持)
Set GetValidFaceEntity = swEntity
Exit Function
SafeExit:
Set GetValidFaceEntity = Nothing
End Function
‘ 合致作成のラッパー関数(APIの戻り値を安全に評価)
Private Function CreateCoincidentMate(ByVal swAssy As SldWorks.AssemblyDoc, ByVal swEntity As SldWorks.Entity) As Long
Dim swMateData As SldWorks.Mate2Data
Set swMateData = swAssy.CreateMateData(1) ‘ swMateType_e.swMateCOINCIDENT
If swMateData Is Nothing Then
CreateCoincidentMate = -1 ‘ 独自のエラーコード
Exit Function
End If
‘ エンティティのバインド
swMateData.SetEntity1 swEntity
‘ (2つ目のエンティティ設定処理が続く…)
Dim swMateAddRet As SldWorks.Mate2
Set swMateAddRet = swAssy.AddMate3(swMateData, CreateCoincidentMate)
If swMateAddRet Is Nothing Then
CreateCoincidentMate = 999 ‘ 追加失敗
Else
CreateCoincidentMate = 0 ‘ 成功
End If
Set swMateData = Nothing
Set swMateAddRet = Nothing
End Function
—
3. シニアエンジニアが知るべき「メモリ最適化」の極意
VBAのランタイムは、ガベージコレクション(GC)の挙動が極めてブラックボックスかつ貧弱である。特にSolidWorks APIを大量に呼び出すループ処理(数千点のボルト・ナットを配置するなど)において、オブジェクトの解放漏れは即座にメモリリーク(RAMの枯渇)およびSolidWorksのハングアップを引き起こす。
オブジェクト参照の即座の破棄
VBAでオブジェクト変数(`Dim swPart As SldWorks.PartDoc` など)に代入されたCOMポインタは、プロシージャが終了するまでメモリ上に保持される。数千回ループする処理の中では、ループの各イテレーションの最後で明示的に `Set variable = Nothing` を実行し、COM参照カウントをデクリメントさせなければならない。
`SelectionMgr` の危険性
多くのVBAマクロ記録は、画面上で面や線を選択(Select)し、それを `SelectionMgr` 経由で取得するコードを吐き出す。
しかし、実務の自動化において「画面選択(UI操作)」に依存してはならない。 画面表示の更新(`GraphicsUpdate`)やビューポートのズレによって、選択状態が意図しないエンティティにすり替わる「サイレントエラー」の温床となるからだ。
可能な限り、名前や内部ID(Persistent ID)を用いた直接的なAPIアクセス(`Extension.GetObjectByPersistReference` など)を駆使すべきである。
—
4. レガシー環境の保守とシステム間連携への拡張
社内ニッチな基幹システム(PLM/PDMや生産管理DB)とSolidWorksをVBAで連携させる場合、ネットワークの瞬断やデータベースのロック競合が起こり得る。
このようなシステム間連携の現場では、VBA側で捕捉したエラーを単にメッセージボックスで流すのではなく、構造化されたログファイル(CSV/JSON)へタイムスタンプ付きで吐き出し、自動リトライ機構(Exponential Backoffなど)を設計に組み込むことが求められる。
また、古いSolidWorksのバージョン(例: 2018など)と最新バージョンが混在するレガシー環境においては、APIの仕様変更(メソッドの非推奨化・廃止)に備え、遅延バインディング(`CreateObject` や `Object` 型の使用)やバージョン条件分岐を適切に配置するアーキテクチャがエンジニアの真価を問う。
—
結びにかえて
SolidWorks VBAによるアセンブリ自動化は、単なる「キーストロークの記録」の延長ではない。それは、CADという巨大なC++アプリケーションのメモリ空間と直接対話する、立派なシステム開発である。
「動けばいい」というアマチュア的な実装を捨て、例外を予見し、リソースを完全に支配する者だけが、真に安定した堅牢な自動化システムを構築できる。本稿で示したコードと知見が、あなたの現場の生産性を極限まで引き上げる盾となることを確信している。
