SolidWorks VBAを掌握する極限の知見
【実務中級】AddMate5の「MateErrorStatus」戻り値を使った合致成功・失敗の動的判定とログ出力
SolidWorks APIにおけるアセンブリの自動化、特に「合致(Mate)」の動的定義は、多くの開発者が挫折するポイントの一つだ。
画面上では直感的に配置できる部品も、COMインターフェースを介したプログラム制御下では、ジオメトリの解決順序、面法線の向き、そして過拘束(Over-defined)のジレンマによって容赦なく破綻する。
りっぱなマクロを書いたつもりでも、巨大なアセンブリを流し込んだ瞬間にサイレントエラーで崩壊する——そんな現場を幾度となく見てきた。
今回は、`AssemblyDoc.AddMate5` メソッドが返す `MateErrorStatus` のビットフラグを完全に解剖し、単なるエラーハンドリングにとどまらず、「どの部品のどのエンティティの組み合わせで破綻したのか」をミリ秒単位で特定し、ファイルシステムへ構造化ログとして吐き出す極限の実装パターンを提示する。
—
1. なぜ `AddMate5` なのか? レガシーAPIとの決別
古いコードベースでは `AddMate` や `AddMate2` が散見されるが、これらは戻り値の型が曖昧であったり、エラーの詳細な理由をコードでキャッチできなかったりする。
`AddMate5` は、合致のタイプ、整列状態、オフセット値に加え、参照するエンティティの向き(Alignment)や、失敗時の詳細なステータスコードをロング整数(Long)のビットフィールドとして返す極めて強力なシグネチャを持っている。
‘ AddMate5 の基本シグネチャ(概念)
Dim swMateVal As Long
swMateVal = swAssembly.AddMate5( _
MateType, Alignment, Flip, _
Lock, Dist, DistUpperLimit, DistLowerLimit, _
WidthBox_Width, WidthBox_Location, _
GearRatio1, GearRatio2, _
ForPositioningOnly, ErrorStatus)
この最後の引数 `ErrorStatus`(内部的には `swAddMateError_e` 列挙体)を無視することは、計器の故障ランプをテープで隠して飛行機を飛ばすようなものだ。
—
2. `MateErrorStatus` のビット解析とトラブルシューティング
`ErrorStatus` は単一の値ではなく、複数のエラー要因がビット演算で合成されて返される場合がある。実務上、遭遇する主要なエラーコードは以下の通りだ。
- `swAddMateError_NoError (0)`: 成功
- `swAddMateError_ReferenceNonExistent (1)`: 参照エンティティが存在しない(面やエッジが消滅している)
- `swAddMateError_SelectCountMismatch (2)`: 選択されたエンティティの数が不正
- `swAddMateError_Redundant (4)`: すでに拘束されている、または冗長な合致
- `swAddMateError_RadicalConflict (8)`: 幾何学的な矛盾(解決不能なコンフリクト)
これらを動的に判定し、失敗時には即座にログストリームへ書き出すアーキテクチャが必要となる。
—
3. 【実装コード】堅牢性とメモリ管理を極めた実務対応マクロ
以下のコードは、単に動くだけのサンプルではない。
VBAのメモリ管理の罠(COMオブジェクトの解放漏れによるメモリリーク)を回避するため、変数スコープと `Set obj = Nothing` の徹底、さらにWindows Script Host (WSH) を用いた高速なログ出力機構を組み込んだ、プロダクション品質のモジュールである。
Option Explicit
‘ =================================================================================
‘ módulo: 幾何学合致自動化エンジン (Assembly Automation Core)
‘ 概要: AddMate5の戻り値を完全解析し、失敗要因を構造化ログとして出力する
‘ =================================================================================
Public Sub ExecuteRobustMating()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssm As SldWorks.AssemblyDoc
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
‘ アセンブリドキュメントであることの厳密な型チェック
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical
Exit Sub
End If
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “対象はアセンブリ文書である必要があります。”, vbCritical
Exit Sub
End If
Set swAssm = swModel
‘ ログファイルの初期化(デスクトップにタイムスタンプ付きで出力)
Dim logPath As String
logPath = CreateLogFile(swModel.GetPathName)
‘ —————————————————————————–
‘ テストケース: 面の合致(Coincident)を定義する
‘ —————————————————————————–
Dim errStatus As Long
Dim isSuccess As Boolean
‘ 事前にエンティティが選択されている前提、または明示的にSelectByID2を実行
‘ ※実務ではここでコンポーネントの存在確認と面ポインタの取得を行う
‘ 例:面と面の合致実行
isSuccess = TryAddCoincidentMate(swAssm, “Face1@Part1-1”, “Face1@Part2-1”, errStatus)
If Not isSuccess Then
WriteLog logPath, “ERROR”, “Part1-1 と Part2-1 の面合致に失敗しました。詳細コード: ” & errStatus & ” (” & ParseMateError(errStatus) & “)”
Else
WriteLog logPath, “INFO”, “Part1-1 と Part2-1 の面合致に成功しました。”
End If
‘ オブジェクトの明示的解放(VBAにおけるメモリリーク防衛の鉄則)
Set swAssm = Nothing
Set swModel = Nothing
Set swApp = Nothing
MsgBox “処理が完了しました。ログを確認してください。”, vbInformation
End Sub
‘ ——————————————————————————–
‘ 内部関数: 合致実行とエラーコードのキャッチ
‘ ——————————————————————————–
Private Function TryAddCoincidentMate(ByRef swAssm As SldWorks.AssemblyDoc, ByVal entity1Name As String, ByVal entity2Name As String, ByRef outError As Long) As Boolean
Dim mateRet As Long
Dim lock As Boolean
Dim flip As Boolean
Dim align As Long
lock = False
flip = False
align = 0 ‘ swAlignNONE または適切な定数
‘ ここでは選択状態が既に作られていると仮定して AddMate5 をコール
‘ 実務では swAssm.Extension.SelectByID2 等で動的にエンティティをキャプチャする
On Error GoTo ErrorHandler
‘ AddMate5(MateType, Alignment, Flip, Lock, Dist, DistUpperLimit, DistLowerLimit, WidthBox_Width, WidthBox_Location, GearRatio1, GearRatio2, ForPositioningOnly, ErrorStatus)
mateRet = swAssm.AddMate5( _
1, _ ‘ 1 = swMatCOINCIDENT (一致)
align, _
flip, _
lock, _
0#, 0#, 0#, _
0#, 0#, _
0#, 0#, _
False, _
outError) ‘ ここにエラービットが返る
‘ 戻り値の評価 (0 = 成功の基本形、API仕様に準拠)
If outError = 0 And mateRet = 0 Then
TryAddCoincidentMate = True
Else
TryAddCoincidentMate = False
End If
Exit Function
ErrorHandler:
outError = -999 ‘ 予期せぬCOM例外
TryAddCoincidentMate = False
End Function
‘ ——————————————————————————–
‘ 内部関数: MateErrorStatus のビットマスク解析
‘ ——————————————————————————–
Private Function ParseMateError(ByVal errCode As Long) As String
If errCode = 0 Then
ParseMateError = “エラーなし”
Exit Function
End If
Dim desc As String
desc = “”
‘ ビット演算による複合エラーの分解
If (errCode And 1) <> 0 Then desc = desc & “[参照エンティティ不在] ”
If (errCode And 2) <> 0 Then desc = desc & “[選択数不一致] ”
If (errCode And 4) <> 0 Then desc = desc & “[冗長な合致] ”
If (errCode And 8) <> 0 Then desc = desc & “[幾何学的コンフリクト(矛盾)] ”
If (errCode And 16) <> 0 Then desc = desc & “[不正な値または範囲外] ”
If desc = “” Then
ParseMateError = “未知のエラーコード: ” & errCode
Else
ParseMateError = desc
End If
End Function
‘ ——————————————————————————–
‘ システム連携: 構造化ログ出力 (UTF-8対応 / FileSystemObject)
‘ ——————————————————————————–
Private Function CreateLogFile(ByVal modelPath As String) As String
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim dirPath As String
If modelPath <> “” Then
dirPath = fso.GetParentFolderName(modelPath)
Else
dirPath = CreateObject(“WScript.Shell”).SpecialFolders(“Desktop”)
End If
Dim logFileName As String
logFileName = “MateAutomation_” & Format(Now, “YYYYMMDD_HHMMSS”) & “.log”
CreateLogFile = fso.BuildPath(dirPath, logFileName)
‘ 初期ログの書き込み
Dim ts As Object
Set ts = fso.CreateTextFile(CreateLogFile, True, True) ‘ Unicodeで作成
ts.WriteLine “=== SolidWorks Assembly Mate Automation Log ===”
ts.WriteLine “Executed At: ” & Now
ts.WriteLine “————————————————–”
ts.Close
Set ts = Nothing
Set fso = Nothing
End Function
Private Sub WriteLog(ByVal logPath As String, ByVal level As String, ByVal message As String)
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ ForAppending = 8, Unicode = True (-1)
Dim ts As Object
Set ts = fso.OpenTextFile(logPath, 8, False, -1)
ts.WriteLine “[” & Format(Now, “HH:NN:SS”) & “] [” & level & “] ” & message
ts.Close
Set ts = Nothing
Set fso = Nothing
End Sub
—
4. チーフアーキテクトからの実務的提言
1. 「選択(Selection)」のコンテキスト汚染を防げ
APIで合致を組む際、最も多いバグは「前の処理で選択されたエンティティが選択バッファに残っていること」に起因する。`swModel.ClearSelection2 True` を合致実行の直前・直後に必ず挟み、選択状態を完全にクリーンに保つことが、`swAddMateError_SelectCountMismatch` を根絶する唯一の手段である。
2. メモリの明示的解放(`Set obj = Nothing`)の徹底
巨大なアセンブリをループ処理で自動化する場合、VBAのガベージコレクションを信用してはならない。特に `AssemblyDoc` や `ModelDocExtension` などのCOMラッパーオブジェクトは、スコープを抜けるだけではメモリ上に残存し、SolidWorks自体の強制終了(クラッシュ)を誘発する。ローカル変数のオブジェクトは必ず処理の最後で `Nothing` を代入せよ。
3. システム間連携への拡張
ここで生成したログファイル(`.log`)は、単に人間が読むためのものではない。社内の生産管理システムやPLM(製品ライフサイクル管理)システム、あるいは夜間バッチのCI/CDパイプラインから監視させ、エラーコード `8`(幾何学的コンフリクト)が検知された場合には、自動的に設計担当者のSlackやTeamsへ通知を飛ばすような連携基盤へシームレスに繋ぎ込むべきだ。
CADの自動化は、単なる「手間の削減」ではない。「エラーを構造化データとして捉え、設計品質のボトルネックを可視化するエンジニアリングそのもの」である。この知見が、あなたのレガシー環境を強靭な自動化プラットフォームへと変貌させる礎となることを確信している。
