【実務・中級編】【実務中級】アセンブリ内のパーツごとに定義されたカスタムプロパティの命名規則違反を一括スキャンして修正するツール – SolidWorks VBA解析バイブル

スポンサーリンク

はじめに:なぜ、アセンブリの「プロパティ揺れ」で設計者は疲弊するのか

大規模なアセンブリを扱う現場において、最も不毛で、かつ見落とされがちなボトルネックが「カスタムプロパティの命名規則違反」だ。

  • 「`PartName` なのか `部品名称` なのか `名称` なのかバラバラ」
  • 「材質(`Material`)のキーが大文字・小文字で混在している」
  • 「必須であるはずの製作者名が空欄のままアセンブリに組み込まれている」

これらを人の目と手作業で修正させるとはどういうことか。数千パーツを抱えるアセンブリにおいて、品質管理のコストは爆発的に跳ね上がり、下流工程(BOM連携やPLMへの登録)で致命的なエラーを引き起こす。

この記事では、SolidWorks APIの深層を突き、アセンブリの階層構造を再帰的に巡回しながら、カスタムプロパティの命名規則違反を一括スキャン・自動補正するプロダクション品質のVBAツールを解説する。

単なる「動くコード」ではなく、実務の現場で耐えうる堅牢性とパフォーマンスを担保した設計思想を叩き込む。

—

1. 堅牢なツール設計のための3つのアーキテクチャ原則

実務で使えるSolidWorksマクロを書くためには、APIの「重み」と「オブジェクトの寿命」を完全に理解していなければならない。

① 再帰処理(Recursive)による全階層の完全走査

アセンブリは「サブアセンブリの中にサブアセンブリ、その中にパーツ」というツリー構造を持つ。フラットなコンポーネント取得では深層のパーツを見落とす。親から子へ、子から孫へと安全に潜っていく再帰関数が必須となる。

② カスタムプロパティマネージャー(CustomPropertyManager)の正確なスコープ

SolidWorksにおいて、プロパティは「コンフィギュレーション固有」と「ユーザー定義(ファイル共通)」の2種類が存在する。命名規則の統制対象がどちらなのかを明確にし、適切なスコープ(構成名を設定するか、空文字列にするか)を操作しなければ、意図したデータが書き換わらない。

③ 辞書(Dictionary)によるマッピングと一括置換の高速化

「旧キー名」から「正当なキー名」へのマッピングは、ハードコーディングせず、VBAの `Scripting.Dictionary` を用いてメモリ上で高速に解決する。これにより、ルール変更時のメンテナンス性が飛躍的に向上する。

—

2. コピー&ペーストで即座に動くプロダクションコード

以下のコードは、アクティブなアセンブリを開いた状態で実行することで、指定されたルールに基づいて全構成部品のカスタムプロパティをスキャンし、違反しているキーを自動リネーム、あるいは新規作成・補正するマクロだ。

Option Explicit

‘ ==============================================================================
‘ 業務自動化アーキテクチャ:カスタムプロパティ一括クレンジングツール
‘ ==============================================================================

‘ 許容する正規のプロパティキーと、そのデフォルト値(定義辞書)
Private Const TARGET_CONFIG As String = “” ‘ 空欄の場合は「ユーザー定義(ファイル共通)」を対象とする

Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssm As SldWorks.AssemblyDoc

Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc

‘ 1. アセンブリが開かれているか検証
If swModel Is Nothing Then
MsgBox “ドキュメントが開かれていません。”, vbCritical, “エラー”
Exit Sub
End If

If swModel.GetType <> swDocASSEMBLY Then
MsgBox “このマクロはアセンブリドキュメントでのみ実行可能です。”, vbCritical, “エラー”
Exit Sub
End If

‘ 2. 辞書オブジェクトの初期化(旧キー名 -> 正式キー名 のマッピング)
Dim propMap As Object
Set propMap = CreateObject(“Scripting.Dictionary”)

‘ 【ルール定義】ここに現場のレギュレーションをマッピングする
‘ 例: “Part_Name”, “名称”, “部品名” などの揺れを “部品名称” に統一する
propMap.Add “Part_Name”, “部品名称”
propMap.Add “名称”, “部品名称”
propMap.Add “PartName”, “部品名称”

propMap.Add “Material”, “材質”
propMap.Add “MAT”, “材質”

propMap.Add “Designer”, “設計者”

‘ 3. 処理開始の確認
Dim confirm As VbMsgBoxResult
confirm = MsgBox(“アクティブアセンブリ内の全パーツ・サブアセンブリのプロパティをスキャンし、命名規則の自動補正を行います。” & vbCrLf & “実行しますか?”, vbQuestion + vbYesNo, “一括クレンジング”)
If confirm = vbNo Then Exit Sub

‘ 4. 処理の実行(パフォーマンス向上のための画面描画停止)
swApp.Visible = False
swModel.Extension.EnableAnimations = False

Dim startTime As Double
startTime = Timer

Dim processedCount As Long
processedCount = 0

‘ 再帰処理の呼び出し
ProcessComponentTree swModel, propMap, processedCount

‘ 5. 処理終了後の後始末
swModel.Extension.EnableAnimations = True
swApp.Visible = True

‘ 強制再描画
swModel.ForceRebuild3 True

MsgBox “処理が完了しました。” & vbCrLf & _
“処理コンポーネント数: ” & processedCount & ” 件” & vbCrLf & _
“処理時間: ” & Format(Timer – startTime, “0.00”) & ” 秒”, vbInformation, “完了”
End Sub

‘ ==============================================================================
‘ アセンブリツリーを再帰的に走査する核心ロジック
‘ ==============================================================================
Private Sub ProcessComponentTree(ByVal swModel As SldWorks.ModelDoc2, ByVal propMap As Object, ByRef count As Long)
Dim swAssm As SldWorks.AssemblyDoc
Set swAssm = swModel

‘ 直下のコンポーネントを取得(トップレベルのみならず、全てのインスタンス)
Dim vComps As Variant
vComps = swAssm.GetComponents(True) ‘ True = トップレベルおよびサブアセンブリ内のすべてのコンポーネント

If IsEmpty(vComps) Then Exit Sub

Dim i As Long
Dim swComp As SldWorks.Component2
Dim swCompModel As SldWorks.ModelDoc2
Dim compPath As String

‘ 処理済みパスを記録するためのDictionary(同一パーツの重複処理を防止)
Dim processedPaths As Object
Set processedPaths = CreateObject(“Scripting.Dictionary”)

For i = LBound(vComps) To UBound(vComps)
Set swComp = vComps(i)

‘ 隠蔽されている、あるいは軽量化されている場合はスキップ等の例外処理
If Not swComp.IsSuppressed Then
Set swCompModel = swComp.GetModelDoc2()

If Not swCompModel Is Nothing Then
compPath = swCompModel.GetPathName

‘ まだ処理していない物理ファイルの場合のみプロパティ操作を行う(仮想部品などの考慮)
If Not processedPaths.Exists(compPath) Then
processedPaths.Add compPath, True

‘ プロパティのクレンジング実行
CleanUpCustomProperties swCompModel, propMap
count = count + 1
End If
End If
End If
Next i
End Sub

‘ ==============================================================================
‘ 個別ドキュメントのカスタムプロパティを解析・置換するコアエンジン
‘ ==============================================================================
Private Sub CleanUpCustomProperties(ByVal swModel As SldWorks.ModelDoc2, ByVal propMap As Object)
Dim swCustPropMgr As SldWorks.CustomPropertyManager
Set swCustPropMgr = swModel.Extension.CustomPropertyManager(TARGET_CONFIG)

If swCustPropMgr Is Nothing Then Exit Sub

Dim vNames As Variant
Dim i As Long
Dim propName As String
Dim propVal As String
Dim resolvedVal As String
Dim evalType As Long

‘ 既存のカスタムプロパティ名の一覧を取得
swCustPropMgr.GetNames2 vNames

If Not IsEmpty(vNames) Then
For i = LBound(vNames) To UBound(vNames)
propName = CStr(vNames(i))

‘ 辞書に「旧キー名」として登録されているかチェック
If propMap.Exists(propName) Then
Dim targetName As String
targetName = propMap(propName)

‘ 値の取得(評価値を取得する)
swCustPropMgr.Get4 propName, False, propVal, resolvedVal

‘ 新しいキー名でプロパティを追加(または上書き)
swCustPropMgr.Add3 targetName, swCustomInfoText, resolvedVal, swCustomPropertyReplaceValue

‘ 古いキー名のプロパティを削除
swCustPropMgr.Delete2 propName
End If
Next i
End If

‘ 補足:必須プロパティが空欄、あるいは存在しない場合のデフォルト値埋め処理
EnsureMandatoryProperty swCustPropMgr, “部品名称”, swModel.GetTitle
EnsureMandatoryProperty swCustPropMgr, “材質”, “未設定”
End Sub

‘ ==============================================================================
‘ 必須プロパティの存在確認と欠損時のデフォルト値補正
‘ ==============================================================================
Private Sub EnsureMandatoryProperty(ByVal swCustPropMgr As SldWorks.CustomPropertyManager, ByVal keyName As String, ByVal defaultValue As String)
Dim val As String
Dim resolved As String
Dim status As Long

status = swCustPropMgr.Get4(keyName, False, val, resolved)

‘ プロパティ自体が存在しない、または値が空の場合
If status = 0 Or Trim(resolved) = “” Then
swCustPropMgr.Add3 keyName, swCustomInfoText, defaultValue, swCustomPropertyReplaceValue
End If
End Sub

—

3. チーフアーキテクトが教える、実務運用上の注意点

このツールを実際の設計環境に導入する際、いくつかの「現場の罠」に直面する。事前にこれらを潰しておくことが、真に信頼される自動化エンジニアの仕事だ。

① 読み取り専用ファイル(Read-Only)のハンドリング

PLMシステムや共有サーバー上のライブラリパーツ(市販品や標準部品)は「読み取り専用」になっていることが多い。上記コードにエラーハンドリング(`On Error Resume Next` の適切な配置やファイルの属性チェック)を加えなければ、標準部品に書き込もうとしてマクロがクラッシュする。
実務では、`swModel.IsReadonly` を事前に評価し、読み取り専用のパーツはスキップするガード節を入れるべきだ。

② 外部参照・コンテキストの破壊リスク

モデルの保存状態を汚さないため、変更を加えたドキュメントは明示的に保存するか、あるいはユーザーに確認を促す設計にすべきである。自動で上書き保存 (`swModel.Save3`) を行う場合は、意図しないコンテキスト変更によるトラブルを防ぐため、事前のバックアップ体制が必須となる。

③ パフォーマンス最適化の極意

大規模アセンブリで `swAssm.GetComponents(True)` を呼ぶと、すべてのコンポーネントの参照がメモリ上にロードされる。もし動作が重い場合は、軽量化モード(Lightweight)のままプロパティにアクセスできるAPI特性を利用しつつ、無駄な再描画を完全にシャットアウトする (`swApp.Visible = False`) 処理が命綱となる。

—

おわりに:データ品質は「自動化」で守る時代へ

設計者が図面を描く時間と同じくらい、「データを綺麗に整理する時間」が無駄に消費されている。
今回紹介したカスタムプロパティのクレンジングツールは、単なるVBAのサンプルではない。「人間の手によるミスをシステムで完全に根絶する」という、エンジニアリングの基本思想を具現化したものだ。

ぜひ自社のレギュレーションに合わせてプロパティマップを拡張し、明日の設計業務のストレスを一つ解消してほしい。

タイトルとURLをコピーしました