【実務・中級編】【上級プロ向け】図面自動生成における非同期・バックグラウンド処理とSolidWorksイベントハンドリング – SolidWorks VBA解析バイブル

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

止まらない自動化:SolidWorks VBAにおけるイベント駆動型設計と非同期制御の極意

業務自動化の現場で、中級者と上級者を分かつ境界線はどこにあるか。それは「コードが動くか」ではなく、「システムが制御不能(フリーズ)に陥らず、例外に対してどれだけ堅牢か」という一点に集約される。

大量のアセンブリから図面を自動生成し、PDFを出力する。一見、単純なループ処理に見えるこのタスクが、大規模プロジェクトにおいては地獄へと変わる。数千個の部品を処理する際、UIがフリーズし、ユーザーが「強制終了」を連打する。あるいは、図面生成の途中でエラーが発生し、どのファイルまで完了したのか、データベースとの整合性は取れているのかが不明になる。

本記事では、単なる「図面生成のスクリプト」を卒業し、イベントハンドリングを用いた「状態管理型(State-Machine)の自動化アーキテクチャ」を構築するための知見を伝授する。

1. なぜ「単純なループ処理」はプロフェッショナルな現場で通用しないのか

多くの開発者が陥る罠は、以下のような実装だ。

' --- 避けるべきアンチパターン ---
For Each part In assemblyList
    Set drw = CreateDrawing(part) ' 図面生成
    drw.ExportPDF                  ' PDF変換
    UpdateDatabase(part)           ' DB更新
Next part

このコードには、3つの致命的な欠陥がある。

1. UIスレッドの占有(Blocking): SolidWorksはシングルスレッド・アーキテクチャに近い挙動を示す。重い計算やI/Oが発生している間、SolidWorksのメインスレッドはロックされ、ユーザーは一切の操作ができなくなる。
2. 不可逆なエラー(Atomicityの欠如): `ExportPDF`が失敗した際、DB更新が行われないままループが止まるか、あるいは不完全な状態でDBが更新される。
3. イベントの無視: 図面生成は「命令を出して終わり」ではない。ビューの更新、計算、再構築(Rebuild)がバックグラウンドで走る。これらが完了する前に次の命令を送ると、COMオブジェクトの競合が発生し、ランタイムエラーを引き起こす。

プロフェッショナルは、「命令(Command)」と「完了(Event)」を分離して考える。

2. イベントハンドリングによる「状態検知」の実装パターン

図面生成の完了を「待ち時間(Sleep)」で制御するのは素人の仕事だ。正解は、SolidWorksの`SwDocEvents`(または`SwAppEvents`)をフックし、「システム側から完了通知を受け取る」設計にすることである。

以下に、クラスモジュールを用いたイベントハンドラーの実装パターンを示す。

実装例:EventWatcher クラスモジュール

まず、クラスモジュールを新規作成し、名前を `clsSwEventWatcher` とする。

' Class Module: clsSwEventWatcher
Option Explicit

' SolidWorksのイベントを捕捉するためのインターフェースを実装
Implements SwDocEvents

Private m_IsProcessing As Boolean
Public IsTaskComplete As Boolean

' 外部から処理開始を指示するためのプロパティ
Public Property Let Processing(ByVal value As Boolean)
    m_IsProcessing = value
End Property

' ドキュメントが保存された、あるいは変更された等のイベントをフック
' ここでは「図面の保存完了」をトリガーにする例
Private Sub SwDocEvents_DocumentSaveNotify(ByVal Doc As Object, ByVal Error As Long)
    ' エラーがなく、かつ現在処理中の場合のみ完了フラグを立てる
    If Error = 0 And m_IsProcessing = True Then
        Debug.Print "Event: Document saved successfully."
        IsTaskComplete = True
        m_IsProcessing = False
    End If
End Sub

' 他の必須メソッドは空実装(インターフェースを満たすために必要)
Private Sub SwDocEvents_DocumentOpenNotify(ByVal Doc As Object, ByVal Error As Long) End Sub
Private Sub SwDocEvents_DocumentCloseNotify(ByVal Doc As Object, ByVal Error As Long) End Sub
Private Sub SwDocEvents_DocumentModifyNotify(ByVal Doc As Object, ByVal Error As Long) End Sub
' ... (他のメソッドも同様に定義)

3. プロダクション・レベルのメインロジック

次に、このイベントハンドラーを利用して、UIをブロックせずに「イベントを待ち受ける」メインロジックを構築する。ここで重要なのは、`DoEvents`を戦略的に使い、OSに制御を戻しながらイベントをポーリング(監視)することだ。

実装例:Standard Module

' Standard Module
Option Explicit

Dim swApp As SldWorks.SldWorks
Dim eventWatcher As clsSwEventWatcher

Sub ProfessionalDrawingAutomation()
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim targetFilePath As String
    
    On Error GoTo ErrorHandler
    
    Set swApp = Application.SldWorks
    Set eventWatcher = New clsSwEventWatcher
    
    ' 1. イベントハンドラーをSolidWorksに登録
    ' 注: 実際にはswApp.SetNotifyを介してイベントを受け取る設定が必要
    ' ここでは概念的な流れを示す
    SetEventHandlers eventWatcher 

    targetFilePath = "C:\Work\Drawing_Example.SLDDRW"

    ' --- プロセス開始 ---
    Debug.Print "Starting Process..."
    eventWatcher.Processing = True
    
    ' 2. 図面を開く/生成する(重い処理)
    Set swModel = swApp.OpenDoc6(targetFilePath, swDocDRAWING, swOpenDocOptions_Silent, "", 0, 0)
    
    If swModel Is Nothing Then
        Err.Raise vbObjectError + 513, "Automation", "Failed to open drawing."
    End If
    
    ' 3. 図面操作(ビュー配置、シート制御など)
    Set swDraw = swModel
    ' ... (ここに詳細な図面生成ロジックを記述) ...
    
    ' 4. 保存(これがイベントのトリガーになる)
    swModel.Save3 swSaveAsOptions_Silent, 0, 0
    
    ' 5. 【重要】非同期待ちループ
    ' DoEventsによりUIのフリーズを防ぎつつ、イベント完了を待つ
    Do While eventWatcher.IsTaskComplete = False
        DoEvents ' OSに制御を戻し、SolidWorksがイベントを発火できる状態にする
        
        ' タイムアウト処理(無限ループ防止)
        ' 実務では必ずタイムアウトを設けること
        If Timer > StartTimer + 300 Then ' 5分制限
            Err.Raise vbObjectError + 514, "Automation", "Timeout waiting for event."
        End If
    Loop
    
    ' 6. 完了後の後処理(DB連携など)
    UpdateDatabase targetFilePath, "SUCCESS"
    Debug.Print "Process Completed Successfully."

CleanUp:
    Set eventWatcher = Nothing
    Exit Sub

ErrorHandler:
    Debug.Print "Error: " & Err.Description
    UpdateDatabase targetFilePath, "FAILED"
    Resume CleanUp
End Sub

Private Sub SetEventHandlers(watcher As clsSwEventWatcher)
    ' 本来はswApp.SetNotify等のAPIを使用して
    ' 自身のクラスインスタンスをイベントシンクとして登録する処理を行う
End Sub

Private Sub UpdateDatabase(path As String, status As String)
    ' ここにDB連携ロジックを記述。
    ' 処理の「成否」が確定した後にのみ実行される堅牢な設計
    Debug.Print "DB Updated: " & path & " -> " & status
End Sub

4. アーキテクトからの警告:設計における3つの鉄則

このレベルの実装を行う際、以下の3点に留意せよ。これをおろそかにすると、どれだけ高度なコードを書いても「バグの温床」となる。

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

VBAにおけるCOMオブジェクト(`swModel`, `swDraw`等)は、エラー発生時に適切に `Set obj = Nothing` しなければならない。特にイベントハンドラーをクラスとして保持する場合、そのインスタンスがメモリ上に残り続けると、SolidWorksが終了してもプロセスが残る(ゾンビプロセス)原因となる。

② 「状態」と「データ」の分離

図面生成の進捗を管理する変数(`IsTaskComplete`など)と、実際の図面データ(`swModel`)は明確に分離せよ。データが書き込み中(I/O中)に、そのデータに対して操作を行うことは、レースコンディション(競合状態)を引き起こす。必ず「イベントによる完了通知」を受けてから、次のデータ操作に移ること。

③ トランザクションの概念を導入せよ

自動化ツールは「不完全な状態」を作り出してはならない。

  • ファイルが作成されたが、PDFが出力されなかった。
  • DBには「成功」と記録されたが、実際にはファイルが壊れていた。

これらを防ぐため、「ファイル作成 → PDF変換 → 保存完了イベント検知 → DB更新」という一連の流れを一つのトランザクションとして捉え、どこかで失敗したら必ずロールバック(あるいはエラーログの記録とリトライキューへの投入)を行う設計にせよ。

結論

SolidWorks VBAの自動化は、単なる「作業の置き換え」ではない。それは、「不確実なソフトウェアの状態を、いかにして確実なシステムとして制御するか」というエンジニアリングの挑戦である。

イベント駆動型の設計をマスターすれば、あなたのツールは「止まる不安」から解放され、真にプロフェッショナルな業務インフラへと昇華するだろう。

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