【SolidWorks VBA上級】アセンブリ構築を完全保護する!ロールバック可能なトランザクション構造の極意
開発プロジェクトのリーダーである私たちが、日常的に直面する悪夢がある。それは、数百点に及ぶ部品の配置と複雑な合致(Mate)の自動生成スクリプトが、処理の途中でエラーを起こし、中途半端な状態でアセンブリが放置されるという現象だ。
画面上に散らばったゴミデータ、外部参照の不整合、そして「手動でどこまで汚されたか分からないファイル」の山。これをリカバリーするために費やす時間は、エンジニアにとって完全なる無駄である。
今回は、SolidWorks VBAの限界を突破し、アセンブリ構築プロセス全体を「完全なトランザクション(ACID特性)」で包み込み、例外発生時に一瞬で初期状態へ復元する極限のアーキテクチャを伝授する。
—
なぜ従来の書き方では破綻するのか?
多くの初学者や中級プログラマは、以下のようなコードを書く。
‘ 【悪手】エラー対策のない直線的なアセンブリ構築
Sub BadAssemblyBuild()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim swAssy As SldWorks.ModelDoc2
Set swAssy = swApp.NewAssembly() ‘ ←ここでアセンブリ新規作成
‘ 部品Aを挿入
Dim compA As SldWorks.Component2
Set compA = swAssy.Extension.InsertComponent3(“C:\PartA.sldprt”, …)
‘ 部品Bを挿入(ここでパスミスなどの予期せぬエラー発生!)
Dim compB As SldWorks.Component2
Set compB = swAssy.Extension.InsertComponent3(“C:\PartB_Typo.sldprt”, …)
‘ 合致の定義…
‘ (エラーで中断すると、PartAだけが入ったゴミアセンブリが残る)
End Sub
この書き方が「悪」である理由
1. 副作用の放置: `InsertComponent3` や `AddMate` は、実行された瞬間にSolidWorksのドキュメントメモリおよびディスク上のセッションに不可逆な変更を加える。
2. クリーンアップの欠如: エラーハンドラー(`On Error GoTo`)を書いたとしても、生成された途中の合致やコンポーネントを正確に逆順で削除するコードは肥大化し、バグの温床になる。
3. トランザクション概念の不在: 「すべて成功するか、一切変更を加えないか」の二者択一が保証されていない。
—
堅牢なアセンブリ・トランザクション設計の核心
この問題を解決するアプローチは極めてシンプルかつ高度だ。
1. サンドボックス(非表示モード)での構築:
アセンブリの新規作成や部品のロードを、ユーザーの目に見えない非表示(Silent/Invisible)モード、あるいはメモリ上のトランザクション空間で実行する。
2. スマート・ファイル・ライフサイクル管理:
新規アセンブリであれば、明示的に「保存して閉じる」か「破棄する」かをコード側で完全にコントロールする。途中で破綻した場合は、ドキュメントを未保存のまま(あるいは強制破棄して)セッションからパージする。
3. Undo/Redoスタックの活用、またはマクロフィーチャー的アプローチ:
SolidWorksの持つコマンド履歴をAPIレベルで制御し、トランザクション開始時点のマークまで一気にロールバックする。
特に実務で最も効果を発揮するのが、「一時ファイルを非表示で作成し、完全成功時のみユーザーにセッションを移行する(あるいはディスクに永続化する)」というセーフガードパターンだ。
—
プロダクションコード:ロールバック可能なアセンブリ構築エンジン
以下のコードは、実際の現場で即座に採用できる、トランザクション構造を持ったアセンブリ自動生成のテンプレートである。例外が発生した場合、アセンブリは痕跡を残さず破棄される。
Option Explicit
‘ ==============================================================================
‘ 業務自動化アーキテクチャ:アセンブリ・トランザクション制御エンジン
‘ ==============================================================================
Sub Main_BuildAssemblyWithTransaction()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim targetAssyPath As String
targetAssyPath = “C:\Projects\GeneratedAssembly.sldasm”
‘ トランザクションの成否フラグ
Dim isSuccess As Boolean
isSuccess = False
‘ 1. 【トランザクション開始】
‘ ユーザーインターフェースをロックし、バックグラウンド処理の高速化と視覚的ノイズの排除を行う
swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swInteractiveProcess, False
swApp.CommandInProgress = True
Dim swAssyDoc As SldWorks.ModelDoc2
Dim docError As Long, docWarning As Long
On Error GoTo TransactionRollback
‘ 非表示、あるいは新規ドキュメントとしてメモリ上に展開
Set swAssyDoc = swApp.NewAssembly()
If swAssyDoc Is Nothing Then Err.Raise 1001, “Transaction”, “アセンブリの新規作成に失敗しました。”
Dim swAssyModel As SldWorks.AssemblyDoc
Set swAssyModel = swAssyDoc
‘ ————————————————————————–
‘ 2. 【プロセス本体】部品の配置と合致定義(ここに業務ロジックを書く)
‘ ————————————————————————–
Debug.Print “プロセス開始: 部品Aの挿入…”
Dim compA As SldWorks.Component2
Set compA = swAssyModel.AddComponent5(“C:\Parts\BasePlate.sldprt”, 0, 0, 0, 0, 0, 0)
If compA Is Nothing Then Err.Raise 1002, “Transaction”, “部品Aの挿入に失敗しました。”
‘ あえてエラーを誘発するテスト(存在しない部品を指定)
Debug.Print “プロセス継続: 部品Bの挿入(意図的なテスト)…”
Dim compB As SldWorks.Component2
Set compB = swAssyModel.AddComponent5(“C:\Parts\NonExistentPart.sldprt”, 0, 0, 0, 0, 0, 0)
If compB Is Nothing Then Err.Raise 1003, “Transaction”, “部品Bの挿入に失敗しました(トランザクションテスト)。”
‘ (ここに高度な合致ロジックが続く…)
‘ ————————————————————————–
‘ すべての処理が成功した場合のみ、成功フラグを立てる
‘ ————————————————————————–
isSuccess = True
GoTo TransactionCommit
TransactionRollback:
‘ ==========================================================================
‘ 【ロールバック処理】異常系
‘ ==========================================================================
Dim errNumber As Long, errSource As String, errDescription As String
errNumber = Err.Number
errSource = Err.Source
errDescription = Err.Description
Debug.Print “【CRITICAL】エラー発生のためトランザクションをロールバックします: ” & errDescription
‘ メモリ上のドキュメントを「変更を破棄して」強制閉局する
If Not swAssyDoc Is Nothing Then
Dim docTitle As String
docTitle = swAssyDoc.GetTitle()
‘ 変更を保存せずに閉じる (swSaveWithoutDocumentChanges / swCloseDoc_Abort)
swApp.CloseDoc docTitle
End If
‘ ユーザーに通知
swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swInteractiveProcess, True
swApp.CommandInProgress = False
MsgBox “アセンブリの自動生成中にエラーが発生したため、変更は完全に破棄されました。” & vbCrLf & _
“詳細: ” & errDescription, vbCritical, “トランザクション・ロールバック実行”
Exit Sub
TransactionCommit:
‘ ==========================================================================
‘ 【コミット処理】正常系
‘ ==========================================================================
‘ ディスクへの保存
Dim saveStatus As Long
saveStatus = swAssyDoc.SaveAs3(targetAssyPath, 0, 2) ‘ swSaveAsOptions_Silent 等を適切に指定
‘ UIのロック解除
swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swInteractiveProcess, True
swApp.CommandInProgress = False
Debug.Print “【SUCCESS】トランザクションが正常にコミットされました。”
MsgBox “アセンブリの構築が正常に完了し、保存されました。”, vbInformation, “完了”
End Sub
—
チーフアーキテクトからの実践的アドバイス:ファイル・DB連携時の注意点
1. PDS/PLM(PDMWorksやENOVIA, Teamcenterなど)との統合における罠
トランザクション内でファイルを一時保存・削除するアプローチを取る場合、PDMのチェックアウト状態と競合することがある。PDM環境下では、ローカルキャッシュの整合性を保つため、API側で `EdmConstants` や PDM専用のインデクス制御をバイパスしないよう、「トランザクションの事前検証(Pre-Flight Check)」を必ず実装すること。つまり、処理を始める前に「すべてのファイルが指定パスに存在するか」「書き込み権限があるか」を走査し、1つでも欠けていればアセンブリ作成すら開始しない設計が最も安全である。
2. UIロック(`InteractiveProcess`)の確実な解除
VBAでエラートラップを書き損ねると、UIがロックされたままSolidWorksがフリーズしたような状態になり、エンドユーザーがタスクマネージャーから強制終了せざるを得なくなる。そのため、`On Error` を使う際は必ず例外ルートと正常系ルートの両方でUI復元処理を通す、あるいは共通のクシ(クリーンアップブロック)を通す構造を徹底すること。
—
総括
プログラマの腕の差は、「うまく動くコードを書く能力」ではなく、「異常系(エッジケース)に直面したときにシステムをいかに美しく、安全に元の状態へ戻せるか」という設計思想の深さに宿る。
今回解説したトランザクション構造をあなたのツール群に導入すれば、無用なデバッグ作業やデータの破損から解放され、真に価値のある自動化ロジックの構築に集中できるようになるはずだ。妥協のない設計を、今すぐあなたの現場へ実装してほしい。
