壊れない自動化を目指して:SolidWorks VBAにおける「不屈のバッチ処理」構築術
こんにちは。設計自動化の荒波を共に乗り越えていく仲間たち、ようこそ。
皆さんは、こんな経験はありませんか?
「数時間かけて数百枚の図面を自動生成するマクロを組んだ。順調に進んでいたのに、残り30枚というところでSolidWorksが突然『応答なし』になり、強制終了してしまった……。最初からやり直しだ……」
この絶望感、私も痛いほど分かります。
マクロの記録から一歩踏み出し、「実用的なツール」を作ろうとすると必ずぶつかる壁。それが「SolidWorksという巨大なソフトウェアの不安定さ」です。APIの呼び出しミス、メモリ不足、あるいは壊れた図面ファイルとの遭遇。これらは、どんなに優れたコードを書いても避けられない「自然災害」のようなものです。
今日は、単なるエラー回避(`On Error Resume Next`)のレベルを超えて、「もしクラッシュしても、そこから再開できる」という、プロフェッショナルが現場に導入するレガシーAPIの現代的ラップ(堅牢なフレームワーク)の考え方を伝授します。
ここをクリアすれば、あなたの作るツールは「便利なマクロ」から「信頼できる業務システム」へと昇華します。
1. なぜ「エラーハンドリング」だけでは足りないのか?
多くの初学者が最初に学ぶのは、これでしょう。
On Error GoTo ErrorHandler
' ... 処理 ...
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description
これは非常に重要ですが、「SolidWorksそのものが落ちる(クラッシュする)」場合には無力です。VBAのコードが実行されている「器」であるSolidWorksが消滅してしまうため、`ErrorHandler`に到達する暇もなく、すべてのメモリと変数が消失します。
プロのエンジニアが設計するのは、コードの中だけで完結する対策ではなく、「外部に状態を記録し続ける仕組み」です。これを私たちは「ジャーナリング(Journaling)」と呼びます。
2. 堅牢なシステムの設計思想:ステートフル・オートメーション
クラッシュに強いシステムを作るための鍵は、「今、何をしている最中か」を常に外部ファイル(テキスト等)に書き出しておくことです。
構築するフレームワークのフロー図
1. 起動時チェック: ログファイルを確認。「前回の未完了タスク」があれば、そこから再開。
2. ジャーナル書き込み: 「これからファイルAを処理します」とログに記録。
3. メイン処理: 図面の生成、ビュー配置、シート制御を実行。
4. 完了記録: 「ファイルAの処理が完了しました」とログに記録。
5. 次へ: ファイルBへ。
もし、手順3の途中でクラッシュしても、ログには「ファイルAを処理中」という記録が残っています。再起動したとき、システムは「あ、ファイルAが中途半端だな」と判断して、自動的にリカバリーを開始できるのです。
3. 実践:リカバリー機能付き図面一括処理テンプレート
では、実際に使えるコードの骨組みを見ていきましょう。今回は、`FileSystemObject` を使って、処理の進捗をテキストファイルに記録する高度な構造を実装します。
' --- 参照設定: Microsoft Scripting Runtime を有効にしてください ---
Option Explicit
' 処理の状態を管理する定数
Private Const LOG_FILE_PATH As String = "C:\Temp\SW_Batch_Journal.txt"
Sub MainBatchProcess()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim fileList As Collection
Dim targetFile As Variant
Dim lastCompletedFile As String
Set swApp = Application.SldWorks
Set fileList = New Collection
' 1. 処理対象のファイルリストを作成(本来はフォルダ走査などで取得)
' ここでは例として、デモ用のパスを直接入れています
fileList.Add "C:\Work\Drawing1.slddrw"
fileList.Add "C:\Work\Drawing2.slddrw"
fileList.Add "C:\Work\Drawing3.slddrw"
' 2. 【重要】リカバリー機能:前回の未完了タスクを確認
lastCompletedFile = GetLastCompletedFile(LOG_FILE_PATH)
Debug.Print "Last Completed: " & lastCompletedFile
' 3. ループ処理
For Each targetFile In fileList
' 前回の続きであればスキップするロジック
If ShouldSkip(targetFile, lastCompletedFile) Then
Debug.Print "Skipping: " & targetFile ' 完了済みなのでスキップ
Else
' 4. ジャーナルに「開始」を記録
WriteJournal LOG_FILE_PATH, "START:" & targetFile
' 5. メインの図面処理(ここでエラーが起きてもログは残っている)
On Error GoTo ErrorHandler
Call ProcessDrawing(swApp, CStr(targetFile))
' 6. ジャーナルに「完了」を記録
WriteJournal LOG_FILE_PATH, "DONE:" & targetFile
End If
Next targetFile
MsgBox "全工程が完了しました!", vbInformation
Exit Sub
ErrorHandler:
' 個別のファイルエラー(ファイルが開けない等)はログに残して次に進む
WriteJournal LOG_FILE_PATH, "ERROR:" & targetFile & " | " & Err.Description
Resume Next
End Sub
' --- 図面処理のコアロジック ---
Sub ProcessDrawing(swApp As SldWorks.SldWorks, filePath As String)
Dim swModel As SldWorks.ModelDoc2
Dim swDraw As SldWorks.DrawingDoc
' 図面を開く
Set swModel = swApp.OpenDoc6(filePath, swDocDRAWING, swOpenDocOptions_Silent, "", 0, 0)
If swModel Is Nothing Then Err.Raise 999, , "ファイルを開けませんでした。"
Set swDraw = swModel
' --- ここに図面操作のAPIを記述 ---
' 例: シートのフォーマット変更、ビューの配置など
' swDraw.ActivateSheet "Sheet1"
' ...
' ------------------------------
' 保存して閉じる
swModel.Save3 swSaveAsOptions_Silent, 0, 0
swApp.CloseDoc swModel.GetTitle
End Sub
' --- ユーティリティ関数群 ---
' ログファイルに一行追記する
Sub WriteJournal(path As String, message As String)
Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
' 追記モード(8)で開く
Set ts = fso.OpenTextFile(path, 8, True)
ts.WriteLine Now & " | " & message
ts.Close
End Sub
' 最後に "DONE:" と記録されたファイル名を取得する
Function GetLastCompletedFile(path As String) As String
Dim fso As Object
Dim ts As Object
Dim line As String
Dim lastDone As String
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(path) Then
GetLastCompletedFile = ""
Exit Function
End If
Set ts = fso.OpenTextFile(path, 1) ' 読み取りモード
Do While Not ts.AtEndOfStream
line = ts.ReadLine
If InStr(line, "DONE:") > 0 Then
' "DONE:C:\Path\To\File" の部分を抽出
lastDone = Mid(line, InStr(line, "DONE:") + 5)
' 文字列の整形(タイムスタンプを除去)
If InStr(lastDone, " |") > 0 Then
lastDone = Left(lastDone, InStr(lastDone, " |") - 1)
End If
End If
Loop
ts.Close
GetLastCompletedFile = lastDone
End Function
' スキップ判定ロジック
Function ShouldSkip(currentFile As Variant, lastDone As String) As Boolean
' 厳密には、前回の「START」が「DONE」になっていないかチェックするロジックが理想
' 今回は簡易的に「最後に完了したファイルと同じならスキップ」とする
If lastDone = currentFile Then
ShouldSkip = True
Else
ShouldSkip = False
End If
End Function
4. このコードが「プロフェッショナル」である理由
このコードには、初学者が陥りがちな罠を回避する3つの知恵が詰まっています。
① 外部メモリ(ファイル)への依存
SolidWorksのメモリがどれほど不安定になろうとも、`C:\Temp\SW_Batch_Journal.txt` という外部ファイルは、OSが守っています。これが「不屈」の源です。
② 「START」と「DONE」の分離
単に「処理中」と書くのではなく、`START` と `DONE` を分けて記録しています。これにより、「STARTは書かれているが、DONEが書かれていない」=「このファイルでクラッシュした」という事実を、プログラムが後から確実に検知できます。
③ `On Error GoTo` の適切な使い分け
全体の流れを管理する `MainBatchProcess` と、個別の作業を行う `ProcessDrawing` を分離しています。これにより、一つの図面でエラーが起きても、システム全体を止めずに「エラーをログに記録して次のファイルへ進む」という、粘り強い動きが可能になります。
最後に:エンジニアとしてのマインドセット
自動化の世界では、「100%成功するコード」を書くことは不可能です。 どんなに完璧なロジックも、ハードウェアの故障や予期せぬバグの前では無力です。
だからこそ、真のプロフェッショナルは「失敗したときに、いかにスマートに、いかに最小限の手間で復旧するか」に思考の重きを置きます。
今回紹介した「ジャーナリング」の考え方は、VBAに限らず、Python、C#、あるいは大規模なサーバーシステムでも共通する、極めて重要な設計思想です。
このコードをベースに、自分なりのエラーログや、エラー発生時の通知機能(メール送信など)を追加してみてください。その積み重ねが、あなたを「単なるマクロ使い」から「信頼されるエンジニア」へと変えてくれるはずです。
応援しています。さあ、次はもっと複雑な自動化に挑戦しましょう!
