【実務・中級編】【上級プロ】カスタムイベントハンドラ(SldWorksEvents)の導入:アセンブリへの部品追加・削除をVBAでリアルタイム検知 – SolidWorks VBA解析バイブル

スポンサーリンク

【SolidWorks VBA極限開発】アセンブリの部品追加・削除をリアルタイム検知するイベントハンドラ(SldWorksEvents)完全実装ガイド

SolidWorksの標準マクロ開発において、多くのエンジニアが到達する限界があります。それが「ボタンを押して実行する文脈依存のバッチ処理」からの脱却です。

業務効率化の最高峰を目指すなら、設計者がアセンブリに部品をドラッグ&ドロップした「その瞬間」、あるいは不要な部品を削除した「その瞬間」に、バックグラウンドでシステムが介入し、プロパティの不整合を自動検知したり、データベースとリアルタイム同期を行ったりする「イベント駆動型(Event-Driven)アーキテクチャ」の構築が不可欠となります。

本稿では、VBAという制約の多い環境下でSolidWorks APIのイベントモデル(`SldWorksEvents` / `AssemblyDoc` イベント)を捕捉し、実務に耐えうる堅牢なリアルタイム監視エンジンを構築するプロフェッショナルな手法を解説します。

—

1. 概念設計:プロシージャ型スクリプトとイベント駆動型エンジンの構造的違い

一般的なVBA開発者が書くスクリプトと、堅牢な自動化エンジニアが構築するシステムには、設計思想レベルで決定的な乖離が存在します。

なぜボタン起動のマクロでは不十分なのか?

| 比較項目 | 従来型(ボタン起動プロシージャ) | イベント駆動型(SldWorksEvents) |
| :— | :— | :— |
| 実行タイミング | ユーザーが意図してボタンを押した時 | 設計変更が発生した「瞬間」(リアルタイム) |
| データの整合性 | 実行時点の「点」でしか検証できない | 変更の都度検知するため、不正データの滞留を防止 |
| ライフサイクル | スクリプト完了時に即座にメモリ解放 | SolidWorksセッション中に常駐(状態保持) |
| 実装難易度 | 低(順次処理) | 高(ライフサイクル管理・再帰防止必須) |

イベント駆動型を実装する際の最大の障壁は、「VBAの実行ライフサイクルの維持」と「SolidWorks COMオブジェクトの参照解放(メモリリーク回避)」の両立です。単にコードを書くだけでは、CADをクラッシュさせる「粗悪なアドイン」と化してしまいます。

—

2. アーキテクチャの必須原則:陥りやすい罠と3つの鉄則

イベントハンドラをVBAで実装する場合、以下の3つの致命的なトラブルに対する防護策をあらかじめ設計に組み込む必要があります。

① 再帰呼び出し(Re-entrancy / デッドロック)の回避

部品が追加されたイベント(`AddItemPostNotify` など)をトリガーにして、VBA側からさらにアセンブリへ合致の追加やコンポーネントの操作を行うと、その操作自体が新たなイベントを発行し、無限ループ(再帰クラッシュ)に陥ります。
必ず「イベント処理中フラグ(排他制御)」を設計してください。

② VBAの変数有効期間(State Persistence)の維持

VBAは通常、`Sub` を抜けたらすべてのローカル変数が破棄されます。`WithEvents` を用いてイベントを監視するには、クラスインスタンスをグローバル変数(または非表示フォーム)上に永続化させる必要があります。

③ COMオブジェクトの参照破棄(メモリリーク防止)

ドキュメントが閉じられた際にイベントをアンフック(解除)しないと、SolidWorksは裏で閉じたはずのドキュメントのメモリを保持し続け、いずれ動作が極端に重くなるか強制終了します。

—

3. 完全実装コード:アセンブリリアルタイム監視エンジン

本プログラムは以下の2つのモジュールで構成されます。

1. `clsAssemblyEvents` (クラスモジュール) : イベントの検知とハンドリングを担当
2. `modMain` (標準モジュール) : イベントの開始・終了・ライフサイクル管理を担当

【クラスモジュール】 `clsAssemblyEvents`

以下のコードをクラスモジュールとして追加し、オブジェクト名を `clsAssemblyEvents` に変更してください。

‘ ==============================================================================
‘ クラス名: clsAssemblyEvents
‘ 役割 : AssemblyDocのイベントをフックし、コンポーネント追加・削除をリアルタイム検知する
‘ ==============================================================================
Option Explicit

‘ SolidWorksのアセンブリドキュメントイベントを捕捉するための宣言
Public WithEvents swApp As SldWorks.SldWorks
Public WithEvents swAssembly As SldWorks.AssemblyDoc

‘ 再帰呼び出し防止用の排他制御フラグ
Private isProcessing As Boolean

Private Sub Class_Initialize()
isProcessing = False
End Sub

‘ ——————————————————————————
‘ イベント: コンポーネント追加の検知 (AddItemPostNotify)
‘ ——————————————————————————
Private Function swAssembly_AddItemPostNotify(ByVal NewRef As Object) As Long
On Error GoTo ErrorHandler

‘ 処理中であれば再帰呼び出しを防止して即座に抜ける
If isProcessing Then Exit Function

‘ 追加されたフィーチャーがコンポーネント(Component2)であるか確認
Dim swfeat As SldWorks.Feature
Set swfeat = NewRef

If Not swfeat Is Nothing Then
‘ フィーチャータイプが “Reference” (コンポーネント) の場合
If swfeat.GetTypeName2() = “Reference” Then
isProcessing = True

Dim swComp As SldWorks.Component2
Set swComp = swfeat.GetSpecificFeature2()

If Not swComp Is Nothing Then
‘ ★【実務処理ロジック】ここに部品追加時の自動化処理を記述★
Debug.Print “[EVENT DETECTED] 部品が追加されました: ” & swComp.Name2 & _
” (パス: ” & swComp.GetPathName & “)”

‘ 例: カスタムプロパティの必須チェックや自動命名ルールの検証
Call ValidateComponentProperties(swComp)
End If

isProcessing = False
End If
End If

swAssembly_AddItemPostNotify = 0
Exit Function

ErrorHandler:
isProcessing = False
Debug.Print “[ERROR] AddItemPostNotify: ” & Err.Description
swAssembly_AddItemPostNotify = 0
End Function

‘ ——————————————————————————
‘ イベント: コンポーネント削除の検知 (ComponentRemoveNotify2)
‘ ——————————————————————————
Private Function swAssembly_ComponentRemoveNotify2(ByVal ComponentName As String, ByVal ComponentPath As String) As Long
On Error GoTo ErrorHandler

If isProcessing Then Exit Function
isProcessing = True

‘ ★【実務処理ロジック】ここに部品削除時の自動化処理を記述★
Debug.Print “[EVENT DETECTED] 部品が削除されました: ” & ComponentName & ” (パス: ” & ComponentPath & “)”

‘ 例: 外部BOMデータベースからのレコード削除登録や、合致エラーの事前チェック
Call OnComponentRemoved(ComponentName, ComponentPath)

isProcessing = False
swAssembly_ComponentRemoveNotify2 = 0
Exit Function

ErrorHandler:
isProcessing = False
Debug.Print “[ERROR] ComponentRemoveNotify2: ” & Err.Description
swAssembly_ComponentRemoveNotify2 = 0
End Function

‘ ——————————————————————————
‘ イベント: アセンブリが閉じられた際のクリーンアップ (DestroyNotify)
‘ ——————————————————————————
Private Function swAssembly_DestroyNotify() As Long
On Error Resume Next
Debug.Print “[INFO] アセンブリが閉じられました。イベントハンドラを解放します。”

‘ イベント参照の切断(メモリリーク防止)
Set swAssembly = Nothing
swAssembly_DestroyNotify = 0
End Function

‘ ——————————————————————————
‘ 内部ビジネスロジック (サンプルのプロパティ検証関数)
‘ ——————————————————————————
Private Sub ValidateComponentProperties(ByRef swComp As SldWorks.Component2)
Dim swModel As SldWorks.ModelDoc2
Set swModel = swComp.GetModelDoc2()

‘ パツがライトウェイト表示などの理由でロードされていない場合の対話処理
If swModel Is Nothing Then
Debug.Print ” [WARNING] モデルデータが未ロードです (ライトウェイト状態の可能性): ” & swComp.Name2
Exit Sub
End If

‘ 例: 品番(PartNo)プロパティが存在するか検証
Dim custPropMgr As SldWorks.CustomPropertyManager
Set custPropMgr = swModel.Extension.CustomPropertyManager(“”)

Dim valOut As String
Dim resolvedValOut As String
Dim wasResolved As Boolean
custPropMgr.Get5 “PartNo”, False, valOut, resolvedValOut, wasResolved

If valOut = “” Then
MsgBox “【警告】追加された部品 [” & swComp.Name2 & “] に ‘PartNo’ プロパティが設定されていません。”, _
vbExclamation, “設計ルール検証エンジン”
End If
End Sub

Private Sub OnComponentRemoved(ByVal compName As String, ByVal compPath As String)
‘ 削除時のDB同期などのロジックをここに集約
End Sub

—

【標準モジュール】 `modMain`

イベントの「起動」および「全開放(終了)」をコントロールする標準モジュールです。

‘ ==============================================================================
‘ モジュール名: modMain
‘ 役割 : イベントハンドラのライフサイクル制御(開始・停止)
‘ ==============================================================================
Option Explicit

‘ グローバル領域にクラスインスタンスを保持し続けることで、VBA終了後もイベントを捕捉可能にする
Private g_AssemblyEvents As clsAssemblyEvents

‘ ——————————————————————————
‘ 監視スタート
‘ ——————————————————————————
Public Sub StartAssemblyMonitoring()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks

Dim swModel As SldWorks.ModelDoc2
Set swModel = swApp.ActiveDoc

‘ アクティブドキュメントがアセンブリかどうかの完全検証
If swModel Is Nothing Then
MsgBox “アセンブリモデルが開かれていません。”, vbCritical
Exit Sub
End If

If swModel.GetType() <> swDocASSEMBLY Then
MsgBox “現在のアクティブモデルはアセンブリではありません。”, vbExclamation
Exit Sub
End If

‘ すでに監視中の場合は一度初期化
If Not g_AssemblyEvents Is Nothing Then
Set g_AssemblyEvents = Nothing
End If

‘ クラスインスタンスの作成とアセンブリのバインド
Set g_AssemblyEvents = New clsAssemblyEvents
Set g_AssemblyEvents.swApp = swApp
Set g_AssemblyEvents.swAssembly = swModel

Debug.Print “==================================================”
Debug.Print ” SolidWorks リアルタイムアセンブリ監視が開始されました”
Debug.Print ” 監視対象: ” & swModel.GetTitle()
Debug.Print “==================================================”

MsgBox “アセンブリのリアルタイム監視を開始しました。\n部品の追加・削除がリアルタイムに検知されます。”, vbInformation
End Sub

‘ ——————————————————————————
‘ 監視ストップ(明示的な解放)
‘ ——————————————————————————
Public Sub StopAssemblyMonitoring()
If Not g_AssemblyEvents Is Nothing Then
Set g_AssemblyEvents.swAssembly = Nothing
Set g_AssemblyEvents.swApp = Nothing
Set g_AssemblyEvents = Nothing
Debug.Print “[INFO] アセンブリ監視を明示的に停止しました。”
End If

MsgBox “アセンブリ監視を停止しました。”, vbInformation
End Sub

—

4. エンタープライズ開発における運用の注意点

このアーキテクチャを現場の生産ラインや大規模開発チームに導入する際、絶対に失敗できない「実用上の境界条件」が3つあります。

1. 外部データベース(SQL / ERP)連携時の非同期思考

部品追加イベント(`AddItemPostNotify`)の中で直列(Synchronous)に外部SQL Serverへの問い合わせやBOM参照を実行してはいけません。ネットワーク遅延が発生した際、SolidWorksのUIスレッドがフリーズし、設計者の操作感が著しく悪化します。

  • 対策: データベース連携が必要な場合は、イベント内では「処理待ちキュー(配列やDictionary)」にデータを格納するのみにとどめ、一定時間ごとにバックグラウンドで処理するか、レスポンスの高速なキャッシュ構造を併用してください。

2. ライトウェイト・大規模アセンブリモードの挙動

アセンブリに部品が追加された際、その部品が「ライトウェイト(Lightweight)」として読み込まれると、`swComp.GetModelDoc2()` は `Nothing` を返します。

  • 対策: プロパティ取得等のモデル内部へアクセスが必要な場合は、`swComp.SetSuppression2(swComponentFullyResolved)` を明示的に呼んでライトウェイトを解除するか、`ModelDocExtension.GetCustomPropertyManager` 等でコンポーネントの参照状態を意識したコード設計を行ってください。

3. 一括処理(バッチ処理)実行時のイベント一時停止

マクロや他システムから「自動で100個の部品を配置する」といった一括処理を実行する際、この監視イベントが有効化されていると、100回イベントが発火してパフォーマンスが惨劇的なことになります。

  • 対策: 大量処理を行うプロシージャ側では、あらかじめ `StopAssemblyMonitoring` を呼んでイベントを無効化し、処理完了後に `StartAssemblyMonitoring` で再登録する設計(`EnableEvents = False` のようなパターン)を徹底してください。

—

5. まとめ:イベント駆動開発がもたらすROI

本稿で解説した `SldWorksEvents` によるリアルタイム検知手法は、従来の「設計が終わった後にまとめて修正する」というリアクティブな運用を、「不整合な設計の発生をその場で防ぐ」というプロアクティブな品質管理体制へと昇華させます。

  • 部品が追加された瞬間に、社外秘プロパティや図番ルールの漏れを即時警告。
  • 部品が削除された瞬間に、関連する構成表(BOM)データや図面への同期要求をキューイング。

標準マクロの域を超え、CADシステムを「企業のコアデータと連動するスマートな端末」に変革させる技術として、本コードを自社ツールの基盤として活用してください。

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