【SolidWorks VBA極限解説】ActiveDocの幻想を断つ:事故ゼロを実現する型安全なパーツ判定イディオム
現場で動く自動化ツールを開発するチーフアーキテクトの私から、まず最初に残酷な現実を告げよう。
ネット上に散らばる「`Set swDoc = swApp.ActiveDoc` と書いておけば動く」というコードをそのまま社内展開しているなら、明日にも大規模な業務エラーを引き起こすだろう。
SolidWorks VBA開発において、アクティブドキュメントの取得と型の特定を怠ることは、時限爆弾を抱えて生産ラインに立つようなものだ。
今回は、初心者から一歩抜け出し、「絶対に落ちない、バグらない」プロダクション品質のパーツ操作コードを構築するための極限の知見を授けよう。
—
なぜ `ActiveDoc` だけでは実務で使い物にならないのか?
多くの入門書では、次のようなコードが平然と紹介されている。
‘ 【アンチパターン】絶対に真似してはならない危険なコード
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Sub DangerousMacro()
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
‘ ここでいきなり操作を始める…
swModel.Extension.SelectByID2 …
End Sub
このコードが実務で大惨事を引き起こす理由は3つある。
1. 何も開いていない(Null参照)の恐怖
SolidWorksが起動しているだけで、ドキュメントが1つも開かれていない状態で実行すると、`swModel` は `Nothing` になる。次の行でメソッドを叩いた瞬間、VBAは容赦なく実行時エラー「428:オブジェクト変数または With ブロック変数が設定されていません」でクラッシュする。
2. アセンブリや図面がアクティブな場合の誤作動
ユーザーがうっかりアセンブリ(`.sldasm`)や図面(`.slddrw`)を開いたままマクロを実行した場合、パーツ(`.sldprt`)専用のフィーチャ操作ロジックが走り、予期せぬデータ破損や強制終了を引き起こす。
3. 暗黙の型キャストの罠
`ModelDoc2` は、パーツ、アセンブリ、図面の「すべての根幹」となる抽象インターフェースに過ぎない。これを具体的な型(パーツなら `PartDoc`)へと安全に安全弁を噛ませて昇華させなければ、堅牢なシステムとは言えない。
—
堅牢な設計:安全な取得と厳密な型判定のロジック
プロのエンジニアが書くべきコードは、「疑うことから始める」コードだ。
SolidWorks APIにおけるドキュメントの種別(Document Type)は、定数 `swDocumentTypes_e` で明確に定義されている。
- `swDocPART` (1) : パーツ
- `swDocASSEMBLY` (2) : アセンブリ
- `swDocDRAWING` (3) : 図面
これを利用し、「①アプリの存在確認 $\rightarrow$ ②ドキュメントの存在確認 $\rightarrow$ ③アクティブ文書がパーツであることの厳密な型判定」という3段階のガード cláusule(ガード節)を突破した時だけ、真の処理を実行する。
—
【コピペ即実戦投入可】プロダクション品質の堅牢テンプレート
以下のコードは、実務の現場で私がリファレンスとしてチームに強制している、エラーハンドリングと型安全を極めたテンプレートだ。そのままコピー&ペーストして活用してほしい。
‘ ==============================================================================
‘ モジュール名: modSafePartOperation
‘ 概要 : アクティブドキュメントを安全に取得し、パーツであることを保証するテンプレート
‘ ==============================================================================
Option Explicit
Public Sub ExecuteSafePartMacro()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swPart As SldWorks.PartDoc
‘ 1. SldWorksアプリケーションのインスタンスを取得
‘ ※GetObjectではなくComHelperやSldWorks.Applicationを使用
Set swApp = Application.SldWorks
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。”, vbCritical, “致命的エラー”
Exit Sub
End If
‘ 2. アクティブドキュメントが存在するかチェック(Null参照防止)
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “現在、アクティブなドキュメントが開かれていません。” & vbCrLf & _
“対象となるパーツファイルを開いてから実行してください。”, vbExclamation, “操作中断”
Exit Sub
End If
‘ 3. ドキュメントの種別が「パーツ」であるかを厳密に判定
‘ ※アセンブリや図面での誤作動を完全にブロック
If swModel.GetType <> swDocPART Then
MsgBox “このマクロは「パーツ(Part)ファイル」専用です。” & vbCrLf & _
“現在アクティブなファイルはパーツではありません。”, vbCritical, “型不一致エラー”
Exit Sub
End If
‘ 4. 安全にパーツ専用インターフェースへキャスト(型安全の担保)
Set swPart = swModel
If swPart Is Nothing Then
MsgBox “パーツドキュメントへの型変換に失敗しました。”, vbCritical, “内部エラー”
Exit Sub
End If
‘ ==========================================================================
‘ 【安全領域】 ここから下は、確実に「パーツが開かれている状態」が保証される
‘ ==========================================================================
Call RunMainProcess(swApp, swModel, swPart)
End Sub
‘ 実業務の処理を記述するメインプロシージャ
Private Sub RunMainProcess(ByVal app As SldWorks.SldWorks, _
ByVal model As SldWorks.ModelDoc2, _
ByVal part As SldWorks.PartDoc)
‘ 例:パーツのタイトルを取得してログに出力
Dim docTitle As String
docTitle = model.GetTitle
MsgBox “安全なパーツ取得に成功しました!” & vbCrLf & _
“対象ファイル: ” & docTitle, vbInformation, “処理完了”
‘ ここに実際のジオメトリ生成やフィーチャ操作のコードを記述していく
End Sub
—
チーフアーキテクトからの実務アドバイス
1. メソッドの責務分離(Single Responsibility Principle)
上記のコードを見てお気づきだろうか。「ドキュメントの安全確認・型判定」と「実際の業務処理(`RunMainProcess`)」を完全に分離している。
これにより、将来的に「アセンブリ対応版も作ってほしい」と言われた際も、ガード節の部分だけを拡張、あるいはポリモーフィズム的な設計へとスムーズにリファクタリングできる。
2. データベースや外部ファイル連携時の注意点
こうした自動化ツールは、往々にしてExcelマスタや外部DB(PDMやSQL Serverなど)と連携する。
もし「パーツが開かれていない状態」で外部DBへの書き込みや、図番の照合処理が走ってしまうと、「SolidWorks側は未選択なのに、DB側だけステータスが更新されてしまう」という最悪のデータ不整合(ゴーストデータ)を生む。
ガード節で早期に処理をハネる(Early Returnする)ことは、SolidWorksだけでなく、社内ニッチなインフラ全体の整合性を守るための防壁なのだ。
—
結びに代えて
「動けばいいや」という妥協のコードは、現場のエンジニアの信頼を奪い、マクロそのものが社内で敬遠される原因になる。
今回紹介した型安全な判定イディオムは、あなたの書くVBAコードの信頼性を一気にプロフェッショナルな領域へと引き上げるはずだ。
妥協なき設計で、真の業務効率化をその手で掴み取ってほしい。
