【テクニカル・上級編】【上級プロ向け】図面自動化プロセスにおける「SolidWorksイベント(SldWorks_FileSaveNotifyなど)」のフックと処理連動 – SolidWorks VBA解析バイブル

スポンサーリンク
スポンサーリンク

イベント駆動型アーキテクチャの極致:SolidWorksイベントによるプロアクティブな図面制御

マクロを「ボタンを押した時に動く便利ツール」と考えているうちは、まだエンジニアの端くれに過ぎない。真の自動化エンジニア、あるいはシステムアーキテクトを目指すならば、ソフトウェアを「ユーザーの操作を待つ受動的な存在」から「システムの状態変化を検知して自律的に動く能動的な存在」へと昇華させなければならない。

本稿では、SolidWorks VBAにおけるイベントハンドリング、特に`SldWorks_FileSaveNotify`等を利用した、図面管理プロセスの高度な自動化手法について詳説する。単なるコードの書き方ではない。SolidWorksという巨大なモノリス(単一プロセス)の中で、いかにしてシステムの安定性を損なわず、外部システムとの同期を実現するか。その設計思想を伝授する。

1. 限界への挑戦:なぜ「マクロ」では足りないのか

一般的な図面処理の自動化は、ユーザーがボタンをクリックし、VBAが起動し、処理が終わるまでユーザーが待機するという「同期実行」のモデルだ。しかし、大規模な設計現場において、これは致命的な欠陥となる。

  • ヒューマンエラーの温床: 保存忘れ、命名規則違反、バックアップ漏れ。これらはすべて「ユーザーの記憶」に依存している。
  • コンテキストスイッチの損失: 図面を保存した直後、設計者は次の設計に移りたい。しかし、重い自動処理が走っていれば、その思考のフローは断絶される。
  • データの不整合: 外部PDM(Product Data Management)への登録や、サーバーへのバックアップが「手動」である限り、設計データと管理データの乖離は避けられない。

これらを解決するのが、イベント駆動型(Event-Driven)設計である。SolidWorksが「ファイルが保存された」というイベントを発行した瞬間に、背後でシステムがそれをキャッチし、処理を開始する。ユーザーの操作を妨げず、かつ確実に業務フローを完遂させる。これが、我々が目指すべき領域だ。

2. イベントフックの設計思想:非同期処理の鉄則

SolidWorksのイベントハンドラ(`SldWorksEvents`)を実装する際、最も初心者が陥りやすい、そして最も破壊的なミスは、「イベントハンドラ内で重い処理を行うこと」である。

SolidWorksは基本的にシングルスレッドに近い挙動を示す。VBAのイベントハンドラ内で、ネットワーク越しにファイルをコピーしたり、データベースにSQLを発行したり、外部APIを叩いたりすれば、その処理が終わるまでSolidWorksのUIは完全にフリーズする。これはユーザー体験を著しく損なうだけでなく、最悪の場合、SolidWorks自体のクラッシュを招く。

黄金律:Dispatcher Pattern(ディスパッチャ・パターン)

プロフェッショナルな設計では、イベントハンドラには「ディスパッチャ(振り分け役)」としての役割のみを担わせる。

1. Event Capture: VBAがイベントを検知する(極めて軽量)。
2. Dispatch: 検知した情報を引数として、外部プロセス(PowerShell, Python, もしくは専用の.NET Service)を非同期で起動する。
3. Execution: 実作業は、SolidWorksのプロセスとは独立した「別プロセス」で実行する。

これにより、SolidWorksはイベント検知直後に制御をユーザーに戻し、ユーザーはフリーズを感じることなく作業を継続できる。

3. 実装:堅牢なイベントリスナーの構築

以下に、クラスモジュールを用いたイベントハンドリングの実装例を示す。ここでは、`SldWorksEvents` インターフェースを実装し、ファイルの保存をトリガーに外部プロセスをキックする構造を記述する。

Class Module: `clsEventWatcher`

このクラスは、SolidWorksのイベントを監視し、特定の条件(図面ファイルの保存など)を満たした際に外部プロセスを呼び出す役割を持つ。

' Class Module: clsEventWatcher
Option Explicit

' SolidWorksイベントインターフェースを保持するための変数
Private WithEvents swEvents As SldWorksEvents
Private swApp As SldWorks.SldWorks

' 外部プロセス起動用の定数(例:PowerShell)
Private Const EXTERNAL_EXECUTABLE As String = "powershell.exe"

' 初期化メソッド
Public Sub Initialize(ByRef app As SldWorks.SldWorks)
    Set swApp = app
    ' SolidWorksEventsオブジェクトの生成
    ' 注意: 環境によりCreateObjectの挙動が異なる場合があるため、
    ' 本来はアドインとして実装するのが理想的だが、VBAでは以下のように扱う
    On Error Resume Next
    Set swEvents = swApp.GetEventData ' 実際にはアドイン経由での取得が一般的
    If swEvents Is Nothing Then
        ' 擬似的な実装例:実際にはAdd-in経由でイベントシンクを登録する必要がある
        MsgBox "Event Sink initialization failed. Ensure Add-in is registered.", vbCritical
    End If
    On Error GoTo 0
End Sub

' ファイル保存イベントのハンドラ
' SldWorks_FileSaveNotify が発生した際に自動的に呼ばれる
Private Sub swEvents_FileSaveNotify(ByVal FileName As String)
    On Error GoTo ErrorHandler

    ' 1. フィルタリング:図面ファイル(.drw)のみを対象とする
    If LCase(Right(FileName, 5)) <> ".drw" Then Exit Sub

    ' 2. 非同期処理のキック(Dispatcherとしての役割)
    ' ここで重い処理(DB登録など)を直接書いてはいけない。
    ' Windows Shellを使用して、別プロセスとして外部スクリプトを呼び出す。
    Call DispatchToExternalProcess(FileName)

    Exit Sub

ErrorHandler:
    ' イベント内でのエラーは、SolidWorks全体の安定性に直結するため、
    ' ログ出力のみに留め、決してユーザーにダイアログを出してはいけない。
    Debug.Print "Event Error: " & Err.Description & " [File: " & FileName & "]"
End Sub

' 外部プロセスへのディスパッチ処理
Private Sub DispatchToExternalProcess(ByVal targetFile As String)
    Dim shell As Object
    Dim command As String
    
    ' PowerShellスクリプトに引数としてファイルパスを渡す
    ' スクリプト側でバックアップやPDM連携を完結させる
    command = String(1, Chr(34)) & "C:\Scripts\DrawingSync.ps1" & String(1, Chr(34)) & _
              " -FilePath " & String(1, Chr(34)) & targetFile & String(1, Chr(34))

    Set shell = CreateObject("WScript.Shell")
    
    ' 第2引数に 0 を指定することで、ウィンドウを非表示で実行(バックグラウンド実行)
    ' 第3引数に False を指定することで、プロセスの終了を待たずに制御を戻す(非同期)
    shell.Run command, 0, False
    
    Set shell = Nothing
End Sub

' オブジェクトの明示的な解放(メモリリーク防止)
Public Sub Terminate()
    Set swEvents = Nothing
    Set swApp = Nothing
End Sub

Standard Module: `modMain`

' Standard Module: modMain
Option Explicit

Private Watcher As clsEventWatcher

' 自動実行(SolidWorks起動時やマクロ開始時)
Sub StartAutomationSystem()
    Dim swApp As SldWorks.SldWorks
    Set swApp = Application.SldWorks
    
    ' クラスのインスタンス化
    Set Watcher = New clsEventWatcher
    Watcher.Initialize swApp
    
    Debug.Print "Event-Driven System Started: Monitoring Drawing Files..."
End Sub

' システムの停止
Sub StopAutomationSystem()
    If Not Watcher Is Nothing Then
        Watcher.Terminate
        Set Watcher = Nothing
        Debug.Print "Event-Driven System Stopped."
    End If
End Sub

4. 極限の知見:メモリ管理とレガシー環境の保守

このレベルのシステムを運用する場合、以下の3点については「常識」として叩き込んでおく必要がある。

① オブジェクトのライフサイクル管理

VBAにおいて、`Set obj = Nothing` による明示的な解放は、単なる「行儀の良さ」ではない。SolidWorksのような巨大なアプリケーションにおいて、イベントリスナーが参照を保持し続けることは、プロセス内に「ゾンビ・オブジェクト」を生み出すことを意味する。これは、SolidWorksの再起動時におけるメモリリークや、アドインのアンロード失敗の主因となる。必ず `Terminate` メソッドを設計し、参照を完全に断つこと。

② Windows APIによるプロセスの監視

もし、外部プロセス(PowerShell等)が異常終了した場合、VBA側からはそれを検知しにくい。より高度なシステムでは、`kernel32.dll` の `OpenProcess` や `WaitForSingleObject` を呼び出し、外部プロセスの生存確認を行うロジックを組み込む。ただし、これはVBAの範疇を超え、C++やVB.NETによる「監視エージェント」の領域となる。

③ レガシー環境への配慮

社内システムには、依然として古いWindows OSや、古いバージョンのSolidWorksが混在している。`WScript.Shell` の挙動や、PowerShellの実行ポリシー(ExecutionPolicy)の違いによって、自動化が突然機能しなくなるリスクがある。設計段階で「環境の差異」を抽象化し、スクリプトのパスや実行コマンドを外部の設定ファイル(INIやJSON)から読み込む設計にしておくべきだ。

結言

SolidWorks VBAによる自動化は、単なる「作業の代行」であってはならない。それは「設計プロセスのインフラ」であるべきだ。

イベントをフックし、非同期に処理を逃がし、SolidWorksのメインプロセスを聖域として守る。このアーキテクチャを理解し、実装できる者こそが、現場の混乱を鎮め、真に価値のある自動化システムを構築できるエンジニアである。

技術の真髄は、コードの短さではなく、その設計の堅牢さと、システム全体への影響力の制御にあることを忘れるな。

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