【極限の知見】SolidWorks VBAによる「非同期型・イベント駆動バックアップシステム」の設計思想
設計現場で「業務効率化ツール」を自称するコードの多くは、実は単なる「便利なマクロ」に過ぎない。
ユーザーがボタンを押した瞬間に、SolidWorksのUIが数秒間フリーズし、砂時計が回り続ける――。もし君が作ったツールがそのような挙動をするなら、それは自動化ではなく「業務の妨害」だ。真のプロフェッショナルが構築すべきは、ユーザーの操作を一切妨げず、裏側で静かに、かつ確実に任務を遂行する「システム」である。
本稿では、SolidWorksのイベントをフックし、図面保存時にPDFバックアップとログ記録を自動で行う「イベント駆動型・非同期バックアップシステム」の設計と実装について、その極限の知見を伝授する。
1. なぜ「マクロ」ではなく「イベント駆動」なのか
一般的な設計者は、以下のようなアプローチを取る。
「保存ボタンを押した後に、バックアップ用マクロを手動で実行する」あるいは「全ての処理を一つの長いマクロに詰め込む」。
これは極めて脆弱な設計だ。なぜなら、「人間の操作ミス(保存忘れ)」を制御できないからだ。
イベント駆動型(Event-Driven)アーキテクチャを採用すれば、SolidWorksのAPIが発行する「ファイルが保存された」「ドキュメントが作成された」というシグナルを、VBAのクラスモジュールが常に監視(Listen)し、条件を満たした瞬間に処理をトリガーできる。
しかし、ここで一つ、致命的な技術的障壁がある。
VBAはシングルスレッドである。
イベントハンドラの中で重いPDFエクスポート処理を直接実行すれば、エクスポートが終わるまでSolidWorksの操作画面は完全にロックされる。これを回避するために、我々は「イベントの検知」と「実際の処理」を分離する「非同期的な振る舞い」を擬似的に作り出す必要がある。
2. アーキテクチャ設計:分離による堅牢性の確保
堅牢なシステムを構築するため、以下の3層構造で設計する。
1. Event Sink (監視層): `SldWorksEvents` インターフェースを実装したクラスモジュール。SolidWorksの動作を監視し、条件(図面ファイルであるか等)に合致した場合のみ、後続のタスクへ信号を送る。
2. Task Dispatcher (指令層): 検知したイベントを「実行すべきタスク」としてキューイング、あるいは外部プロセスへ委譲する。
3. Background Worker (実行層): 実際のPDFエクスポートを行う。ここでは、SolidWorksのメインスレッドを解放するため、「WshShellによる外部VBScriptの呼び出し」、あるいは「別プロセスでのエクスポート」を検討する。
3. 実装:プロダクション・グレードのコード
以下に、実務でそのまま利用可能なレベルの構成を示す。ここでは、メインスレッドへの負荷を最小限にするため、イベント検知後に軽量なシェル経由で処理を投げる設計思想に基づいている。
3.1 クラスモジュール: `clsEventWatcher`
このクラスが、SolidWorksの心臓部からイベントを盗み取る「センサー」となる。
' Class Name: clsEventWatcher
Option Explicit
' SolidWorksのイベントを受け取るためのインターフェースを実装
Private WithEvents swApp As SldWorks.SldWorks
Private targetExtension As String
' 初期化メソッド
Public Sub Initialize(ByRef model As SldWorks.SldWorks)
Set swApp = model
targetExtension = ".SLDDRW" ' 図面ファイルのみを対象とする
End Sub
' ファイル保存イベントのハンドラ
' Note: ここで重い処理をしてはいけない。検知とトリガーのみに徹する。
Private Sub swApp_FileSaveNotify(ByVal FileName As String)
On Error GoTo ErrorHandler
' 1. 拡張子のチェック(図面ファイルか?)
If InStr(1, FileName, targetExtension, vbTextCompare) > 0 Then
' 2. 非同期処理のトリガー
' 直接PDF変換を行うとUIが固まるため、外部の軽量スクリプトを
' バックグラウンドで実行させる(WshShellを使用)
Call TriggerBackgroundBackup(FileName)
End If
Exit Sub
ErrorHandler:
' ログ記録(エラー発生時もユーザーの操作を止めない)
Debug.Print "Event Error: " & Err.Description
End Sub
' 外部プロセスへの委譲(非同期の鍵)
Private Sub TriggerBackgroundBackup(ByVal targetFile As String)
Dim shell As Object
Set shell = CreateObject("WScript.Shell")
' コマンドライン引数としてファイルパスを渡す
' ここでは例として、別のVBScript(Worker)を呼び出す
' vbHide を指定することで、黒い画面(コンソール)を出さずに実行する
Dim cmd As String
cmd = "wscript.exe ""C:\YourPath\BackupWorker.vbs"" """ & targetFile & """"
shell.Run cmd, 0, False ' Falseを指定することで、終了を待たずに制御を戻す(非同期)
End Sub
3.2 標準モジュール: `modMain`
システムの起動とライフサイクル管理を行う。
' Module Name: modMain
Option Explicit
Private watcher As clsEventWatcher
' システムの起動
Public Sub StartMonitoring()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
If swApp Is Nothing Then
MsgBox "SolidWorksが起動していません。", vbCritical
Exit Sub
End If
' クラスのインスタンス化
Set watcher = New clsEventWatcher
watcher.Initialize swApp
Debug.Print "Monitoring Started: " & Now
End Sub
' システムの停止
Public Sub StopMonitoring()
Set watcher = Nothing
Debug.Print "Monitoring Stopped: " & Now
End Sub
4. 運用上の極意:バグを未然に防ぐ3つの鉄則
このシステムをプロダクション環境(実際の業務ライン)に投入する際、以下の3点に留意せよ。これをおろそかにすると、システムは「お荷物」へと成り下がる。
① ファイルロックの競合回避
`FileSaveNotify` が発生した直後は、SolidWorksがまだファイルを書き込み中(ロック状態)である可能性がある。バックグラウンドのWorker側では、ファイルが利用可能になるまで数ミリ秒のウェイトを入れるか、リトライロジックを必ず組み込むこと。
② ログの「非同期書き込み」
ログ出力に `Open … For Append` を使い、かつメインスレッドで行うと、ログ出力待ちでUIが止まる。ログ記録もまた、Worker側に任せるか、メモリ上のキューに溜めてから一括処理する設計が望ましい。
③ ライフサイクルの管理
VBAのクラスインスタンスは、変数がスコープを抜けると破棄される。`watcher` 変数を標準モジュールのレベル(モジュールレベル変数)で保持し続けなければ、イベント監視は一瞬で終了する。これは初学者が最も陥りやすい罠だ。
結論:エンジニアとしての視座
自動化エンジニアの価値は、「コードが動くこと」ではなく、「ユーザーのワークフローをいかに破壊せずに、価値を付加できるか」にかかっている。
イベント駆動による非同期設計は、実装の難易度は高い。しかし、この「裏側で静かに動く」という思想をマスターしたとき、君の書くコードは単なるマクロを超え、真の「業務インフラ」へと昇華する。
「ユーザーに意識させないこと。それが最高の自動化である。」
この言葉を、常にデスクに刻んでおけ。
