止まらない自動化:SolidWorksにおけるイベント駆動型非同期バックアップ・アーキテクチャの構築
設計現場において、自動化ツールは「便利」であるだけでは足りない。真にプロフェッショナルが求めるものは、「設計者の思考を中断させない(Non-intrusive)」こと、そして「不可逆的なデータの喪失を物理的に不可能にする」ことだ。
多くのエンジニアが陥る罠がある。それは、SolidWorksのAPIを利用して「保存時にPDFを出力する」という処理を、メインのスレッドに直接組み込んでしまうことだ。これでは、大規模なアセンブリや複雑な図面を扱う際、PDF生成の重いプロセスがSolidWorksのUIをロックし、設計者のリズムを破壊する。これは「自動化」ではなく、単なる「作業の強制」である。
本稿では、VBAのクラスモジュールを用いたイベントフック、そしてVBAの単一スレッドという制約を打破するための「サイドカー・プロセス(Sidecar Process)パターン」を用いた、非同期バックアップシステムの設計思想を詳述する。
1. アーキテクチャの設計思想:Decoupling(分離)
我々が目指すのは、以下の3つのレイヤーに完全に分離されたシステムである。
1. Observer Layer (VBA Class Module): SolidWorksのイベント(`FileSaveNotify`等)を監視し、イベントを検知した瞬間に「タスクのトリガー」のみを行う。
2. Orchestrator Layer (Standard Module): 検知したイベントから必要なメタデータ(ファイルパス、タイムスタンプ)を抽出し、バックアップ指示書(引数)を作成する。
3. Worker Layer (External Process): SolidWorks本体とは独立したプロセス(VBScriptまたは軽量なVB.NETコンソールアプリ)として動作し、バックグラウンドでPDFエクスポートとログ記録を実行する。
この「分離」こそが、UIのフリーズを防ぎ、メモリリークのリスクを最小化する鍵となる。
2. 実装:イベントフックの極限
まず、SolidWorksのイベントを捕捉するためのクラスモジュールを作成する。ここでは `SldWorksEvents` インターフェースを実装する。
Class Module: `CEventWatcher`
' ==============================================================================
' Class Name: CEventWatcher
' Description: SolidWorksのファイル操作イベントを監視する Observer クラス
' ==============================================================================
Option Explicit
Implements SldWorksEvents
Private mSwApp As SldWorks.SldWorks
' イベント監視を開始するための初期化メソッド
Public Sub Initialize(ByRef swApp As SldWorks.SldWorks)
Set mSwApp = swApp
' イベント通知の開始
mSwApp.BeginNotify
End Sub
' イベント監視を停止するための終了メソッド
Public Sub Terminate()
If Not mSwApp Is Nothing Then
mSwApp.EndNotify
End If
Set mSwApp = Nothing
End Sub
' --- SldWorksEvents Interface Implementation ---
' ファイル保存イベントをフック
Private Function swApp_FileSaveNotify(ByVal FileName As String, ByVal FileType As Long) As Long
On Error GoTo ErrorHandler
' 図面ファイル(Drawing)であることを確認 (FileTypeの定数は環境に依存するため注意)
' ここでは簡易的に拡張子で判定するが、実務では定数を用いるべき
If LCase(Right(FileName, 6)) = ".slddrw" Then
' 【極意】ここで重い処理を呼んではならない。
' 外部プロセスへ「投げっぱなし(Fire-and-Forget)」にする。
TriggerAsyncBackup FileName
End If
swApp_FileSaveNotify = 0
Exit Function
ErrorHandler:
' ログ出力(標準エラー出力やファイルへの記録)
Debug.Print "Event Error: " & Err.Description
swApp_FileSaveNotify = 1
End Function
' 以下のインターフェースは実装が必要だが、今回は使用しない
Private Function swApp_FileOpenNotify(ByVal FileName As String) As Long: swApp_FileOpenNotify = 0: End Function
Private Function swApp_FileCloseNotify(ByVal FileName As String) As Long: swApp_FileCloseNotify = 0: End Function
Private Function swApp_FileSaveAsNotify(ByVal FileName As String, ByVal FileType As Long) As Long: swApp_FileSaveAsNotify = 0: End Function
Private Function swApp_FileReloadNotify(ByVal FileName As String) As Long: swApp_FileReloadNotify = 0: End Function
Private Function swApp_FileDeleteNotify(ByVal FileName As String) As Long: swApp_FileDeleteNotify = 0: End Function
Private Function swApp_FileRenameNotify(ByVal OldName As String, ByVal NewName As String) As Long: swApp_FileRenameNotify = 0: End Function
' --- Private Helper Methods ---
Private Sub TriggerAsyncBackup(ByVal targetPath As String)
Dim shell As Object
Set shell = CreateObject("WScript.Shell")
' Windows APIの考え方を応用し、非同期実行を実現する。
' wshShell.Run の第2引数に 0 (非表示) または 1 (表示) を指定。
' 第3引数に False を指定することで、VBAはWorkerの終了を待たずに即座に制御を戻す。
' これが「非同期」の正体である。
Dim scriptPath As String
Dim command As String
' 外部スクリプト(Worker)のパス
scriptPath = "C:\Automation\BackupWorker.vbs"
' 引数にファイルパスを渡す(パスにスペースが含まれることを想定しダブルクォーテーションで囲む)
command = "wscript.exe """ & scriptPath & """ """ & targetPath & """"
' 非同期実行の実行
shell.Run command, 0, False
' オブジェクトの明示的な解放
Set shell = Nothing
End Sub
3. 実装:Workerプロセス(非同期実行体)
VBAが「投げた」タスクを受け取り、実際にPDFを生成するのはこのスクリプトである。これを `BackupWorker.vbs` として保存する。
External Script: `BackupWorker.vbs`
' ==============================================================================
' Script Name: BackupWorker.vbs
' Description: SolidWorksのメインプロセスとは別プロセスで動作するバックアップ実行体
' ==============================================================================
Option Explicit
Dim args, targetFile, swApp, swModel, swExportData
Set args = WScript.Arguments
If args.Count = 0 Then WScript.Quit
targetFile = args(0)
On Error Resume Next
' 1. SolidWorksへの接続(既存のインスタンスを取得)
Set swApp = GetObject(, "SldWorks.Application")
If Err.Number <> 0 Then
' SolidWorksが起動していない場合はログを吐いて終了
WriteLog "Error: SolidWorks instance not found."
WScript.Quit
End If
' 2. ファイルのオープン(バックグラウンド処理のため、非表示または読み取り専用を推奨)
' 注意:既にユーザーが開いているファイルに対しては、読み取り専用で開く必要がある
Set swModel = swApp.OpenDoc6(targetFile, 3, 1, "", 0, 0) ' 3 = swDocDRAWING, 1 = swOpenDocOptions_Silent
If Not swModel Is Nothing Then
' 3. PDFエクスポートの実行
Dim exportPath
exportPath = Replace(targetFile, ".slddrw", ".pdf")
' PDF保存(簡易的な実装。実際には SaveAs を使用)
Dim errors, warnings
swModel.Extension.SaveAs exportPath, 0, 0, Nothing, errors, warnings
If errors = 0 Then
WriteLog "Success: " & targetFile & " -> " & exportPath
Else
WriteLog "Export Failed: " & targetFile & " (Error Code: " & errors & ")"
End If
' 4. メモリ管理:モデルを閉じる
swApp.CloseDoc swModel.GetTitle
Set swModel = Nothing
Else
WriteLog "Error: Could not open file " & targetFile
End If
Set swApp = Nothing
' --- Helper: Logging ---
Sub WriteLog(msg)
Dim fso, logFile
Set fso = CreateObject("Scripting.FileSystemObject")
' ログファイルは作業ディレクトリに固定
Set logFile = fso.OpenTextFile("C:\Automation\backup_log.txt", 8, True)
logFile.WriteLine Now & " | " & msg
logFile.Close
End Sub
4. アーキテクトの視点:メモリとパフォーマンスの極限
このシステムを運用する上で、シニアエンジニアが留意すべき「重み」が3点ある。
I. COM参照カウントの厳格な管理
VBAにおいて `Set obj = Nothing` は単なる作法ではない。特に `SldWorksEvents` のようなインターフェースを実装している場合、参照が残存すると、SolidWorksを終了させようとした際に「プロセスが残る」というレガシーな問題を引き起こす。`Terminate` メソッドにおいて、必ず `EndNotify` を呼び出し、参照を完全に断ち切る設計を徹底せよ。
II. 「非同期」の真実
VBA自体にマルチスレッド機能は存在しない。我々が行っているのは「プロセスの分身(Worker)を作る」ことである。これにより、SolidWorksのメインスレッド(UIスレッド)は、`shell.Run` の実行直後に制御をユーザーに戻すことができる。設計者がマウスを動かしている間に、裏側で `wscript.exe` が PDF を書き出す。このパラレルな動きこそが、業務効率を最大化する。
III. エラーハンドリングの階層化
バックアップシステム自体がクラッシュして、SolidWorks本体を巻き込むことはあってはならない。
- Level 1 (VBA): `On Error GoTo` で、イベントハンドラ内での例外を握り潰さず、ログに記録して即座に制御を戻す。
- Level 2 (Worker): `GetObject` や `OpenDoc6` の失敗を想定し、エラーコードをログに詳細に残す。
この二段構えのガードが、システムの堅牢性を担保する。
結論
自動化とは、人間を機械に合わせることではない。機械を人間のリズムに溶け込ませることである。
イベント駆動型、かつ非同期なアーキテクチャを採用することで、SolidWorksは単なるCADツールから、設計者の動きを察知し、静かに、かつ確実に業務を完遂する「自律的なプラットフォーム」へと進化する。
この知見を、貴殿のシステム構築の礎としていただきたい。
