【テクニカル・上級編】【実務中級】アセンブリ内のパーツごとに異なるカスタムプロパティ(材料・仕上げ等)が一括設定されているかを検証するバリデーション – SolidWorks VBA解析バイブル

スポンサーリンク

SolidWorks VBA 伝説的チーフアーキテクトが語る:アセンブリ バリデーションの深淵 ~カスタムプロパティ監査による製造データ連携の自動化~

製造業におけるデータ連携の自動化は、もはや単なる効率化の範疇を超え、品質保証とリードタイム短縮の生命線である。特に、複雑なアセンブリ構造を持つ製品群において、各コンポーネントに付与されるカスタムプロパティ(材料、仕上げ、加工方法など)の正確性と網羅性は、後工程へのデータ伝達の信頼性を左右する。本稿では、SolidWorks VBA を駆使し、アセンブリ内の全パーツに設定されたカスタムプロパティの一括検証を行うバリデーションシステムの実装に焦点を当てる。単なるリファレンスコードの提示に終始せず、オブジェクトのライフサイクル管理、Windows API の活用、そしてレガシー環境における保守性といった、現場のエンジニアが直面するであろう「深淵」に踏み込んでいく。

なぜカスタムプロパティの自動監査が必要なのか?

製造業の現場では、設計データがそのまま製造指示データとして利用されることが一般的だ。しかし、設計段階で付与されるカスタムプロパティに漏れや誤りがあれば、それはそのまま製造ミス、品質低下、手戻り、そしてコスト増に直結する。特に、大規模なアセンブリでは、手作業による全パーツのカスタムプロパティ確認は非現実的であり、ヒューマンエラーのリスクも極めて高い。

ここで、SolidWorks VBA による自動バリデーションが真価を発揮する。

  • 品質保証の向上: 必須プロパティの未設定を早期に検知し、製造工程への不正なデータ流入を防ぐ。
  • リードタイムの短縮: 手作業での確認時間を大幅に削減し、設計から製造への移行をスムーズにする。
  • トレーサビリティの確保: 全パーツのプロパティ情報を一元管理し、製品ライフサイクル全体での追跡を容易にする。
  • システム間連携の自動化: 製造実行システム(MES)や ERP システムなど、他システムへのデータ連携の精度を高める。

SolidWorks API のオブジェクトライフサイクルとメモリ管理の重要性

SolidWorks VBA でアセンブリを扱う際、最も注意すべきは オブジェクトのライフサイクル管理 である。特に、大規模なアセンブリを繰り返し処理する場合、不要になったオブジェクトを適切に解放しないと、メモリリークを引き起こし、SolidWorks 自体の動作が不安定になったり、最悪の場合はクラッシュを招いたりする。

オブジェクトの明示的解放 (Nothing への代入)

VBA では、COM オブジェクトは明示的に `Nothing` に代入することで解放される。これは、グローバル変数やループ内で生成されるオブジェクトに対して特に重要だ。

‘ 悪い例:オブジェクトが解放されず、メモリを圧迫する可能性がある
Sub ProcessAssembly_Bad()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssembly As SldWorks.AssemblyDoc
Dim swComp As SldWorks.Component2
Dim swConfigMgr As SldWorks.ConfigurationManager
Dim swConf As SldWorks.Configuration

Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Or swModel.GetType <> swDocumentTypes_e.swDocASSEMBLY Then
MsgBox “アクティブなドキュメントがアセンブリではありません。”, vbExclamation
Exit Sub
End If
Set swAssembly = swModel

‘ コンフィグレーションマネージャーやコンフィグレーションオブジェクトも同様
Set swConfigMgr = swModel.ConfigurationManager
Set swConf = swConfigMgr.ActiveConfiguration

‘ コンポーネントのループ処理
Dim vComponents As Variant
vComponents = swAssembly.GetComponents(True) ‘ Trueで再帰的に全コンポーネントを取得
Dim i As Long
For i = LBound(vComponents) To UBound(vComponents)
Set swComp = vComponents(i)
‘ swComp を使った処理…
‘ ここで swComp を Nothing に代入しないと、ループを抜けてもオブジェクトは残り続ける
‘ Set swComp = Nothing ‘ ← これは間違い、配列の要素だから解放されない
Next i

‘ swAssembly, swModel, swApp も解放しないと…
‘ Set swComp = Nothing ‘ ← 処理が終わった後で、ループ内で使ったオブジェクトを解放する
‘ Set swConf = Nothing
‘ Set swConfigMgr = Nothing
‘ Set swAssembly = Nothing
‘ Set swModel = Nothing
‘ Set swApp = Nothing
‘ (実際には、Application.SldWorks は通常解放しないが、他のオブジェクトは必要に応じて)
End Sub

‘ 良い例:各オブジェクトを適切なタイミングで解放する
Sub ProcessAssembly_Good()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssembly As SldWorks.AssemblyDoc
Dim swComp As SldWorks.Component2
Dim vComponents As Variant
Dim i As Long

‘ SolidWorks アプリケーションオブジェクトは通常、グローバルなインスタンスを参照するため、明示的な解放は行わないことが多い
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc

If swModel Is Nothing Then
MsgBox “アクティブなドキュメントがありません。”, vbExclamation
Exit Sub
End If

If swModel.GetType <> swDocumentTypes_e.swDocASSEMBLY Then
MsgBox “アクティブなドキュメントがアセンブリではありません。”, vbExclamation
Exit Sub
End If
Set swAssembly = swModel ‘ アセンブリドキュメントとしてキャスト

Dim success As Boolean
success = True ‘ 検証結果を保持するフラグ

‘ コンポーネントのコレクションを取得
vComponents = swAssembly.GetComponents(True) ‘ Trueで再帰的に全コンポーネントを取得

If Not IsEmpty(vComponents) Then
For i = LBound(vComponents) To UBound(vComponents)
Set swComp = vComponents(i)

‘ — ここでカスタムプロパティの検証処理を行う —
Dim propValue As String
Dim propName As String
propName = “材料” ‘ 例: 材料プロパティを検証

‘ コンポーネントのドキュメントを取得
Dim swCompModel As SldWorks.ModelDoc2
Set swCompModel = swComp.GetModelDoc2

If Not swCompModel Is Nothing Then
‘ カスタムプロパティを取得
propValue = swCompModel.Extension.CustomPropertyManager(“”).Get(propName)

If Trim(propValue) = “” Then
‘ 未設定の場合の処理
Debug.Print “警告: コンポーネント ‘” & swComp.Name2 & “‘ のカスタムプロパティ ‘” & propName & “‘ が未設定です。”
‘ TODO: 該当コンポーネントをハイライトする処理などを追加
success = False
End If

‘ コンポーネントのドキュメントオブジェクトを解放
Set swCompModel = Nothing
Else
Debug.Print “警告: コンポーネント ‘” & swComp.Name2 & “‘ のモデルドキュメントを取得できませんでした。”
success = False
End If
‘ — 検証処理ここまで —

‘ ループ内で使用した swComp オブジェクトを解放
Set swComp = Nothing
Next i
End If

‘ 使用したオブジェクトを明示的に解放
Set swAssembly = Nothing
Set swModel = Nothing
‘ swApp は通常解放しない

If success Then
MsgBox “すべてのカスタムプロパティが正しく設定されています。”, vbInformation
Else
MsgBox “カスタムプロパティに未設定項目が検出されました。詳細はイミディエイトウィンドウを確認してください。”, vbExclamation
End If
End Sub

配列とオブジェクト

上記コード例の `vComponents` は Variant 型の配列 であり、その要素(`swComp`)は `Component2` オブジェクトへの参照です。配列自体が解放されるのは、配列変数自体が `Nothing` に代入されたり、スコープを抜けるときです。しかし、配列の 各要素 が保持しているオブジェクトへの参照は、配列が解放されるまで残り続けます。そのため、ループ内で `swComp` を `Nothing` に代入することは、配列の要素が保持する参照を解放する ために有効です。

`ModelDoc2` オブジェクトの管理

`Component2` オブジェクトから `GetModelDoc2()` メソッドで取得できる `ModelDoc2` オブジェクトも COM オブジェクトです。これを `Nothing` に代入し忘れると、メモリリークの原因となります。特に、パーツドキュメントやサブアセンブリドキュメントが多数開かれたままになる可能性があり、パフォーマンスに悪影響を与えます。

Windows API の活用:メモリ使用量の可視化とデバッグ

VBA の標準機能だけでは、メモリ使用量を詳細に把握するのは困難です。しかし、Windows API を利用することで、より詳細な情報にアクセスし、デバッグや最適化に役立てることができます。

`GlobalMemoryStatusEx` によるメモリ状況の取得

Windows API の `GlobalMemoryStatusEx` 関数は、システム全体のメモリ使用状況を取得するために使用できます。これにより、VBA マクロ実行前後でのメモリ増減を監視し、メモリリークの兆候を早期に発見することができます。

‘ Windows API 宣言 (標準モジュールに記述)
Private Declare Function GlobalMemoryStatusEx Lib “kernel32” ( _
lpBuffer As MEMORYSTATUSEX _
) As Long

Private Type MEMORYSTATUSEX
dwLength As Long
dwMemoryLoad As Long
ullTotalPhys As Currency
ullAvailPhys As Currency
ullTotalPageFile As Currency
ullAvailPageFile As Currency
ullTotalVirtual As Currency
ullAvailVirtual As Currency
ullAvailExtendedVirtual As Currency
End Type

‘ メモリ状況を取得して表示する関数
Sub CheckSystemMemory()
Dim memStatus As MEMORYSTATUSEX
memStatus.dwLength = Len(memStatus) ‘ Type構造体のサイズを設定

If GlobalMemoryStatusEx(memStatus) <> 0 Then
Debug.Print “— システムメモリ情報 —”
Debug.Print “メモリ使用率: ” & memStatus.dwMemoryLoad & “%”
Debug.Print “物理メモリ総量: ” & FormatCurrency(memStatus.ullTotalPhys)
Debug.Print “物理メモリ空き量: ” & FormatCurrency(memStatus.ullAvailPhys)
Debug.Print “仮想メモリ総量: ” & FormatCurrency(memStatus.ullTotalVirtual)
Debug.Print “仮想メモリ空き量: ” & FormatCurrency(memStatus.ullAvailVirtual)
Debug.Print “————————”
Else
Debug.Print “GlobalMemoryStatusEx の呼び出しに失敗しました。”
End If
End Sub

‘ ユーティリティ関数:バイトをGB単位で表示
Function FormatCurrency(ByVal bytes As Currency) As String
If bytes < 1024 Then FormatCurrency = bytes & " Bytes" ElseIf bytes < 1024 1024 Then FormatCurrency = Round(bytes / 1024, 2) & " KB" ElseIf bytes < 1024 1024 1024 Then FormatCurrency = Round(bytes / (1024 1024), 2) & " MB" Else FormatCurrency = Round(bytes / (1024 1024 1024), 2) & " GB" End If End Function この `CheckSystemMemory` サブルーチンを、バリデーション処理の前後で呼び出すことで、メモリ使用量の変化を監視し、潜在的なメモリリークを特定する手がかりを得られます。

`EnumWindows` と `FindWindow` によるプロセス特定

SolidWorks のプロセスを特定し、そのプロセスに関連する情報を取得するために Windows API を使用することも可能です。例えば、`EnumWindows` や `FindWindow` API を使って SolidWorks のウィンドウハンドルを取得し、そこからプロセスID を特定する、といった応用が考えられます。これは、複数の SolidWorks インスタンスが起動している環境での処理を厳密に制御したい場合に役立ちます。

(※これらの API の実装は、より高度なトピックとなるため、ここでは詳細なコード例は割愛しますが、`FindWindow` API は特定のウィンドウテキストを持つウィンドウのハンドルを取得するのに便利です。これにより、対象となる SolidWorks インスタンスを正確に指定できます。)

レガシー環境での保守とシステム間連携の課題

長年運用されているシステムでは、レガシーな VBA コードが残存していることが多く、その保守はしばしば困難を極めます。

レガシー VBA コードの保守性向上

1. コメントの徹底: コードの意図、API の使用方法、オブジェクトのライフサイクルに関する注意点などを詳細にコメントとして残す。
2. モジュール化と構造化: 機能ごとにモジュールを分け、再利用可能なサブルーチンや関数を作成する。
3. エラーハンドリングの強化: `On Error Resume Next` の多用は避け、具体的なエラータイプに応じた処理を実装する。`Err` オブジェクトの詳細情報をログに出力するなど。
4. バージョン管理: コードの変更履歴を管理し、いつ、誰が、何を、なぜ変更したのかを明確にする。
5. テストコードの作成: バリデーションロジックの各部分に対する単体テストを作成し、変更による影響範囲を最小限に抑える。

システム間連携における考慮事項

  • データ形式の標準化: CSV, XML, JSON など、汎用的なデータ形式でカスタムプロパティをエクスポートする。
  • API 連携: SolidWorks の API を直接呼び出すのではなく、中間層(例: VB.NET アプリケーション)を介して、他システムとの連携を疎結合にする。
  • トランザクション処理: データ連携時には、データの整合性を保つためのトランザクション処理(コミット/ロールバック)を考慮する。
  • エラー通知メカニズム: データ連携に失敗した場合、関係者に速やかに通知する仕組みを構築する。

実装例:カスタムプロパティ検証バリデーション VBA コード

以下に、アセンブリ内の全パーツのカスタムプロパティ(例:「材料」と「仕上げ」)を検証し、未設定項目をイミディエイトウィンドウに表示する VBA コード例を示します。

Option Explicit

‘
‘ Routine: ValidateAssemblyCustomProperties
‘ Purpose: アセンブリ内の全コンポーネントのカスタムプロパティを検証する
‘ Author: 伝説的チーフアーキテクト
‘ Date: 2023/10/27
‘ Notes: 検証対象のプロパティ名と、未設定時にハイライトする処理は適宜カスタマイズのこと
‘
Sub ValidateAssemblyCustomProperties()

Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssembly As SldWorks.AssemblyDoc
Dim vComponents As Variant
Dim swComp As SldWorks.Component2
Dim swCompModel As SldWorks.ModelDoc2
Dim propValue As String
Dim propName As String
Dim missingProps As String
Dim componentName As String
Dim i As Long
Dim validationSuccess As Boolean

‘ — 初期化 —
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc

‘ アクティブドキュメントのチェック
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントがありません。”, vbExclamation, “バリデーションエラー”
Exit Sub
End If

If swModel.GetType <> swDocumentTypes_e.swDocASSEMBLY Then
MsgBox “アクティブなドキュメントはアセンブリではありません。”, vbExclamation, “バリデーションエラー”
Exit Sub
End If
Set swAssembly = swModel

validationSuccess = True ‘ 検証結果フラグ
missingProps = “” ‘ 未設定プロパティのリスト

Debug.Print “— アセンブリカスタムプロパティ検証開始 —”
Debug.Print “対象アセンブリ: ” & swModel.GetTitle

‘ — コンポーネントの取得 —
‘ GetComponents(True) は再帰的にすべてのコンポーネントを取得する
vComponents = swAssembly.GetComponents(True)

If IsEmpty(vComponents) Then
Debug.Print “アセンブリ内にコンポーネントが見つかりませんでした。”
MsgBox “アセンブリ内にコンポーネントが見つかりませんでした。”, vbInformation, “バリデーション完了”
Exit Sub
End If

‘ — 各コンポーネントの検証ループ —
For i = LBound(vComponents) To UBound(vComponents)
Set swComp = vComponents(i)
componentName = swComp.Name2 ‘ コンポーネント名を取得

‘ コンポーネントのモデルドキュメントを取得
Set swCompModel = swComp.GetModelDoc2

If Not swCompModel Is Nothing Then
‘ — 検証対象プロパティ —
Dim propertiesToValidate As Variant
propertiesToValidate = Array(“材料”, “仕上げ”, “加工方法”) ‘ ここで検証したいプロパティ名を指定

Dim j As Long
For j = LBound(propertiesToValidate) To UBound(propertiesToValidate)
propName = propertiesToValidate(j)
propValue = “” ‘ 初期化

‘ カスタムプロパティマネージャーを取得
Dim swCustPropMgr As SldWorks.CustomPropertyManager
Set swCustPropMgr = swCompModel.Extension.CustomPropertyManager(“”) ‘ “” はデフォルトのプロパティセットを意味する

‘ プロパティの値を取得
propValue = swCustPropMgr.Get(propName)

‘ プロパティが未設定か、空文字列かを確認
If Trim(propValue) = “” Then
validationSuccess = False
missingProps = missingProps & “- ‘” & componentName & “‘ のプロパティ ‘” & propName & “‘ が未設定です。” & vbCrLf
Debug.Print “未設定検出: [” & componentName & “] – ‘” & propName & “‘”

‘ — TODO: 該当コンポーネントをハイライトする処理 —
‘ 例: コンポーネントを非表示/表示切り替え、色を変更するなど
‘ (より高度なハイライトには、Windows API や SolidWorks API の詳細な知識が必要)
‘ swComp.SetDisplayState (swDispState_e.swDispState_eInActive) ‘ 例:一時的に非表示
End If

‘ オブジェクト解放
Set swCustPropMgr = Nothing
Next j

‘ コンポーネントのモデルドキュメントオブジェクトを解放
Set swCompModel = Nothing
Else
‘ モデルドキュメントが取得できなかった場合(例:リンク切れ、未ロードなど)
validationSuccess = False
missingProps = missingProps & “- ‘” & componentName & “‘ のモデルドキュメントを取得できませんでした。” & vbCrLf
Debug.Print “エラー: [” & componentName & “] – モデルドキュメント取得不可”
End If

‘ ループ内で使用したコンポーネントオブジェクトを解放
Set swComp = Nothing
Next i

‘ — 結果表示 —
Debug.Print “— アセンブリカスタムプロパティ検証終了 —”

If validationSuccess Then
MsgBox “すべての必須カスタムプロパティが正しく設定されています。”, vbInformation, “バリデーション完了”
Else
MsgBox “カスタムプロパティに未設定項目が検出されました。詳細はイミディエイトウィンドウを確認してください。” & vbCrLf & vbCrLf & missingProps, vbExclamation, “バリデーション完了(警告あり)”
End If

‘ — オブジェクト解放 —
Set swAssembly = Nothing
Set swModel = Nothing
‘ swApp は通常解放しない

End Sub

まとめ

SolidWorks VBA を用いたアセンブリのカスタムプロパティバリデーションは、製造プロセスの信頼性を劇的に向上させる強力な手段です。本稿では、単にコードを示すだけでなく、オブジェクトのライフサイクル管理、Windows API の活用、そしてレガシー環境における保守性といった、実践的な開発現場で直面するであろう課題に光を当てました。

これらの深遠な知識と、それを現場で活かすための実装力こそが、伝説的なチーフアーキテクトが求める「技術の真髄」です。この知見が、皆様の業務自動化プロジェクトの一助となれば幸いです。

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