SolidWorks VBAを掌握する極限の知見
【上級プロ】トランザクション管理によるアセンブリ一括構築のロールバック実装
アセンブリの自動化において、最も恐ろしい瞬間を知っているか?
それは、数千点に及ぶ部品の配置と合致(Mate)の定義の最中、プロセスが中盤でクラッシュし、「中途半端に散らかったゴミのようなアセンブリ」がディスクに書き残される瞬間だ。
ネット上のコードによくある `ModelDocExtension::StartCommand` や、UIのボタンクリックをシミュレートする安易なマクロ記録の流用。これらは実務の巨大なアセンブリの前では無力であり、百害あって一利なしだ。エラーが起きた瞬間、画面はフリーズし、未完全な合致エラー(Red Error)の山が残り、ユーザーは頭を抱えることになる。
真のエンジニアリングにおいて、バッチ処理は「全か無か(All-or-Nothing)」でなければならない。
今回は、SolidWorks APIのメモリ管理とドキュメントライフサイクルを熟知した者だけが扱える、「トランザクション管理によるアセンブリ一括構築のロールバック実装」の全貌を授けよう。
—
なぜ `StartCommand` や「なりゆき保存」では破綻するのか?
多くの初級・中級プログラマが陥る罠は、エラーハンドリングを `On Error Resume Next` で雑に塗りつぶし、途中で失敗したアセンブリをそのまま `Save` することだ。
非効率なアプローチの弊害:
1. UIコンテキストへの依存: `StartCommand` はSolidWorksの画面描画や選択状態(SelectionMgr)に強く依存するため、バックグラウンド処理や大規模アセンブリでは確実に対象をロストする。
2. メモリリークとCOMオブジェクトの残骸: 失敗したインスタンスがメモリ上に浮遊し続け、VBAのセッション全体を不安定にする。
3. トランザクション概念の欠如: データベースの世界では常識である「コミットメントとロールバック」の概念をAPIレベルで構築していないため、失敗時のクリーンアップが手動になる。
堅牢なアセンブリ構築の設計思想
今回構築するアーキテクチャの核心は以下の3点だ。
1. サンドボックス(一時ドキュメント)戦略:
本番のアセンブリファイルを直接汚染せず、メモリ上(あるいは非表示)で新規アセンブリを組み立て、すべての合致が完璧に解決(Solve)された瞬間初めてディスクに書き込む。
2. 厳格な例外監視とスコープ管理:
処理の途中で予期せぬエラー(ゼロ除算、ファイル未検出、合致の過拘束など)が発生した場合、即座に例外をキャッチし、メモリ上のドキュメントを「保存せずに破棄」する。
3. 明示的なリビルド制御:
合致を追加する都度の重いリビルドを避け、一括追加後に一度だけ完全解決(ForceRebuild3)を実行する。
—
プロダクションコード例:トランザクション制御アセンブリビルダー
以下のコードは、実務の現場でそのまま組み込める、堅牢なトランザクション管理つきアセンブリ構築モジュールだ。
Option Explicit
‘ =================================================================================
‘ ódulo名: CAssemblyTransactionManager
‘ 概要: アセンブリのトランザクション構築とロールバックを担保するマスタープロシージャ
‘ =================================================================================
Sub ExecuteBatchAssemblyWithTransaction()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssm As SldWorks.AssemblyDoc
Set swApp = Application.SldWorks
‘ 1. トランザクション開始前の事前チェック
If swApp Is Nothing Then Exit Sub
Dim targetTemplate As String
targetTemplate = swApp.GetUserPreferenceStringValue(swDefaultTemplateAssembly)
Dim docError As Long
Dim docWarning As Long
‘ 【サンドボックスの生成】
‘ 非表示、またはバックグラウンドに近い状態で新規アセンブリをメモリ上に立ち上げる
‘ ※完全な完全サイレント起動はAPIの制約があるため、ドキュメント作成後に即座にsetVisibleなどで制御
Set swModel = swApp.NewDocument(targetTemplate, swDwgPaperA4size, 0#, 0#)
If swModel Is Nothing Then
MsgBox “アセンブリテンプレートのロードに失敗しました。”, vbCritical
Exit Sub
End If
Set swAssm = swModel
‘ トランザクション・フラグの初期化
Dim isTransactionSuccessful As Boolean
isTransactionSuccessful = False
‘ エラーハンドリングのスコープへ移行
On Error GoTo RollbackHandler
‘ =================================================================
‘ 【トランザクション領域(業務ロジック)】
‘ ここに部品の挿入と合致定義を記述する。
‘ 途中でエラーが発生した場合、必ずRollbackHandlerへジャンプする。
‘ =================================================================
Debug.Print “— トランザクション処理開始 —”
‘ 例:部品Aの挿入(パスは環境に合わせて変更してください)
Dim partPathA As String
partPathA = “C:\Components\BasePlate.sldprt”
Dim compA As SldWorks.Component2
Set compA = swAssm.AddComponents3(partPathA, 0, 0, 0)
If compA Is Nothing Then Err.Raise vbObjectError + 1001, “AssemblyBuilder”, “部品Aの配置に失敗しました。”
‘ 例:部品Bの挿入
Dim partPathB As String
partPathB = “C:\Components\Pin.sldprt”
Dim compB As SldWorks.Component2
Set compB = swAssm.AddComponents3(partPathB, 0, 0, 0.1)
If compB Is Nothing Then Err.Raise vbObjectError + 1002, “AssemblyBuilder”, “部品Bの配置に失敗しました。”
‘ 【重要】合致定義の実行(本来は面やエッジの特定処理が入る)
‘ ここで過拘束や矛盾エラーが発生すると、自動的にErr.Raiseが発生する想定
Call DefineMatesStub(swModel, compA, compB)
‘ 最終リビルドの実行
Dim rebuildSuccess As Boolean
rebuildSuccess = swModel.ForceRebuild3(False)
If Not rebuildSuccess Then
Err.Raise vbObjectError + 1003, “AssemblyBuilder”, “アセンブリの幾何学解決(リビルド)に失敗しました。”
End If
‘ =================================================================
‘ トランザクション正常終了(コミット)
‘ =================================================================
isTransactionSuccessful = True
‘ 必要に応じてここで初めて名前をつけて保存する
Dim saveSuccess As Boolean
Dim savedPath As String
savedPath = “C:\Assemblies\AutoGenerated_Assm.sldasm”
‘ 既存ファイルがある場合の強制上書き保存フラグ等を設定
Dim saveError As Long, saveWarning As Long
saveSuccess = swModel.Extension.SaveAs3(savedPath, 0, 2, Nothing, Nothing, saveError, saveWarning)
If Not saveSuccess Then
Err.Raise vbObjectError + 1004, “AssemblyBuilder”, “生成されたアセンブリの保存に失敗しました。Error Code: ” & saveError
End If
Debug.Print “— トランザクション正常終了 (Commit) —”
Exit Sub
RollbackHandler:
‘ =================================================================
‘ 【ロールバック領域(例外処理)】
‘ 処理の途中で死んだ場合、作成中のドキュメントをディスクに残さず破棄する
‘ =================================================================
If Not isTransactionSuccessful Then
Dim errDesc As String
errDesc = Err.Description
Debug.Print “!!! エラー発生によるロールバック実行: ” & errDesc
If Not swModel Is Nothing Then
Dim modelTitle As String
modelTitle = swModel.GetTitle()
‘ メモリ上からドキュメントを強制閉鎖(変更を破棄: False = NoSave)
swApp.CloseDoc modelTitle
End If
MsgBox “アセンブリの自動構築中に致命的なエラーが発生しました。” & vbCrLf & _
“変更はすべて破棄されました(ロールバック完了)。” & vbCrLf & vbCrLf & _
“詳細: ” & errDesc, vbCritical, “トランザクション異常終了”
End If
End Sub
‘ 合致定義のスタブ(実務ではここにMate2などのAPI群を記述する)
Private Sub DefineMatesStub(ByRef swModel As SldWorks.ModelDoc2, ByRef compA As SldWorks.Component2, ByRef compB As SldWorks.Component2)
‘ 擬似的なエラー検証(テスト時はここをわざとエラーにしてみよ)
Dim simulateError As Boolean
simulateError = False ‘ Trueにするとロールバックのテストが可能
If simulateError Then
Err.Raise vbObjectError + 9999, “MateDefine”, “意図的な合致エラーの発生”
End If
‘ 実務では swModel.Extension.SelectByID2 などを駆使して Mate 関連APIを叩く
End Sub
—
プロフェッショナルのための実装上の急所と注意点
1. ドキュメントタイトルの特定による確実なクローズ
エラー時に `swApp.CloseDoc` を呼ぶ際、オブジェクト変数そのものを渡すのではなく、`swModel.GetTitle()` で取得したタイトル文字列を使うこと。COMラッパーの参照切れによる「ドキュメントが閉じられない現象」を完全に回避できる。
2. ファイル名重複とデータベース連携の罠
もしこの自動化システムが外部のPLMやPDS(Product Data Management)、あるいはExcelデータベースと連携している場合、途中で失敗したファイルがゴミとして残ると、次回のバッチ実行時にファイル名競合(File Name Conflict)を引き起こす。今回のロールバック実装により、「失敗時はディスクの消費容量が1バイトも増えない」というクリーンな状態が保証される。
3. トランザクションの粒度(Granularity)
アセンブリ全体を1つのトランザクションにするのが基本だが、サブアセンブリ(Sub-Assembly)を複数抱える巨大な構造の場合、サブアセンブリ単位でこのトランザクション構造をネスト(あるいは関数分離)させると、保守性が劇的に向上する。
—
結びにかえて
自動化とは、ただ手数を減らすことではない。
「想定外の異常事態が発生したときに、システムがどれだけ優雅に、かつ安全に元の安全地帯へ帰還できるか」。こここにプロとアマの決定的な境界線がある。
`StartCommand` やマウス操作の模倣に頼る開発からは、今日で卒業しなさい。APIのライフサイクルを支配し、堅牢なトランザクション・アーキテクチャをその手で実装せよ。それこそが、現場の信頼を勝ち得く唯一のエンジニアリングである。
