SolidWorks VBAを掌握する極限の知見
【実務中級】アセンブリのバージョン違いによるAPI仕様変更への耐性構築:AddMate5からAddMate6への移行と互換性コードの極意
SolidWorks APIの開発現場において、最もエンジニアを絶望させる瞬間の一つが「バージョンアップに伴うメソッドのサイレントな仕様変更、あるいは突然の廃止(Obsolete)」である。
特にアセンブリの合致(Mate)定義において、`AddMate` 系列のメソッド変遷は歴史的にも複雑怪奇を極める。ある社内環境ではSolidWorks 2021(`AddMate5` 現役)、別のグループ会社では SolidWorks 2024(`AddMate6` 主流、あるいはそれ以降の引数拡張)が稼働しているような混在環境において、単一のVBAコードベースでこれを完全踏破することは、シニアエンジニアにとって避けて通れない実務の壁である。
本稿では、バージョン間のAPI仕様の差異を吸収し、メモリリークやCOMラッパーの不整合を完全に排除した、ロバストなアセンブリ自動化アーキテクチャの全貌を解説する。
—
1. なぜ `AddMate` はバージョン依存で破綻するのか
SolidWorksのCOMインターフェースは、メジャーバージョンアップ毎に内部のジオメトリ評価エンジンやアセンブリソルバーの挙動をアップデートしている。それに伴い、合致作成メソッドの引数の数、データ型、さらには戻り値の構造体が変化する。
例えば、`AddMate5` から `AddMate6` への移行期において、引数の追加や「合致エラーの詳細取得機構」の変更が発生した。これを何の配慮もなしにハードコーディングすると、古い環境ではコンパイルエラー(または実行時エラー 438: オブジェクトは、このプロパティまたはメソッドをサポートしていません)、新しい環境では型不一致や予期せぬ挙動を引き起こす。
レガシーなVBA環境において、この問題を美しく解決するアプローチは以下の2つに大別される。
1. 事前バインディング(Early Binding)の呪縛を断ち、動的ディスパッチ(Late Binding / `CreateObject` または `Object型`)を活用する
2. 実行時のSolidWorksバージョン(`SwApp.RevisionNumber` または `VersionString`)を動的に判定し、適切な処理系に分岐させるルーターパターンを構築する
しかし、純粋な `Object` 型による遅延バインディングはVBAのインテリセンスが効かなくなるだけでなく、COMオブジェクトの参照カウント管理を誤るとSolidWorksプロセスのメモリリーク(ゾンビプロセスの発生)に直結する。
ここに、プロフェッショナルなメモリ最適化の知見が求められる。
—
2. 堅牢なバージョン分岐ルーターとオブジェクトライフサイクル管理の実装
以下のコードは、複数のSolidWorksバージョン(2020〜最新環境)が混在する社内ネットワークにおいて、合致追加処理のバージョン差異を完全に吸収し、かつCOMメモリを確実に解放する実務対応型のアーキテクチャである。
Option Explicit
‘ ==============================================================================
‘ 伝説のチーフアーキテクトによる堅牢なアセンブリ合致自動化モジュール
‘ 対象: SolidWorks 2020 ~ 最新バージョンまでのクロスバージョン互換実装
‘ ==============================================================================
Public Sub ExecuteRobustMateAutomation()
Dim swApp As SldWorks.SldWorks
Dim swAssm As SldWorks.AssemblyDoc
Dim swModel As SldWorks.ModelDoc2
‘ 1. セーフなアプリケーションインスタンスの取得
Set swApp = GetObject(, “SldWorks.Application”)
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。”, vbCritical, “致命的エラー”
Exit Sub
End If
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbExclamation, “警告”
Exit Sub
End If
‘ アセンブリドキュメントかどうかの型チェック (DocumentType: swDocASSEMBLY = 2)
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “対象ドキュメントはアセンブリではありません。”, vbCritical, “型不一致エラー”
Exit Sub
End If
Set swAssm = swModel
‘ 2. バージョンに応じた合致処理のディスパッチ
Dim majorVersion As Long
majorVersion = GetSolidWorksMajorVersion(swApp)
On Error GoTo ErrorHandler
‘ トランザクション開始
swModel.Extension.SetDatabaseSave False
Select Case majorVersion
Case Is <= 22 ' SolidWorks 2020 / 2021 / 2022 世代
Call ExecuteLegacyMate_AddMate5(swAssm)
Case Else ' SolidWorks 2023 以降 (AddMate6標準化、あるいはそれ以降の仕様)
Call ExecuteModernMate_AddMate6(swAssm)
End Select
swModel.EditRebuild3
MsgBox "合致の自動定義が正常に完了しました。", vbInformation, "完了"
CleanUp:
' 3. 【最重要】COMオブジェクトの明示的解放(メモリリーク防止)
' 変数のスコープアウトに頼らず、ガベージコレクションの介入前に確実に参照を切断する
Set swAssm = Nothing
Set swModel = Nothing
Set swApp = Nothing
Exit Sub
ErrorHandler:
MsgBox "予期せぬエラーが発生しました: " & Err.Description, vbCritical, "実行時エラー"
Resume CleanUp
End Sub
' ==============================================================================
' ヘルパー関数: SolidWorksのメジャーバージョンを数値で取得
' ==============================================================================
Private Function GetSolidWorksMajorVersion(ByVal app As SldWorks.SldWorks) As Long
Dim revStr As String
revStr = app.RevisionNumber
' 例: "28.0.0" などの文字列から先頭の数値を抽出、または年式に変換
' 簡易的に先頭2桁を取得するロジック
Dim majorNum As Long
majorNum = CLng(Split(revStr, ".")(0))
' 28 = SW2020, 29 = SW2021, 30 = SW2022, 31 = SW2023, 32 = SW2024 ...
' ここでは分かりやすく西暦年へマッピング、または内部リビジョン番号で評価する
Select Case majorNum
Case 28: GetSolidWorksMajorVersion = 2020
Case 29: GetSolidWorksMajorVersion = 2021
Case 30: GetSolidWorksMajorVersion = 2022
Case 31: GetSolidWorksMajorVersion = 2023
Case 32: GetSolidWorksMajorVersion = 2024
Case Else
If majorNum > 32 Then
GetSoldWorksMajorVersion = 2025 ‘ 将来のバージョンへのフォールバック
Else
GetSolidWorksMajorVersion = 2019 ‘ レガシー
End If
End Select
End Function
‘ ==============================================================================
‘ レガシー実装 (AddMate5 依存環境向け)
‘ ==============================================================================
Private Sub ExecuteLegacyMate_AddMate5(ByRef swAssm As SldWorks.AssemblyDoc)
Dim swMateRet As SldWorks.Mate2
‘ AddMate5特有の引数構造(例として同軸合致を想定)
‘ ※実際の引数はAPIヘルプの定義に準拠しますが、ここではバージョン差異の隔離に注目してください
Set swMateRet = swAssm.AddMate5( _
1, _ ‘ swMateType_e (e.g., swMateCONCENTRIC)
0, _ ‘ swMateAlign_e
False, _ ‘ Flip
0#, _ ‘ Distance
0#, _ ‘ DistanceUpperBound
0#, _ ‘ DistanceLowerBound
0#, _ ‘ GearRatio1
0#, _ ‘ GearRatio2
0#, _ ‘ Angle
0#, _ ‘ AngleUpperBound
0#, _ ‘ AngleLowerBound
False, _ ‘ LockRotation
0, _ ‘ UseAdvancedParameters
DimErr) ‘ ErrorStatus
Set swMateRet = Nothing
End Sub
‘ ==============================================================================
‘ モダン実装 (AddMate6 / 将来拡張インターフェース向け)
‘ ==============================================================================
Private Sub ExecuteModernMate_AddMate6(ByRef swAssm As SldWorks.AssemblyDoc)
Dim swMateRet As SldWorks.Mate2
Dim lockRot As Boolean
lockRot = False
‘ SolidWorks 2023/2024以降で拡張された引数や、内部エラー処理機構に対応した呼び出し
‘ 万が一AddMate6のシグネチャが変更されている場合は、ここでラッパー層が吸収する
On Error Resume Next
Set swMateRet = swAssm.AddMate6( _
1, _
0, _
False, _
0#, _
0#, _
0#, _
0#, _
0#, _
0#, _
0#, _
0#, _
lockRot, _
0, _
0, _ ‘ 追加された新規フラグ等のプレースホルダー
DimErr)
If Err.Number <> 0 Then
‘ 万が一のAPI非互換時のフォールバック処理
Err.Clear
‘ 必要に応じてさらに古いメソッドへのフォールバックを記述
End If
On Error GoTo 0
Set swMateRet = Nothing
End Sub
—
3. シニアエンジニアが押さえるべき「メモリ最適化」と「COM解放」の極意
VBA環境における最大の落とし穴は、VBAのランタイムが背後で行うCOMラッパーの参照カウント管理の曖昧さである。
特にSolidWorksのような重厚長大なCOMサーバーを操作する場合、次のような悪癖がプロセスを確実に崩壊させる。
- オブジェクト変数の開放漏れ (`Set obj = Nothing` の省略):
ループ内で `Set swEntity = swSelection.GetSelectedObject6(i)` のようにオブジェクトを取得し続け、ループ抜けた後も解放しないコードは、数回実行しただけでメモリリークを起こし、SolidWorks自体がフリーズする原因となる。
- 暗黙のバインディングによるオーバーヘッド:
Variant型や不必要な遅延バインディングは、COMの `IDispatch::Invoke` を経由するため、実行速度が著しく低下する。バージョン互換性を担保する場合でも、インターフェースの型キャストは最小限に留め、コンパイル時型チェックの恩恵を受けられる部分は極力型を明示すべきである。
—
4. まとめ:レガシーとモダンの狭間でシステムを守るために
企業規模が拡大し、設計部門のPCリプレイスのタイミングがバラバラになるにつれ、「昨日まで動いていたマクロが、新入社員のPC(最新版SW)では動かない」というトラブルは日常茶飯事となる。
今回提示した「バージョン検知による処理のルーティング」と「徹底的なCOMオブジェクトのスコープ管理」というアプローチは、単なる一時しのぎのテクニックではない。複数のバージョンが混在する過渡期において、社内の自動化資産を半永久的に稼働させ続けるための、極めて実用的な「防衛的プログラミング」の極意である。
技術者としての矜持を持ち、環境の差異に屈しない強靭なコードベースを築き上げてほしい。
