【実務・中級編】【実務中級】コンポーネントの材質(Material)と質量特性(Mass Properties)をVBAでアセンブリ一括取得しExcel品質レポートを出力 – SolidWorks VBA解析バイブル

スポンサーリンク

【実務中級】コンポーネントの材質と質量特性をVBAでアセンブリ一括取得しExcel品質レポートを出力

開発現場でこんな絶望を味わったことはないか?

「大規模アセンブリの総重量と重心位置を確認したいのに、変更のたびに各パーツを開いてプロパティを確認し、手作業でExcelに転記している……」
「材質が未設定の部品が紛れ込んでいて、最終的な重量計算が全くあてにならない……」

手作業による転記ミスは、設計ミスに直結する。そして、SolidWorks標準の質量特性レポート機能だけでは、社内フォーマットに合わせた「重量配分チェックシート」をダイレクトに出力することはできない。

今回は、SolidWorks VBAを駆使して、アセンブリ内の全コンポーネントの「階層構造」「材質」「質量」「重心位置」をミリ秒単位で一括抽出。さらに、Excelを背後で自動制御して、そのまま提出可能な品質管理レポートとして出力する「プロダクションコード(実務レベルの堅牢なコード)」を伝授する。

中途半端なサンプルコードでお茶を濁す気はない。メモリリークを防ぎ、巨大アセンブリでもフリーズしないための「SolidWorks APIの急所」をすべて公開しよう。

—

1. 堅牢なアセンブリ走査における3大鉄則

SolidWorks VBAでアセンブリを扱う際、素人が書いたコードは必ず「巨大アセンブリを開いた瞬間にフリーズする」か「メモリリークでExcelごとクラッシュする」のどちらかを迎える。現場で生き残るための設計思想を頭に叩き込んでほしい。

① 仮想コンポーネント(Virtual Component)と非表示部品のハンドリング

アセンブリには、外部ファイルとして存在しない「仮想コンポーネント」や、コンフィギュレーションで「消去(Suppressed)」されている部品が混在する。これらを無条件で処理しようとすると、`Nothing`参照による実行時エラー(24番など)でマクロが即死する。

② 再帰処理(Recursive)による全階層の完全捕捉

アセンブリの中にサブアセンブリがあり、さらにその中にパーツがある……という多重構造を突破するには、再帰関数(自分自身を呼び出す関数)の設計が不可欠だ。スタックオーバーフローを起こさないスマートな脱出条件の設定がキモとなる。

③ Excelオブジェクトの完全解放(Marshal.ReleaseComObjectのVBA版思考)

VBAからExcelを操作する場合、`CreateObject(“Excel.Application”)`を実行したプロセスは、コード終了後もメモリ上に残りがちだ。これを防ぐためには、生成したRangeやWorksheetの参照を確実に切り、プロセスを綺麗に掃除(クリーンアップ)する作法が絶対条件となる。

—

2. 【プロダクションコード】一括集計&Excelレポート自動生成マクロ

以下のコードは、現在アクティブなSolidWorksのアセンブリからデータを吸い上げ、デスクトップに綺麗にフォーマットされたExcelレポートを生成する。

そのままコピー&ペーストし、VBAエディタの標準モジュールに貼り付けて実行してほしい。

Option Explicit

‘ ==============================================================================
‘ 処理名: アセンブリ質量特性一括抽出 & Excel品質レポート自動生成ツール
‘ 備考: SolidWorks 2021以降推奨 / 早期バインド(要参照設定)または遅延バインド対応
‘ ==============================================================================
Sub ExportAssemblyMassPropertiesToExcel()

Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssDoc As SldWorks.AssemblyDoc

‘ 1. SolidWorks アプリケーションの取得
Set swApp = Application.SldWorks
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。”, vbCritical, “致命的エラー”
Exit Sub
End If

Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “エラー”
Exit Sub
End If

‘ ドキュメントタイプがアセンブリ(swDocumentTypes_e.swDocASSEMBLY = 2)かチェック
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “対象ドキュメントはアセンブリではありません。”, vbExclamation, “警告”
Exit Sub
End If

Set swAssDoc = swModel

‘ 2. データ格納用動的配列の準備 (Index, 階層, 名称, 材質, 質量(kg), 重心X, 重心Y, 重心Z)
Dim reportData() As Variant
ReDim reportData(1 To 1, 1 to 7)
Dim dataCount As Long
dataCount = 0

‘ 処理開始のトースト通知的メッセージ(ステータスバー表示)
swApp.SendMsgToUser2 “アセンブリ構造の解析を開始します…”, 0, 0
swModel.Extension.SetUserPreferenceToggle swUserPreferenceToggle_e.swInteractiveMode, False

‘ 3. 再帰処理によるコンポーネント走査の実行
Dim rootComp As SldWorks.Component2
Set rootComp = swAssDoc.GetRootComponent3(True)

If Not rootComp Is Nothing Then
Call TraverseComponent(rootComp, 1, reportData, dataCount)
End If

‘ インタラクティブモード復帰
swModel.Extension.SetUserPreferenceToggle swUserPreferenceToggle_e.swInteractiveMode, True

If dataCount = 0 Then
MsgBox “有効なコンポーネントが見つかりませんでした。”, vbInformation, “終了”
Exit Sub
End If

‘ 4. Excel出力処理の開始
Dim xlApp As Object
Dim xlWb As Object
Dim xlWs As Object

On Error GoTo ExcelError
Set xlApp = CreateObject(“Excel.Application”)
xlApp.Visible = False
xlApp.ScreenUpdating = False

Set xlWb = xlApp.Workbooks.Add
Set xlWs = xlWb.Sheets(1)
xlWs.Name = “重量配分チェックシート”

‘ ヘッダーの構築
With xlWs
.Cells(1, 1).Value = “【設計検証】アセンブリ重量配分レポート”
.Cells(1, 1).Font.Size = 16
.Cells(1, 1).Font.Bold = True

.Cells(2, 1).Value = “対象ファイル: ” & swModel.GetPathName
.Cells(3, 1).Value = “生成日時: ” & Format(Now, “yyyy/mm/dd hh:nn:ss”)

Dim headers As Variant
headers = Array(“階層”, “コンポーネント名”, “設定名”, “材質”, “質量 (kg)”, “重心 X (mm)”, “重心 Y (mm)”, “重心 Z (mm)”)

Dim i As Long
For i = LBound(headers) To UBound(headers)
.Cells(5, i + 1).Value = headers(i)
Next i

‘ ヘッダー装飾
With .Range(.Cells(5, 1), .Cells(5, UBound(headers) + 1))
.Interior.Color = RGB(41, 128, 185)
.Font.Color = RGB(255, 255, 255)
.Font.Bold = True
.HorizontalAlignment = -4108 ‘ 中央揃え
End With

‘ データ流し込み
.Range(.Cells(6, 1), .Cells(6 + dataCount – 1, UBound(headers) + 1)).Value = reportData

‘ 合計行の追加
Dim lastRow As Long
lastRow = 5 + dataCount
.Cells(lastRow + 1, 4).Value = “総重量合計:”
.Cells(lastRow + 1, 4).Font.Bold = True
.Cells(lastRow + 1, 5).Formula = “=SUM(E6:E” & lastRow & “)”
.Cells(lastRow + 1, 5).Font.Bold = True

‘ 罫線とオートフィット
Dim dataRange As Object
Set dataRange = .Range(.Cells(5, 1), .Cells(lastRow + 1, UBound(headers) + 1))
dataRange.Borders.LineStyle = 1 ‘ 連続線
.Columns.AutoFit
End With

‘ デスクトップに保存
Dim desktopPath As String
desktopPath = CreateObject(“WScript.Shell”).SpecialFolders(“Desktop”) & “\”
Dim saveFileName As String
saveFileName = desktopPath & “WeightReport_” & Format(Now, “yyyymmdd_hhnnss”) & “.xlsx”

xlWb.SaveAs saveFileName
xlApp.ScreenUpdating = True
xlApp.Visible = True

MsgBox “レポートの出力が完了しました!” & vbCrLf & saveFileName, vbInformation, “成功”

CleanUp:
Exit Sub

ExcelError:
If Not xlApp Is Nothing Then xlApp.ScreenUpdating = True
MsgBox “Excel出力中にエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
Resume CleanUp
End Sub

‘ ==============================================================================
‘ 内部関数: コンポーネント再帰走査
‘ ==============================================================================
Private Sub TraverseComponent(ByVal swComp As SldWorks.Component2, ByVal level As Long, ByRef dataArr() As Variant, ByRef cnt As Long)

Dim vChildComps As Variant
Dim i As Long

‘ 非表示(Suppressed)または除外すべきコンポーネントのスキップ
If swComp.GetSuppression = swComponentSuppressionState_e.swComponentSuppressed Then Exit Sub
If swComp.IsEnvelope Then Exit Sub ‘ 仮想・エンベロープ等は除外

‘ パーツドキュメントまたはサブアセンブリのモデル取得
Dim swChildModel As SldWorks.ModelDoc2
Set swChildModel = swComp.GetModelDoc2()

If Not swChildModel Is Nothing Then
cnt = cnt + 1
ReDim Preserve dataArr(1 To cnt, 1 To 8)

‘ 1. 階層
dataArr(cnt, 1) = level
‘ 2. コンポーネント名
dataArr(cnt, 2) = swComp.Name2
‘ 3. コンフィギュレーション名
dataArr(cnt, 3) = swComp.ConfigurationName

‘ 4. 材質の取得
Dim materialName As String
Dim databaseName As String
materialName = swChildModel.GetMaterialName(databaseName)
If materialName = “” Then
dataArr(cnt, 4) = “【未設定】”
Else
dataArr(cnt, 4) = materialName & ” (” & databaseName & “)”
End If

‘ 5-8. 質量特性の取得 (MassPropertiesオブジェクトの活用)
Dim swMassProp As SldWorks.MassProperty
Set swMassProp = swChildModel.Extension.CreateMassProperty()

If Not swMassProp Is Nothing Then
‘ アセンブリ文脈でのトランスフォームを考慮する場合、ComponentからMassPropを取るかModelDocから取るか要件次第。
‘ 今回はパーツ単体の物理特性+コンポーネント単位の質量を取得
swMassProp.UseSystemUnits = True ‘ ドキュメント単位系を使用

dataArr(cnt, 5) = Round(swMassProp.Mass, 4) ‘ 質量 (kg)

Dim vCenterOfMass As Variant
vCenterOfMass = swMassProp.CenterOfMass
If Not IsEmpty(vCenterOfMass) Then
dataArr(cnt, 6) = Round(vCenterOfMass(0) 1000, 2) ‘ X (mm変換)
dataArr(cnt, 7) = Round(vCenterOfMass(1) 1000, 2) ‘ Y (mm変換)
dataArr(cnt, 8) = Round(vCenterOfMass(2) 1000, 2) ‘ Z (mm変換)
End If
End If
End If

‘ 子コンポーネントの有無を確認し、再帰呼び出し
vChildComps = swComp.GetChildren
If Not IsEmpty(vChildComps) Then
For i = LBound(vChildComps) To UBound(vChildComps)
Call TraverseComponent(vChildComps(i), level + 1, dataArr, cnt)
Next i
End If

End Sub

—

3. チーフアーキテクトが教える、コードの急所とチューニング

上記のコードがなぜ「実務で使える」レベルなのか、その裏側にある技術的プライポイントを解説しよう。

配列の動的拡張(`ReDim Preserve`)の最適化思想

ループのたびにワークシートのセルを直接書き換えるアプローチは、COM通信のオーバヘッドが大きすぎて使い物にならない(いわゆる「カチカチ遅延現象」を引き起こす)。
このコードでは、一度VBA側の二次元配列(`reportData`)にすべてのデータをメモリ上で高速に蓄積し、最後に一度の命令でExcelのセル範囲へバルク転送(一括書き込み)している。この設計思想だけで実行速度が数十倍〜数百倍変わる。

材質未設定アラートの罠

実務で一番多いトラブルが「材質がアサインされていないパーツの存在」だ。
`swChildModel.GetMaterialName` が空文字を返した場合に、単にブランクにするのではなく、コード内であえて`【未設定】`という文字列を挿入するようにしている。これにより、Excel側で条件付き書式(未設定セルを赤くハイライト等)を組み合わせることで、設計ミスを視覚的に即座に検知できるようになる。

—

4. さらなる高みへ:現場で展開する際の拡張アイデア

このベーススクリプトを手に入れたあなたなら、現場の要求に合わせてさらにカスタマイズが可能だ。

  • カスタムプロパティ(図面枠情報など)の同時抽出:

`CustomPropertyManager` インターフェースを噛ませることで、「承認者」「設計者」「部品番号」などのメタデータを同時に吸い上げ、BOM(部品表)と直結した高精度なチェックシートに昇華できる。

  • PDF自動書き出しの連携:

Excel出力と同時に、アセンブリの軽量プレビュー(eDrawingsやPDF)をサイレントで同時生成するバッチ処理を組めば、社内ポータルへの自動アップロード基盤が完成する。

手作業による転記地獄から設計者を解放せよ。APIの挙動を掌握した者だけが、真の業務効率化という果実を手にすることができる。

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