【テクニカル・上級編】【中級者向け】図面ファイル群の一括印刷:指定プリンタと用紙サイズを割り当てて自動スプール – SolidWorks VBA解析バイブル

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

堅牢なる一括印刷アーキテクチャ:SolidWorks図面群のメモリ管理とスプーラー制御の極致

業務自動化の現場において、「動くコード」を書くことは容易だ。しかし、数百、数千という図面ファイルを処理する「システム」を構築することは、全く別次元の難易度を要求される。

多くのエンジニアが陥る罠がある。単純な `For Each` ループで図面を開き、印刷コマンドを送り、閉じる。この素朴な実装は、ファイル数が10枚程度なら機能する。しかし、50枚、100枚と増えた途端、SolidWorksはメモリを食いつぶし、ゾンビプロセス(実体のない `SLDWORKS.exe`)を大量に生成し、最終的にはOSごとハングアップさせる。

本稿では、単なる自動化の範疇を超え、オブジェクトのライフサイクル、メモリの決定論的解放、そしてWindowsスプーラーとの整合性を考慮した、プロフェッショナルな一括印刷エンジンの設計思想を伝授する。

1. 破綻する自動化:なぜメモリは枯渇するのか

図面の一括処理における最大の敵は、COMオブジェクトの参照カウントの不整合である。

SolidWorks APIはCOM(Component Object Model)に基づいている。`Set swModel = swApp.OpenDoc6(…)` と記述した瞬間、メモリ上にはその図面への参照が生成される。しかし、`swApp.CloseDoc` を呼び出しただけでは、VBA内の変数 `swModel` が保持する参照が残存し続ける場合がある。この「浮いた参照」が蓄積されることで、メモリリークが発生し、SolidWorksのプロセスが肥大化していくのだ。

真に堅牢なシステムを構築するには、以下の3原則を徹底しなければならない。

1. 明示的なドキュメントの切断: `CloseDoc` だけでなく、すべてのインターフェース変数に対して `Set = Nothing` を実行する。
2. エラーハンドリングによるプロセスの保護: 一枚の破損ファイルが、数百枚のバッチ処理全体を停止させることを許してはならない。
3. ガベージコレクションを待たない: VBAのメモリ管理に依存せず、エンジニアが自らの手でオブジェクトの寿命を制御する。

2. プリンタ制御の戦術:用紙サイズとスプーラーの同期

図面印刷において、最も神経を使うのが「用紙サイズ」と「プリンタ設定」の整合性だ。

SolidWorksの `PageSetup` オブジェクトは、単に「印刷する」という命令だけでは不十分だ。プリンタドライバが要求する用紙サイズ(A3, A4等)と、図面シートのサイズが一致していない場合、スプーラーは勝手にスケーリングを行い、図面が意図しないサイズで出力される。

設計思想として、「図面シートのプロパティを読み取り、それに基づいてプリンタのPageSetupを動的に書き換える」というプロセスを組み込む必要がある。

3. 実装:極限の堅牢性を備えた一括印刷エンジン

以下に、シニアエンジニアが実装すべき、メモリ管理とエラーハンドリングを極めたVBAコードのテンプレートを示す。

Option Explicit

' ======================================================================================
' Module: BatchPrintEngine
' Description: 高信頼性図面一括印刷エンジン
' Author: Legendary Chief Architect
' ======================================================================================

Sub ExecuteBatchPrinting()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim fileSystem As Object
    Dim folderPath As String
    Dim fileName As String
    Dim errorCount As Long
    Dim successCount As Long
    
    ' --- 初期化 ---
    On Error GoTo ErrorHandler
    Set swApp = Application.SldWorks
    If swApp Is Nothing Then
        MsgBox "SolidWorksが起動していません。", vbCritical
        Exit Sub
    End If
    
    ' フォルダ選択(実運用では引数や設定ファイルから取得することを推奨)
    folderPath = "C:\Work\Drawings\" ' ターゲットディレクトリ
    If Right(folderPath, 1) <> "\" Then folderPath = folderPath & "\"
    
    Set fileSystem = CreateObject("Scripting.FileSystemObject")
    If Not fileSystem.FolderExists(folderPath) Then
        MsgBox "指定されたパスが存在しません。", vbCritical
        Exit Sub
    End If

    fileName = Dir(folderPath & "*.slddrw")
    
    ' --- メインループ ---
    Do While fileName <> ""
        On Error GoTo FileErrorHandler ' 個別ファイルのエラーを捕捉
        
        Debug.Print "Processing: " & fileName
        
        ' 1. ファイルのオープン (バックグラウンド実行を意識)
        ' swOpenDocOptions_Silent を使用してダイアログを抑制
        Set swModel = swApp.OpenDoc6(folderPath & fileName, swDocDRAWING, swOpenDocOptions_Silent, "", 0, 0)
        
        If Not swModel Is Nothing Then
            Set swDraw = swModel
            
            ' 2. 図面設定の最適化 (PageSetup制御)
            ' ここで用紙サイズに応じたプリンタ設定のロジックを注入する
            ConfigurePageSetup swDraw
            
            ' 3. 印刷実行 (PrintOut2を使用し、スプーラーへ送る)
            ' 引数はプリンタ名、用紙サイズ等の詳細設定が必要な場合がある
            swModel.PrintOut2
            
            successCount = successCount + 1
            
            ' 4. 徹底したメモリ解放 (重要)
            ' ドキュメントを閉じる前に、参照を完全に切断する
            swApp.CloseDoc swModel.GetTitle
            Set swDraw = Nothing
            Set swModel = Nothing
        Else
            Debug.Print "Failed to open: " & fileName
            errorCount = errorCount + 1
        End If
        
        fileName = Dir() ' 次のファイルへ
        
        ' OSの負荷軽減のため、わずかな待機を入れる(スプーラーの詰まり防止)
        DoEvents 
        
    Loop

    MsgBox "処理完了" & vbCrLf & _
           "成功: " & successCount & vbCrLf & _
           "失敗: " & errorCount, vbInformation
    
    Exit Sub

ErrorHandler:
    MsgBox "致命的なシステムエラーが発生しました: " & Err.Description, vbCritical
    Exit Sub

FileErrorHandler:
    ' 個別のファイルエラー時にループを止めず、エラーカウントを上げて次へ進む
    Debug.Print "Error in file " & fileName & ": " & Err.Description
    errorCount = errorCount + 1
    ' 失敗したファイルが開きっぱなしにならないよう、安全策として閉じる
    If Not swModel Is Nothing Then
        swApp.CloseDoc swModel.GetTitle
        Set swModel = Nothing
        Set swDraw = Nothing
    End If
    Resume Next
End Sub

''' <summary>
''' 図面のシートサイズに基づき、PageSetupを動的に制御する
''' </summary>
Private Sub ConfigurePageSetup(ByRef swDraw As SldWorks.DrawingDoc)
    Dim swPageSetup As SldWorks.PageSetup
    Set swPageSetup = swDraw.PageSetup
    
    ' ここでは例として、標準的な設定を適用。
    ' 実務では、swDraw.GetSheetProperties を用いてシートサイズを取得し、
    ' プリンタの用紙設定と照合するロジックを実装する。
    
    With swPageSetup
        .Orientation = swPageOrientation_Portrait ' 縦向き
        .ScaleToFit = True                        ' 用紙に合わせる
        ' .PrinterName = "Your_Specific_Printer"  ' 特定のプリンタを指定する場合
    End With
End Sub

4. アーキテクトの視点:さらなる高みへ

上記のコードは、一般的な自動化スクリプトを「システム」へと昇華させたものだ。しかし、真のマスターを目指すなら、以下のトピックにも目を向けてほしい。

Windows API によるスプーラー監視

大量の印刷命令を連続して送ると、Windowsのプリントスプーラー(`spoolsv.exe`)が過負荷になり、印刷ジョブがスタックすることがある。高度なシステムでは、`winspool.drv` の API(`OpenPrinter`, `GetJob` 等)を呼び出し、スプーラー内のジョブ待ち行列の長さを監視し、キューが一定数を超えたら一時停止する「流量制御(Flow Control)」を実装する。

非同期処理とヘッドレス・モード

SolidWorksをGUI(可視状態)で動かすことは、リソースの無駄である。`swApp.Visible = False` で実行することは基本だが、さらにパフォーマンスを求めるなら、SolidWorksを「バックグラウンド・タスク」として完全に分離し、UIスレッドをブロックしない設計が求められる。

ログの構造化

「エラーが発生しました」というメッセージは、管理者にとって何の役にも立たない。`Timestamp | FilePath | ErrorCode | ErrorDescription` という構造化されたログをファイルに出力し、後から機械的に解析できるようにしておくこと。それが、保守性の高いシステムを作るプロフェッショナルの作法だ。

結言

自動化とは、単に作業を楽にすることではない。「人間が介在することで発生するエラーの確率を、数学的にゼロに近づけるプロセス」である。

メモリの一片、オブジェクトの参照一つにまで魂を込めて設計すること。それが、伝説的なエンジニアと呼ばれる者が歩む道である。

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