SolidWorks VBAを掌握する極限の知見
【カスタムプロパティの高度なメタデータ管理】CustomPropertyManager.GetNamesとDelete2によるクレンジング自動化
レガシーな3D CAD運用において、最も見過ごされ、かつ確実に生産性を蝕む癌(がん)がある。
それが「カスタムプロパティの腐敗」だ。
設計変更の嵐、担当者の交代、急場しのぎの外部連携マクロの乱立。これらが何年も積み重なった結果、現場の図面やモデルには、以下のような「ゴミデータ」が無限に肥大化していく。
- 使われなくなった旧システムの管理コード(`Old_Part_No` など)
- タイポや大文字小文字の揺れによるゾンビプロパティ(`material` と `Material` と `MAT` の共存)
- 外部連携用の一時的なフラグの残骸
このメタデータの汚染は、PDM(Product Data Management)連携の失敗、BOM(部品表)出力の致命的なバグ、そして検索性の低下によるエンジニアの認知負荷増大を引き起こす。
今回は、SolidWorks APIの `CustomPropertyManager` を極限まで使い倒し、蓄積されたゴミデータを全自動でスキャン・浄化(クレンジング)し、命名規則を強制統一する「データガバナンス・クレンジングエンジン」の全貌を解説する。
—
1. アーキテクチャの核心:なぜ標準機能ではクレンジングできないのか?
SolidWorksの標準UI(プロパティタブビルダーやファイルプロパティダイアログ)は、あくまで「人間が個別に対象を触る」ためのインターフェースに過ぎない。数千、数万点におよぶレガシーアセンブリのツリー構造を辿り、バックグラウンドで高速にメタデータを監査・消去するには、APIのメモリライフサイクルを完全に制御したプログラムが不可欠だ。
ここで鍵となるのが以下の3つのオブジェクトとメソッドである。
1. `ModelDoc2.Extension.CustomPropertyManager`:
モデル本体(Config固有の場合はコンフィギュレーション名)に紐付くメタデータの総元締。
2. `CustomPropertyManager.GetNames`:
現在登録されているすべてのプロパティ名を `Variant` 型の配列として一網打尽に取得する。
3. `CustomPropertyManager.Delete2`:
指定したプロパティ名をメモリおよびストレージから完全に抹殺する。
しかし、VBAでこれらを安易にループさせると、COMオブジェクトの解放漏れによるメモリリークや、コンフィギュレーション固有プロパティとカスタムプロパティ(全コンフィギュレーション共通)の取り違えといった致命的な罠に踏み込むことになる。
—
2. 実装:メタデータ・クレンジング自動化マクロ
以下のコードは、アクティブなドキュメント(部品またはアセンブリ)を対象に、許可されたホワイトリスト以外の不要なプロパティをすべて削除し、さらに指定された大文字小文字の揺れを強制修正するエンタープライズグレードのマクロである。
Option Explicit
‘ ——————————————————————————–宗派
‘ 模倣を許さないチーフアーキテクトのコードブロック
‘ ターゲット: CustomPropertyManager クレンジング & ガバナンス強制適用
‘ ——————————————————————————–
Sub ExecuteMetadataGovernance()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swCustPropMgr As SldWorks.CustomPropertyManager
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “Governance Error”
Exit Sub
End If
Dim startTime As Double
startTime = Timer
‘ 1. 処理対象のコンフィギュレーション名を取得(アクティブコンフィギュレーション)
Dim activeConfigName As String
activeConfigName = swModel.ConfigurationManager.ActiveConfiguration.Name
‘ —————————————————————-
Nugget_CleanProperties swModel, “”, activeConfigName
‘ —————————————————————-
‘ 画面描画を強制リフレッシュし、変更をコミット
swModel.ForceRebuild3 False
Debug.Print “メタデータクレンジング完了. 処理時間: ” & Format(Timer – startTime, “0.00秒”)
MsgBox “メタデータのクレンジングとガバナンス適用が完了しました。”, vbInformation, “System Success”
End Sub
Private Sub Nugget_CleanProperties(ByRef swModel As SldWorks.ModelDoc2, ByVal configName As String, ByVal activeConfigName As String)
Dim swCustPropMgr As SldWorks.CustomPropertyManager
‘ 引数 configName が空文字列の場合は「カスタム(全構成共通)」、指定がある場合は「コンフィギュレーション固有」
Set swCustPropMgr = swModel.Extension.CustomPropertyManager(configName)
If swCustPropMgr Is Nothing Then Exit Sub
Dim vPropNames As Variant
vPropNames = swCustPropMgr.GetNames
If IsEmpty(vPropNames) Then Exit Sub
Dim i As Long
Dim propName As String
Dim valOut As String
Dim resolvedValOut As String
Dim wasResolved As Boolean
Dim linkVal As String
‘ — 【ホワイトリスト定義】 —
‘ 組織として存続を許すプロパティ名(完全一致・大文字小文字を区別しない場合は別途LCase比較)
Dim whiteList As Variant
whiteList = Array(“PART_NO”, “DESCRIPTION”, “MATERIAL”, “AUTHOR”, “REVISION”)
For i = LBound(vPropNames) To UBound(vPropNames)
propName = CStr(vPropNames(i))
‘ ガバナンス判定1: ホワイトリストに含まれているか?
If Not IsInArray(propName, whiteList) Then
‘ 許可されていないプロパティは即座に削除(Delete2)
‘ 引数: PropertyName
swCustPropMgr.Delete2 propName
Debug.Print “[DELETE] 廃棄された不要プロパティ: ” & propName & ” (Config: ” & IIf(configName = “”, “
Else
‘ ガバナンス判定2: 命名規則・大文字小文字の強制統一(例: “material” -> “MATERIAL”)
Dim standardizedName As String
standardizedName = GetStandardizedName(propName, whiteList)
If propName <> standardizedName Then
‘ 値を一度退避
swCustPropMgr.Get4 propName, False, valOut, resolvedValOut, wasResolved, linkVal
‘ 旧名称を削除
swCustPropMgr.Delete2 propName
‘ 正規化された名称で再登録
Dim resolvedType As Long
‘ 型を維持した再登録が必要だが、簡略化のためテキストとして再設定する例
swCustPropMgr.Add3 standardizedName, swCustomInfoText, resolvedValOut, swCustomPropertyReplaceValue
Debug.Print “[NORMALIZE] 命名規則を統一: ” & propName & ” -> ” & standardizedName
End If
End If
Next i
‘ ※アセンブリの場合は子コンポーネント(部品)への再帰処理をここに実装可能
End Sub
‘ ユーティリティ関数: ホワイトリスト判定(大文字小文字を区別しない)
Private Function IsInArray(ByVal stringToFind As String, ByRef arr As Variant) As Boolean
Dim item As Variant
For Each item In arr
If UCase(item) = UCase(stringToFind) Then
IsInArray = True
Exit Function
End If
Next item
IsInArray = False
End Function
‘ ユーティリティ関数: 正式なホワイトリスト表記の名称を返す
Private Function GetStandardizedName(ByVal stringToFind As String, ByRef arr As Variant) As Boolean
Dim item As Variant
For Each item In arr
If UCase(item) = UCase(stringToFind) Then
GetStandardizedName = CStr(item)
Exit Function
End If
Next item
GetStandardizedName = stringToFind
End Function
—
3. シニアエンジニアが押さえるべき「APIの急所」
上記のコードを実務の巨大なアセンブリ(数千部品)に適用する際、パフォーマンスと安定性を担保するための極意を伝授する。
A. `GetNames` の戻り値の罠
`CustomPropertyManager.GetNames` は、プロパティが1つも存在しない場合、空の配列ではなく `Empty` を返す。これをそのまま `UBound` にかけると `Run-time error ‘9’: Subscript out of range` が発生する。必ず `IsEmpty()` によるガード句を挟むこと。これはSolidWorks API全般の文字列配列取得における鉄則である。
B. `Delete2` の挙動とメモリ解放
`Delete2` メソッドを実行した瞬間、そのプロパティ領域は即座にメモリ上から破棄される。しかし、COMの参照カウンタやポインタの整合性を保つため、ループ内で `GetNames` を再取得するような愚行は避けるべきだ。最初に配列として名前をスキャンし、インデックスベースで一括処理する今回のアーキテクチャが最も安全かつ高速である。
C. 大文字小文字の非対称性
SolidWorksのカスタムプロパティは、GUI上では大文字小文字を区別しないように見える挙動を示すことがあるが、内部的には `Material` と `MATERIAL` は完全に別個のプロパティとして共存し得る。これが混乱の元凶である。クレンジング時には、一度 `UCase` で比較し、重複リスクを排除した上で削除・再登録のトランザクションを張る必要がある。
—
4. システム間連携(PDM / ERP)への昇華
このマクロを単なる「ローカルの掃除屋」で終わらせてはならない。
社内の PLM/PDMシステムや基幹ERP(SAP等)との連携バッチ の前段に、このクレンジングロジックを組み込むのだ。
外部システムへCADデータを送信する直前、あるいは夜間のタスクスケジューラによるバッチ処理の中で本プログラムをヘッドレス(UI非表示)で走らせる。これにより、設計者がいかに無秩序にプロパティを入力しようとも、上流工程(ERP/BOM)に到達する前にメタデータが自動的に浄化される「自己治癒型エンジニアリングチェーン」が完成する。
レガシーな技術的負債を嘆く時間は終わった。APIを掌握し、CADデータの秩序をコードの力で支配せよ。
