皆さん、こんにちは! SolidWorks VBAの世界へようこそ。
マクロの記録から一歩踏み出し、もっと自由に、もっと堅牢な自動化を目指したいと願う皆さんにとって、この記事はきっと役立つはずです。今回は、SolidWorks VBAを扱う上で避けて通れない、しかし最も重要なテーマの一つである「エラーハンドリング」に焦点を当てます。
特に、SolidWorks API特有の「Rebuild Error」や、選択参照の喪失に起因する「Selection Mark Error」といった、一見すると対処が難しいエラーを、どのようにして的確に捉え、処理を中断させずにエラー原因を特定するのか。その「極限の知見」を皆さんに伝授します。
まるでベテランの探偵が事件現場の痕跡から真実を突き止めるように、SolidWorks VBAのエラーメッセージの裏に隠された真の原因を見つけ出す方法を、一緒に学んでいきましょう。ここをクリアすれば、SolidWorks VBAの基本はバッチリですよ!
—
エラーは友達? SolidWorks VBAの奥深いエラーハンドリングの世界へ
VBAでコードを書いていると、予期せぬエラーに遭遇することは日常茶飯事です。「あれ?さっきまで動いていたのに…」「このフィーチャ、なぜか作成できない!」といった経験、皆さんにもあるのではないでしょうか?
特にSolidWorks VBAでは、単なるVBAの文法エラーだけでなく、APIの呼び出し方や、SolidWorksの設計ルールに起因する「固有のエラー」が数多く存在します。そして厄介なことに、これらのエラーはVBA標準の `Err` オブジェクトだけでは詳細を掴みにくいことが多いのです。
しかし、恐れることはありません。エラーは、私たちのコードをより強く、より賢くするための貴重なフィードバックです。適切にエラーをハンドリングすることで、マクロは単に動くだけでなく、「何が問題なのか」を自ら語り、「どうすれば解決できるのか」を示唆してくれるようになるのです。
SolidWorks APIのエラー通知:基本と限界
SolidWorks APIのメソッドは、処理が成功したか失敗したかを伝えるために、様々な方法でフィードバックを返します。
- 戻り値: 多くのメソッドは `Boolean` (True/False) や `Long` (成功コード/エラーコード) を返します。例えば、`ModelDoc2.ActivateView` はビューの活性化に成功すれば `True` を返します。
- メッセージボックス: SolidWorksは、特に重要な警告やエラーが発生した場合、ポップアップメッセージボックスを表示することがあります。`swMessageBoxWarning` や `swMessageBoxError` といった種類がありますね。
- `SldWorks.SendMsgToUser2`: コード内で意図的にユーザーにメッセージを送信するためのメソッドです。
しかし、これらの基本的な通知だけでは、特に複雑なジオメトリ操作やフィーチャ作成で発生するエラーの根本原因を特定するには不十分な場合が多いのです。
VBAの`On Error`ステートメントの限界
VBAには `On Error GoTo` という非常に強力なエラーハンドリングステートメントがあります。これにより、実行時エラーが発生した際に指定したエラー処理ルーチンにジャンプし、エラー番号 (`Err.Number`) やエラー内容 (`Err.Description`) を確認できます。
Sub BasicErrorHandler()
On Error GoTo ErrHandler ‘ エラーが発生したらErrHandlerへジャンプ
Dim num As Integer
num = 10 / 0 ‘ ゼロ除算エラーを意図的に発生させる
MsgBox “処理が完了しました。”
GoTo EndSub
ErrHandler:
MsgBox “エラーが発生しました!” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“説明: ” & Err.Description, vbCritical
EndSub:
‘ クリーンアップ処理など
End Sub
これは一般的なVBAエラーには非常に有効です。しかし、SolidWorks APIが内部的に発生させる「Rebuild Error」や「Selection Mark Error」のようなエラーは、VBAの `Err.Number` に直接、詳細なSolidWorks固有のエラーコードとして現れることは稀です。多くの場合、`EditRebuild3` の戻り値が `True` になるだけで、VBAの `Err` オブジェクトには何も記録されない、といった状況に陥りがちです。
ここで、いよいよ「極限の知見」の出番です。
—
【本質】「Rebuild Error」を深掘りする:どのフィーチャが問題なのか?
SolidWorksでフィーチャを作成したり、変更したりした際に、モデルが再構築(リビルド)されます。このリビルドの過程で、ジオメトリ的な矛盾や参照の欠落などが発生すると、「Rebuild Error」が発生します。
例えば、「穴フィーチャを作成しようとしたが、参照するエッジが見つからない」「押し出しの方向が不正である」といったケースです。SolidWorksの画面上では、フィーチャツリーのアイコンに「!」マークが表示されたり、黄色い警告が表示されたりしますね。
`ModelDoc2.EditRebuild3` の戻り値を監視する
マクロでフィーチャを操作した後、モデルをリビルドするために `ModelDoc2.EditRebuild3` メソッドを呼び出すことがよくあります。このメソッドは、リビルドの結果としてエラーが発生したかどうかを `Boolean` 型で返してくれます。
Dim swModel As SldWorks.ModelDoc2
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then Exit Sub
Dim rebuildErrors As Boolean
rebuildErrors = swModel.EditRebuild3 ‘ モデルをリビルド
If rebuildErrors Then
MsgBox “リビルド中にエラーが発生しました!”, vbCritical
Else
MsgBox “リビルドは正常に完了しました。”, vbInformation
End If
これで「エラーが発生したか否か」は分かります。しかし、「どのフィーチャで、どんな種類のエラーが発生したのか?」までは分かりません。ここが問題なのです。
【極限の知見】`Feature.Error` プロパティで真犯人を特定する!
ここからが、伝説的なチーフアーキテクトが教える「本当の」エラー特定術です。
`ModelDoc2.EditRebuild3` が `True` を返した場合、SolidWorksの内部では、エラーを引き起こしたフィーチャに対して、その「エラー状態」が記録されています。私たちは、この記録を「まるで探偵が現場の証拠品を一つずつ調べるように」、APIを通して確認することができます。
その鍵となるのが、`Feature` オブジェクトが持つ`Error` プロパティです。このプロパティは、そのフィーチャにエラーがある場合に `True` を返します。
つまり、リビルド後にモデル内のすべてのフィーチャを順番に走査し、`Feature.Error` が `True` になっているものを探し出せば、エラーの原因となっているフィーチャを特定できるのです!
コード例:Rebuild Errorの原因フィーチャを特定する
以下のコードは、新規パーツを作成し、意図的にエラーとなるフィーチャ(ここでは不正な参照を持つ押し出し)を追加した後、リビルドを行い、どのフィーチャにエラーがあるかを特定するテンプレートです。
Option Explicit
‘ SolidWorks APIオブジェクトを宣言
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swPart As SldWorks.PartDoc
Dim swFeatMgr As SldWorks.FeatureManager
Dim swFeat As SldWorks.Feature
Dim swSketchMgr As SldWorks.SketchManager
Dim swSelMgr As SldWorks.SelectionMgr
Sub SolidWorksRebuildErrorHandler()
‘— エラーハンドリングの開始 —
On Error GoTo ErrHandler
‘ SolidWorksアプリケーションに接続
Set swApp = Application.SldWorks
‘— ユーザー設定の一時変更(警告メッセージの抑制) —
‘ これにより、SolidWorksが自動で表示する警告メッセージボックスを抑制し、
‘ マクロでエラーを捕捉しやすくなります。
‘ 処理の最後に元の設定に戻すことを忘れないでください。
Dim originalWarningSetting As Long
originalWarningSetting = swApp.GetUserPreferenceIntegerValue(swUserPreferenceIntegerValue_e.swViewWarningMessages)
swApp.SetUserPreferenceIntegerValue swUserPreferenceIntegerValue_e.swViewWarningMessages, False
‘ 新規パーツドキュメントを作成
Set swModel = swApp.NewDocument(“C:\ProgramData\SolidWorks\SolidWorks 2023\templates\Part.prtDot”, 0, 0, 0)
If swModel Is Nothing Then
MsgBox “新規パーツドキュメントの作成に失敗しました。”, vbCritical
GoTo EndSub
End If
Set swPart = swModel
swModel.Visible = True ‘ ドキュメントを表示
swModel.FeatureManager.EnableFeatureTree = True ‘ フィーチャツリーを表示
swModel.ClearSelection2 True ‘ 選択をクリア
‘————————————————————
‘ 1. 正常なフィーチャを作成する(基準となる押し出し)
‘————————————————————
Call CreateBaseExtrude
‘————————————————————
‘ 2. 意図的にエラーとなるフィーチャを作成する
‘ (ここでは、存在しない平面を参照しようとする不正な押し出しを試みます)
‘————————————————————
Call CreateErrorExtrude
‘————————————————————
‘ 3. モデルをリビルドし、エラー状態をチェックする
‘————————————————————
Dim rebuildErrors As Boolean
rebuildErrors = swModel.EditRebuild3 ‘ モデル全体をリビルド
If rebuildErrors Then
‘ リビルドエラーが発生した場合、どのフィーチャが原因かを特定する
MsgBox “リビルド中にエラーが発生しました。原因フィーチャを特定します。”, vbExclamation
Set swFeatMgr = swModel.FeatureManager
Dim vFeatures As Variant
Dim i As Long
‘ モデル内のすべてのフィーチャを取得
vFeatures = swFeatMgr.GetFeatures(True) ‘ Trueでサプレス状態のフィーチャも取得
If Not IsEmpty(vFeatures) Then
For i = LBound(vFeatures) To UBound(vFeatures)
Set swFeat = vFeatures(i)
‘ Feature.ErrorプロパティがTrueの場合、そのフィーチャがエラーの原因
If swFeat.Error Then
MsgBox “エラーフィーチャ発見!” & vbCrLf & _
“名前: ” & swFeat.Name & vbCrLf & _
“タイプ: ” & swFeat.Type, vbCritical
‘ ここでログファイルに書き込んだり、ユーザーに具体的な指示を出したりできます。
End If
Next i
End If
Else
MsgBox “リビルドは正常に完了しました。”, vbInformation
End If
‘— 処理終了 —
MsgBox “マクロ処理が完了しました。”, vbInformation
EndSub:
‘— クリーンアップ処理 —
On Error Resume Next ‘ クリーンアップ中のエラーは無視
‘ ユーザー設定を元に戻す
If Not swApp Is Nothing Then
swApp.SetUserPreferenceIntegerValue swUserPreferenceIntegerValue_e.swViewWarningMessages, originalWarningSetting
End If
‘ オブジェクトの解放は非常に重要です!
‘ メモリリークやSolidWorksの不安定化を防ぎます。
Set swSelMgr = Nothing
Set swSketchMgr = Nothing
Set swFeat = Nothing
Set swFeatMgr = Nothing
Set swPart = Nothing
Set swModel = Nothing
‘ swAppはアプリケーション全体なので、マクロ終了時に解放はしません
Exit Sub ‘ 正常終了時はエラーハンドラに飛ばない
ErrHandler:
‘ VBAの実行時エラーが発生した場合の処理
MsgBox “致命的なエラーが発生しました!” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“説明: ” & Err.Description & vbCrLf & _
“ソース: ” & Err.Source, vbCritical
GoTo EndSub ‘ クリーンアップ処理へ
End Sub
‘————————————————————
‘ サブプロシージャ:正常なベース押し出しフィーチャを作成
‘————————————————————
Private Sub CreateBaseExtrude()
Dim swSketchMan As SldWorks.SketchManager
Dim swModelDocExt As SldWorks.ModelDocExtension
Dim swMathUtil As SldWorks.MathUtility
Dim swMathPt As SldWorks.MathPoint
Dim vSkLines As Variant
Dim boolStatus As Boolean
Set swModelDocExt = swModel.Extension
Set swSketchMan = swModel.SketchManager
Set swMathUtil = swApp.GetMathUtility
‘ 正面平面を選択してスケッチを開始
boolStatus = swModelDocExt.SelectByID2(“正面”, “PLANE”, 0, 0, 0, False, 0, Nothing, 0)
swSketchMan.InsertSketch True ‘ スケッチを挿入し、自動的にスケッチモードに入る
‘ 四角形を描画
swSketchMan.CreateLine 0, 0, 0, 0.1, 0, 0
swSketchMan.CreateLine 0.1, 0, 0, 0.1, 0.1, 0
swSketchMan.CreateLine 0.1, 0.1, 0, 0, 0.1, 0
swSketchMan.CreateLine 0, 0.1, 0, 0, 0, 0
‘ スケッチを終了
swSketchMan.InsertSketch True
‘ スケッチを選択して押し出しフィーチャを作成
boolStatus = swModelDocExt.SelectByID2(“スケッチ1”, “SKETCH”, 0, 0, 0, False, 0, Nothing, 0)
Dim swExtrudeFeat As SldWorks.Feature
Set swExtrudeFeat = swPart.FeatureManager.FeatureExtrusion3( _
True, False, False, 0, 0, 0.05, 0.005, False, False, False, False, 0, 0, 0, 0, True, True, True, 0, 0, False)
If swExtrudeFeat Is Nothing Then
MsgBox “ベース押し出しフィーチャの作成に失敗しました。”, vbCritical
Exit Sub
End If
swModel.ClearSelection2 True ‘ 選択をクリア
‘ オブジェクトの解放
Set swExtrudeFeat = Nothing
Set swMathUtil = Nothing
Set swSketchMan = Nothing
Set swModelDocExt = Nothing
End Sub
‘————————————————————
‘ サブプロシージャ:意図的にエラーとなる押し出しフィーチャを作成
‘————————————————————
Private Sub CreateErrorExtrude()
Dim swSketchMan As SldWorks.SketchManager
Dim swModelDocExt As SldWorks.ModelDocExtension
Dim swMathUtil As SldWorks.MathUtility
Dim boolStatus As Boolean
Set swModelDocExt = swModel.Extension
Set swSketchMan = swModel.SketchManager
Set swMathUtil = swApp.GetMathUtility
‘ モデルのサーフェス(押し出し面)を選択してスケッチを開始
‘ ここでは「押し出し1」のトップ面を選択すると仮定
‘ しかし、もし「押し出し1」が存在しなかったり、選択する面が不正だったりすると、
‘ この後のスケッチ作成やフィーチャ作成は失敗し、Rebuild Errorの原因となる。
‘ 今回は、適当な面を選択してスケッチを作成し、押し出しを作成するが、
‘ 非常に短い寸法など、Rebuild Errorになりやすい条件で試す。
‘ 押し出し1の上面を選択する
‘ もし名前が「押し出し1」でない、または面がない場合、SelectByID2が失敗する。
boolStatus = swModelDocExt.SelectByID2(“面<1>“, “FACE”, 0, 0, 0.05, False, 0, Nothing, 0)
If Not boolStatus Then
MsgBox “エラーフィーチャ作成のための面選択に失敗しました。この後のフィーチャはエラーになる可能性が高いです。”, vbExclamation
‘ ここではエラーを継続させて、Rebuild Errorの検出をテストします。
‘ エラーメッセージを出すだけで処理を止めずに続行させます。
End If
swSketchMan.InsertSketch True ‘ スケッチを挿入
‘ 中心に小さな円を描画
swSketchMan.CreateCircle 0.05, 0.05, 0, 0.05000001, 0.05000001, 0 ‘ 微妙な値でエラーを誘発
swSketchMan.InsertSketch True ‘ スケッチを終了
‘ スケッチを選択して押し出しフィーチャを作成
boolStatus = swModelDocExt.SelectByID2(“スケッチ2”, “SKETCH”, 0, 0, 0, False, 0, Nothing, 0)
Dim swExtrudeFeat As SldWorks.Feature
Set swExtrudeFeat = swPart.FeatureManager.FeatureExtrusion3( _
True, False, False, 0, 0, 0.000001, 0.000001, False, False, False, False, 0, 0, 0, 0, True, True, True, 0, 0, False)
‘ 押し出し量を極端に小さくして、ジオメトリエラーを誘発しやすくする
If swExtrudeFeat Is Nothing Then
MsgBox “エラーとなる押し出しフィーチャの作成API呼び出しは成功しましたが、実際にはフィーチャツリーにエラーとして表示される可能性があります。”, vbInformation
‘ API自体は成功を返しても、リビルドでエラーになることはよくあります。
End If
swModel.ClearSelection2 True
‘ オブジェクトの解放
Set swExtrudeFeat = Nothing
Set swMathUtil = Nothing
Set swSketchMan = Nothing
Set swModelDocExt = Nothing
End Sub
このコードを実行すると、「リビルド中にエラーが発生しました」というメッセージの後に、「エラーフィーチャ発見!名前: 押し出し2、タイプ: Extrude」というメッセージが表示されるはずです。これで、どのフィーチャがエラーの原因なのかを明確に特定できましたね!
—
【本質】「Selection Mark Error」をどう捉えるか?
「Selection Mark Error」は、特定のフィーチャを作成または編集する際に、必要な参照ジオメトリ(エッジ、面、頂点など)が正しく選択されていない、または選択が失われた場合に発生することが多いです。これもRebuild Errorの一種として現れることがほとんどです。
例えば、「穴ウィザードで穴を作成しようとしたが、穴を配置する面が選択されていない」といった状況です。
選択APIの戻り値と `SelectionMgr` で事前チェック
この種のエラーを防ぐ(または早期に検出する)ためには、選択を行うAPIの戻り値を常にチェックすること、そして`SelectionMgr`オブジェクトを使用して現在の選択状態を能動的に確認することが重要です。
- `ModelDocExtension.SelectByID2` / `SelectByID` / `SelectByPoint` の戻り値: これらのメソッドは、選択に成功すれば `True` を、失敗すれば `False` を返します。`False` が返された場合、その後の操作は高確率で失敗します。
- `SelectionMgr.GetSelectedObject6` / `GetSelectedObjects2`: 現在選択されているオブジェクトを取得するためのメソッドです。これらのメソッドが `Nothing` を返したり、期待するオブジェクトと異なるものを返したりした場合、選択状態が不正であると判断できます。
例:選択失敗を事前に検出する
Dim swModel As SldWorks.ModelDoc2
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then Exit Sub
Dim swModelDocExt As SldWorks.ModelDocExtension
Set swModelDocExt = swModel.Extension
Dim boolStatus As Boolean
‘ 存在しない名前の平面を選択しようと試みる
boolStatus = swModelDocExt.SelectByID2(“存在しない平面”, “PLANE”, 0, 0, 0, False, 0, Nothing, 0)
If Not boolStatus Then
MsgBox “指定された平面の選択に失敗しました!この後の操作はエラーになる可能性があります。”, vbExclamation
‘ ここで処理を中断するか、代替処理を行う
Else
MsgBox “平面の選択に成功しました。”, vbInformation
End If
swModel.ClearSelection2 True ‘ 選択をクリア
このように、選択の段階でエラーを検出できれば、その後の複雑なフィーチャ作成処理に進む前に問題を特定し、より分かりやすいエラーメッセージをユーザーに提示できます。
そして、もし選択が失敗したにも関わらず処理を続行し、それが原因でRebuild Errorが発生したとしても、先ほど紹介した`Feature.Error` プロパティの走査によって、最終的にどのフィーチャがエラーになったかを特定できるのです。まさに二段構えの堅牢な設計ですね!
—
堅牢なエラーハンドリングテンプレートの構築
これまでの知見を統合し、実務で使える堅牢なエラーハンドリングテンプレートを構築しましょう。
テンプレートのポイント
1. `On Error GoTo` によるVBA実行時エラーの捕捉: これは基本中の基本です。
2. `SldWorks.SetUserPreferenceIntegerValue` による警告メッセージの抑制: SolidWorksが自動で出すポップアップは、マクロの自動実行を妨げる可能性があります。一時的に抑制し、マクロ自身でエラーを処理するようにします。ただし、元の設定に戻すことを絶対に忘れないでください!
3. APIの戻り値チェック: `Boolean` や `Long` を返すAPIは、必ずその戻り値を確認します。
4. `ModelDoc2.EditRebuild3` の戻り値チェック: リビルドエラーが発生したか否かを判断します。
5. `Feature.Error` プロパティの走査: リビルドエラーが発生した場合、どのフィーチャが原因かを特定する「宝の地図」です。
6. `SelectionMgr` を使った選択状態の確認: Selection Mark Errorを未然に防ぎ、早期に検出します。
7. 徹底したオブジェクトの解放: マクロ終了時、または不要になった時点で `Set obj = Nothing` を実行し、メモリリークやSolidWorksの不安定化を防ぎます。
8. 詳細なログ出力: 大規模なマクロでは、`MsgBox` だけでなく、エラーの詳細をテキストファイルに書き出すロギング機能を追加すると、デバッグが格段に楽になります。
上記の`SolidWorksRebuildErrorHandler`サブルーチンは、このテンプレートの多くの要素を既に含んでいます。
—
ベテランの知恵:パフォーマンスとオブジェクト管理
最後に、伝説的なチーフアーキテクトならではの、もう一歩踏み込んだアドバイスをお伝えします。
オブジェクトの解放は「聖なる儀式」
VBAでは、`Dim` で宣言したオブジェクト変数は、プロシージャの終了時に自動的に解放されるのが一般的です。しかし、SolidWorks APIオブジェクトはCOMオブジェクトであり、VBAのガベージコレクションだけでは完全に解放されない、または解放タイミングが遅れることがあります。
これが原因で、SolidWorksが不安定になったり、メモリリークが発生して動作が重くなったりする場合があります。特にループ内で大量のオブジェクトを生成・参照する場合や、複雑なドキュメント操作を行う場合は顕著です。
ですから、使用し終わったSolidWorks APIオブジェクト(`Feature`、`Sketch`、`ModelDoc2`など)は、必ず`Set obj = Nothing`として明示的に解放する習慣をつけましょう。これはマクロの安定性とSolidWorks全体のパフォーマンスを保つための「聖なる儀式」だと思ってください。
`EditRebuild3` の呼び出しタイミング
`ModelDoc2.EditRebuild3` は、モデル全体を再計算する非常に重い処理です。フィーチャを一つ作成するたびにこのメソッドを呼んでいると、マクロの実行速度が著しく低下します。
複数のフィーチャを連続して作成・編集する場合は、すべての操作が完了した後、最後に一度だけ`EditRebuild3`を呼び出すのがベストプラクティスです。これにより、リビルドの回数を最小限に抑え、マクロの実行時間を短縮できます。
ただし、リビルドしないと次の操作に必要なジオメトリが生成されない、といった依存関係がある場合は、必要なタイミングで呼び出す必要があります。このバランスを見極めるのが、経験を積んだエンジニアの腕の見せ所です。
—
まとめ:エラーは成長の糧
SolidWorks VBAのエラーハンドリングは、確かに奥深く、時には複雑に感じるかもしれません。しかし、今回学んだ`Feature.Error`プロパティの活用や、`SelectionMgr`による事前チェック、そして堅牢なテンプレートの構築によって、皆さんのマクロは格段に信頼性を増し、開発効率も向上するはずです。
エラーは決して敵ではありません。それは、私たちのコードが「現実のSolidWorks」と対話し、そこから学んでいる証拠です。適切にエラーをハンドリングし、そのメッセージから真の原因を読み解くことで、皆さんのSolidWorks VBAスキルは間違いなく一段上のレベルへと到達します。
さあ、恐れることなく、エラーを味方につけて、より素晴らしいSolidWorks自動化の世界を切り拓いていきましょう!
—
