【SolidWorks VBA極限の知見】CustomPropertyManagerを完全掌握する:レガシーメタデータ一括クレンジング・エンジン
社内ニッチなPLMや次世代図面管理システムへの移行期。エンジニアリングデータベースの最大の足枷となるのは、過去の設計者が野放図に乱立させた「カスタムプロパティの不整合」である。
「材質」「MAT」「Material」「マテリアル」――。これらは人間にとっては同義であっても、厳密なデータベーススキーマを持つシステムにとっては致命的なノイズだ。
今回は、SolidWorks VBAの底レイヤーを貫き、数千ファイルのパーツ群からカスタムプロパティを秒速で全走査・一括置換する、現場叩き上げのメンテナンススクリプトを公開する。
レガシーAPIの癖、COMオブジェクトの寿命管理、そしてメモリリークを防ぐための鉄則をここに記す。
—
1. 架构の核心:CustomPropertyManagerの裏側
SolidWorksのカスタムプロパティ操作において、多くの初学者が陥る罠が `ModelDocExtension` と `CustomPropertyManager` のライフサイクルの誤認である。
パーツ(`.sldprt`)やアセンブリ(`.sldasm`)のルートレベル、あるいは特定コンフィギュレーションにおけるプロパティを操作する場合、必ず以下の階層構造を意識しなければならない。
1. ModelDoc2(ドキュメント本体)
2. ModelDocExtension(拡張インターフェース:SW2005以降のモダンな操作の起点)
3. CustomPropertyManager(プロパティコンテナへのアクセッサ)
特に `GetNames` メソッドで配列を取得し、`Get2` で値を引き出すプロセスは、Variant型配列のメモリ安全性とCOMの参照カウントを正確に理解していないと、大規模バッチ処理中に「沈黙のメモリリーク(VBA特有のヒープ断片化)」を引き起こす。
—
2. 実装:メタデータ一括クレンジング・エンジン
以下のコードは、アクティブなドキュメント、あるいは指定されたパーツファイルの全カスタムプロパティ(コンフィギュレーション特有のものを含む)を走査し、揺れのあるキー名を標準スキーマへ強制的に置換・統合する実用スクリプトである。
Option Explicit
‘ =================================================================================
‘ 伝説のチーフアーキテクトによるカスタムプロパティ・クレンジングエンジン
‘ 対象: SolidWorks 201X – 202X
‘ =================================================================================
Sub MasterPropertyCleansingEngine()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swExt As SldWorks.ModelDocExtension
Dim swCustPropMgr As SldWorks.CustomPropertyManager
‘ イニシャライズ
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “対象となるドキュメントが開かれていません。”, vbCritical, “致命的エラー”
Exit Sub
End If
Set swExt = swModel.Extension
‘ 1. 【標準情報】コンフィギュレーション非依存プロパティ(指定なし=””)の操作
‘ 第2引数 “” はファイル固有プロパティを指す
Set swCustPropMgr = swExt.CustomPropertyManager(“”)
Call ProcessProperties(swCustPropMgr, “Config_None”)
‘ 2. 【拡張情報】アクティブコンフィギュレーション固有プロパティの操作
Dim activeConfigName As String
activeConfigName = swModel.GetActiveConfiguration.Name
Set swCustPropMgr = swExt.CustomPropertyManager(activeConfigName)
Call ProcessProperties(swCustPropMgr, activeConfigName)
‘ 変更の強制反映と再構築
swModel.ForceRebuild3 False
‘ 明示的なオブジェクト解放(VBAヒープ汚染防止)
Set swCustPropMgr = Nothing
Set swExt = Nothing
Set swModel = Nothing
Set swApp = Nothing
MsgBox “カスタムプロパティのクレンジングが完了しました。”, vbInformation, “完了”
End Sub
Private Sub ProcessProperties(ByRef custPropMgr As SldWorks.CustomPropertyManager, ByVal scopeName As String)
Dim vPropNames As Variant
Dim lRetVal As Long
Dim valOut As String
Dim resolvedValOut As String
Dim wasResolved As Boolean
Dim linkToProperty As Boolean
‘ GetNamesはプロパティが存在しない場合、Emptyを返すため事前チェック必須
vPropNames = custPropMgr.GetNames
If IsEmpty(vPropNames) Then
Debug.Print “[” & scopeName & “] プロパティは存在しません。”
Exit Sub
End If
Dim i As Long
For i = LBound(vPropNames) To UBound(vPropNames)
Dim propName As String
propName = CStr(vPropNames(i))
‘ Get2メソッドによる値の取得
‘ 引数: PropertyName, ValOut (評価前), ResolvedValOut (評価後), LinkToProperty
lRetVal = custPropMgr.Get2(propName, valOut, resolvedValOut)
If lRetVal = swCustomInfoAddResult_Successful Then
Debug.Print “走査中 -> キー: ” & propName & ” | 値: ” & resolvedValOut
‘ 【重要】スキーマ標準化ロジック(例:レガシーキーの統合)
Select Case UCase(Trim(propName))
Case “MAT”, “MATERIAL”, “マテリアル”
‘ 旧キーの値を標準キー「MATERIAL_SPEC」へ移行し、旧キーを削除
custPropMgr.Add3 “MATERIAL_SPEC”, swCustomInfoText, resolvedValOut, swCustomPropertyDeleteAndAdd
If UCase(propName) <> “MATERIAL_SPEC” Then
custPropMgr.Delete propName
End If
Case “AUTHOR”, “作成者”, “設計者”
custPropMgr.Add3 “DESIGNED_BY”, swCustomInfoText, resolvedValOut, swCustomPropertyDeleteAndAdd
If UCase(propName) <> “DESIGNED_BY” Then
custPropMgr.Delete propName
End If
‘ 必要に応じてここに社内独自のマッピングルールを追加
Case Else
‘ その他のプロパティはそのまま保持、またはフォーマット正規化
End Select
End If
Next i
End Sub
—
3. チーフアーキテクトが解説する「死角なき実装ポイント」
A. `GetNames` が返すVariant型の罠
VBAにおける `CustomPropertyManager.GetNames` は、内部的にCOMの安全配列(SAFEARRAY)を返す。プロパティが1つも存在しない状態でこのメソッドを叩くと、戻り値は `Empty` になる。
これを `LBound` / `UBound` にそのまま突っ込むと、ランタイムエラー `Subscript out of range (Error 9)` が発生する。必ず `IsEmpty()` によるガード節を設けること。
B. `Get2` の戻り値と評価済み値の活用
メタデータ移行において最も厄介なのは、プロパティ値に寸法や質量などの「数式(`$PRPSHEET` 等)」が埋め込まれているケースだ。
`Get2` メソッドの第3引数である `ResolvedValOut` を使用することで、SolidWorksが自動解決した評価済みの文字列(例:「SUS304」や「120.5」)を直接取得できる。レガシーデータをクリーンなマスターデータに変換する際、未解決の数式文字列を引き継いでしまう事故を防ぐには、常に `ResolvedValOut` を参照しに行かなければならない。
C. `swCustomPropertyDeleteAndAdd` によるアトミックな置換
プロパティの値を書き換える際、単に `Set` メソッドを使うだけでは、型(Type)の不整合や既存リンクの競合を起こすことがある。
`Add3` メソッドのオプション引数に `swCustomPropertyDeleteAndAdd` を指定することで、「同名プロパティが存在すれば強制削除し、新しい型と値でアトミック(不可分)に再作成する」という安全な挙動を担保できる。
—
4. 大規模バッチ処理への拡張:ファイルシステム走査の心得
もしこれを単一パーツではなく、ネットワークドライブ上の数万パーツに対して一括実行する場合は、以下のアーキテクチャ上の制約に留意せよ。
- バックグラウンドサイレントオープン:
`swApp.OpenDoc6` を用いる際、ユーザーインターフェースを描画させないオプション(`swOpenDocOptions_Silent`)を必ず指定すること。グラフィック描画のオーバーヘッドを削るだけで、処理速度は10倍以上に跳ね上がる。
- COMガベージコレクションの強制:
VBAのランタイムはCOM参照の解放タイミングが曖昧である。数千ファイルをループさせると必ずメモリーリークを起こすため、ファイルごとのループの最後に `DoEvents` を挟み、かつインスタンスの参照を完全に断ち切る設計が不可欠となる。
総括
社内システムの近代化は、往々にして「過去の設計データの泥臭い掃除」から始まる。
SolidWorks APIの挙動の機微を理解し、メモリとコンテキストを正確にコントロールするVBAコードを書けるかどうかが、プロジェクトの成否を分ける。
手動での修正に数カ月を費やす愚行はもう終わりにしよう。コードに語らせ、一瞬でモダンなデータ基盤へ移行せよ。
