【SolidWorks VBA極限活用】カスタムプロパティの完全同期と一括クリーンアップ:レガシー汚染を断つメタデータ制御術
開発現場でこんな絶望を味わったことはないだろうか。
「何年も蓄積されたレガシーパーツのカスタムプロパティがカオス状態だ」
「担当者によって『材質』『Material』『マテリアル』と表記揺れを起こし、PDMや外部ERP連携の自動化スクリプトが毎日エラーを吐く」
「不要なゴミプロパティが数千個のファイルに残留し、ファイルサイズとメモリを無駄に圧迫している」
GUIの手作業でこれらを修正するなど、エンジニアの人生の無駄遣いでしかない。
今回は、SolidWorks APIの神髄である `CustomPropertyManager` を完全に手なづけ、「既存のゴミを完璧に掃き清め、社内標準スキーマへと強制同期・一括クリーンアップする」ためのプロダクションコードを授けよう。
中途半端なネットのサンプルコードでありがちな「エラーハンドリングの欠如」「メモリリーク」「存在しないプロパティへのアクセスによるクラッシュ」とは今日で決別する。プロの現場で耐えうる、鉄壁のVBAアーキテクチャを解説する。
—
1. なぜレガシープロパティの操作は難解なのか?
SolidWorksのカスタムプロパティ操作において、多くのVBA初心者(そして中級者すら)がハマる致命的な罠がある。
1. スコープ(コンフィギュレーション)の罠
カスタムプロパティには、「ファイル全体(全コンフィギュレーション共通)」と「特定コンフィギュレーション固有」の2つのレイヤーが存在する。これを意識せずに取得・削除を行うと、意図しないレイヤーにゴミを残すことになる。
2. 存在しないキーへのアクセス
VBAの `Get` メソッドは、存在しないキーを指定するとランタイムエラー(あるいは空のバリアント)を返し、挙動が不安定になる。
3. 列挙と削除のアンチパターン
ループを回しながらコレクションの要素(プロパティ)をその場で削除すると、インデックスがずれて確実にバグる(プロパティの取りこぼしが発生する)。
これらをクリアするためには、「全スキャン ➔ 削除リストの作成 ➔ 一括削除 ➔ 標準スキーマの流し込み」という厳格なライフサイクル管理が必要だ。
—
2. アーキテクチャ設計:メタデータ完全同期の4ステップ
今回構築するスクリプトのワークフローは以下の通りだ。
[処理開始]
│
├─ 1. 対象コンフィギュレーション(またはカスタムプロパティマネージャー)の取得
├─ 2. EnumCustomProperties または GetNames による全プロパティ名の完全列挙
├─ 3. 「死活監視」:社内標準スキーマに合致しないレガシーキーを特定し、削除リストへ登録
├─ 4. クリーンアップ実行(一括削除)
└─ 5. 社内標準プロパティの書き込み(値の強制同期)
[処理完了]
特に `GetNames` と `EnumCustomProperties` の使い分けが重要だ。
`GetNames` はVariant配列を返すため一見手軽だが、大規模なアセンブリや履歴の汚染されたパーツでは、予期せぬNULLや重複が含まれることがある。堅牢性を担保するため、今回はAPIの仕様に忠実なアプローチを採用する。
—
3. プロダクションコード:メタデータ完全同期・一括クリーンアップモジュール
以下のコードは、アクティブなパーツドキュメント(または指定ドキュメント)に対し、不要なプロパティを全削除し、定義された標準プロパティ構造へと強制上書きする実務用マクロだ。
‘ Option Explicitはプログラマの良心である。必ず宣言せよ。
Option Explicit
‘ メインエントリーポイント
Sub Main_SyncCustomProperties()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swCustPropMgr As SldWorks.CustomPropertyManager
Dim lRetVal As Long
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
‘ ドキュメントが開かれているか、かつパーツ(またはアセンブリ)かチェック
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “エラー”
Exit Sub
End If
If swModel.GetType <> swDocPART And swModel.GetType <> swDocASSEMBLY Then
MsgBox “このマクロはパーツまたはアセンブリでのみ実行可能です。”, vbExclamation, “対象外”
Exit Sub
End If
‘ 処理確認
If MsgBox(“現在のカスタムプロパティを社内標準スキーマへ強制同期・クリーンアップしますか?” & vbCrLf & _
“※不要なレガシープロパティは削除されます。”, vbYesNo + vbQuestion, “カスタムプロパティ同期”) = vbNo Then
Exit Sub
End If
‘ 設定(Configuration)を指定しない場合は空文字列(””)で「要約情報 / すべてのコンフィギュレーション」を対象とする
‘ ※特定コンフィギュレーションに紐づくプロパティを操作する場合は、コンフィギュレーション名を取得して渡すこと
Set swCustPropMgr = swModel.Extension.CustomPropertyManager(“”)
On Error GoTo ErrorHandler
‘ ステップ1: レガシープロパティの全削除(クリーンアップ)
Call CleanupLegacyProperties(swCustPropMgr)
‘ ステップ2: 社内標準スキーマの適用(インジェクション)
Call ApplyStandardSchema(swCustPropMgr, swModel)
‘ 変更を保存対象の状態にする(強制リビルド・ファイル保存は要件に応じて追加)
swModel.SetSaveFlag
MsgBox “カスタムプロパティの完全同期が正常に完了しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
‘ —————————————————————–
‘ レガシープロパティの網羅的スキャンと一括削除
‘ —————————————————————–
Private Sub CleanupLegacyProperties(swCustPropMgr As SldWorks.CustomPropertyManager)
היי vba配列とAPIの連携
Dim vPropNames As Variant
Dim i As Long
Dim propName As String
‘ GetNamesで全てのカスタムプロパティ名を取得
‘ 戻り値がEmptyの場合の対策としてVarTypeをチェック
lRetVal = swCustPropMgr.GetNames(vPropNames)
If Not IsEmpty(vPropNames) Then
For i = LBound(vPropNames) To UBound(vPropNames)
propName = CStr(vPropNames(i))
‘ 【重要】削除してはいけないシステム予約プロパティやPDM連携キーがある場合はここで除外判定を行う
If Not IsSystemOrProtectedProperty(propName) Then
‘ プロパティの削除を実行
swCustPropMgr.Delete (propName)
End If
Next i
End If
End Sub
‘ —————————————————————–
‘ 社内標準スキーマの流し込み(同期)
‘ —————————————————————–
Private Sub ApplyStandardSchema(swCustPropMgr As SldWorks.CustomPropertyManager, swModel As SldWorks.ModelDoc2)
Dim valOut As String
Dim resolvedValOut As String
Dim wasResolved As Boolean
Dim linkToProp As Boolean
‘ 例:社内標準スキーマの定義とデフォルト値の設定
‘ swCustomInfoText (30), swCustomInfoNumber (11) などのタイプを指定
‘ 1. 図面枠連動:承認者
Call SetPropertySafe(swCustPropMgr, “APPROVED_BY”, “T.Yamada”, swCustomInfoText)
‘ 2. マテリアル(SolidWorksの材質情報から自動取得して同期する例)
Dim matName As String
Dim matDB As String
matName = swModel.GetMaterialName2(“”, matDB)
If matName = “” Then matName = “未設定”
Call SetPropertySafe(swCustPropMgr, “MATERIAL”, matName, swCustomInfoText)
‘ 3. 会社規定の分類コード(初期値)
Call SetPropertySafe(swCustPropMgr, “PART_CLASS”, “GENERAL_MECHANICAL”, swCustomInfoText)
‘ 4. 履歴管理用タイムスタンプ
Call SetPropertySafe(swCustPropMgr, “SCHEMA_SYNC_DATE”, Format(Now, “yyyy-mm-dd”), swCustomInfoText)
End Sub
‘ —————————————————————–
‘ 安全なプロパティ設定ラッパー関数
‘ —————————————————————–
Private Sub SetPropertySafe(swCustPropMgr As SldWorks.CustomPropertyManager, _
ByVal propName As String, _
ByVal propValue As String, _
ByVal propType As Long)
Dim nRet As Long
‘ Add3 第1引数: 名前
‘ 第2引数: タイプ (swCustomInfoType_e)
‘ 第3引数: 値
‘ 第4引数: 既存の場合の上書きモード (swCustomInfoAddText = 1, swCustomInfoReplaceValue = 2 等)
‘ ※ Add3は既存の場合は上書き失敗することがあるため、確実に存在チェックまたはReplaceを使う
‘ 既に存在するか確認して分岐
Dim valOut As String
Dim resolvedValOut As String
Dim status As Long
status = swCustPropMgr.Get6(propName, False, valOut, resolvedValOut, False, False)
If status = swCustomInfoGetResult_NotPresent Then
‘ 新規追加
nRet = swCustPropMgr.Add3(propName, propType, propValue, swCustomInfoAddOption_DoNotAddIfPresent)
Else
‘ 既存の場合は値を置換
nRet = swCustPropMgr.Set2(propName, propValue)
End If
End Sub
‘ —————————————————————–
‘ 保護すべきプロパティの判定(ホワイトリスト・ブラックリスト管理)
‘ —————————————————————–
Private Function IsSystemOrProtectedProperty(ByVal propName As String) As Boolean
‘ PDMのシステム変数や、消してはならないレガシーキーをここで弾く
Select Case UCase(propName)
Case “SW-Mass”, “SW-Volume”, “SW-Density”, “PDM_STATE”, “CHECKED_OUT_BY”
IsSystemOrProtectedProperty = True
Case Else
IsSystemOrProtectedProperty = False
End Select
End Function
—
4. チーフアーキテクトが教える「現場で絶対に躓かない」ための実装上の急所
このコードを実務のバッチ処理(複数ファイルの自動処理など、FileSystemObjectと組み合わせたファイル一括処理)に組み込む際、以下の2点を見落とすと大惨事になる。
① パフォーマンスとメモリリークの防衛
大量のパーツファイルをバックグラウンド(`swApp.OpenDoc6` の `Silent` モード)で処理する場合、モデルを開いたままにすると確実にメモリが破綻する。
ファイルごとに処理を完結させたら、必ず以下の手順でメモリを解放すること。
‘ バックグラウンド処理時の必須イディオム
swApp.CloseDoc swModel.GetTitle
Set swModel = Nothing
これを怠ると、500ファイルを処理したあたりでSolidWorksがフリーズするか、メモリ不足でクラッシュする。
② コンフィギュレーション別プロパティの魔窟への対策
今回のサンプルは「全コンフィギュレーション共通(要約情報)」を対象としているが、社内規程によっては「コンフィギュレーションごとに材質や質量プロパティが異なる」ケースがある。
もし特定コンフィギュレーション固有のカスタムプロパティを対象にする場合は、`swModel.GetConfigurationNames` を用いて全コンフィギュレーションの配列を取得し、ループを回してそれぞれの `CustomPropertyManager`(引数にコンフィギュレーション名を渡す)に対して同じ処理を実行しなければならない。
Dim vConfigs As Variant
Dim j As Long
vConfigs = swModel.GetConfigurationNames()
For j = LBound(vConfigs) To UBound(vConfigs)
Set swCustPropMgr = swModel.Extension.CustomPropertyManager(CStr(vConfigs(j)))
‘ ここでクリーンアップと同期を実行
Next j
—
5. おわりに:メタデータの美しさは、設計の美しさに直結する
汚染されたカスタムプロパティは、CADデータにおける「ゴミ屋敷」だ。
目に見えない部分のデータ構造が乱れていると、上流工程(設計)から下流工程(CAM、CAE、PDM、ERP、そして自動図面生成)に至るすべての自動化パイプラインが毒される。
今回紹介した `CustomPropertyManager` を駆使した一括クリーンアップ&同期スクリプトをマスターすれば、レガシーデータの呪縛から完全に解放されるだけでなく、あなたのチームの業務効率は次元の違うスピードへと突入する。
さあ、このコードをあなたの開発環境にブッ込み、社内のメタデータを美しく浄化し尽くしてほしい。
