【テクニカル・上級編】【上級プロ向け】SolidWorks図面エクスポートプロセスにおける「イベント駆動型(Event-Driven)非同期自動バックアップシステム」 – SolidWorks VBA解析バイブル

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

止まらない自動化: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ツールから、設計者の動きを察知し、静かに、かつ確実に業務を完遂する「自律的なプラットフォーム」へと進化する。

この知見を、貴殿のシステム構築の礎としていただきたい。

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