データの秩序を設計せよ:SolidWorks図面一括変換・自動振り分けエンジンの構築
設計業務の自動化において、多くのエンジニアが「単一のファイルの変換」という小さな戦いに終始している。しかし、真のアーキテクトが向き合うべきは、設計完了後に発生する数千、数万のデータが、いかにして「管理可能な秩序」としてストレージに格納されるかという、システム全体のライフサイクルである。
図面(Drawing)ファイルをPDFとDXFへ同時に変換し、製品番号に基づいたディレクトリ構造へ自動的に仕分ける。この一見単純なタスクの裏には、COMオブジェクトのメモリリーク対策、ファイルシステムへの低レイテンシなアクセス、そして例外処理によるバッチ処理の堅牢性という、極めて高度な設計思想が求められる。
本稿では、単なる「スクリプト」ではない、業務基盤として耐えうる「変換エンジン」の設計手法を詳解する。
1. アーキテクチャ設計の要諦:メモリとライフサイクル
SolidWorks APIをバッチ処理で使用する際、最大の敵は「メモリの肥大化」と「プロセスの中断」である。SolidWorksは非常に重厚なCOMサーバーであり、ループ内で `ModelDoc2` オブジェクトを適切に解放(Release)せずに放置すれば、数百ファイル目の処理を待たずして、システムはリソース枯渇により沈黙する。
オブジェクトの明示的解放
VBAにおいて `Set obj = Nothing` は基本中の基本だが、プロフェッショナルは「オブジェクトのスコープ」を意識する。ループの内部で定義した変数、特に `swModel` や `swDrawing` などのインターフェースは、その反復の終わりに確実に破棄されなければならない。
ファイルシステムへの介入
ディレクトリの自動生成には、VBA標準の `MkDir` ではなく、`Scripting.FileSystemObject` (FSO) を採用すべきである。FSOは、ディレクトリの存在確認、階層構造の作成、パス操作において、Windows APIに近い信頼性と柔軟性を提供する。
2. 実装:高信頼性変換エンジンのコア・ロジック
以下に、実戦投入を想定したコード構造を示す。ここでは、製品番号をファイル名から抽出するロジック、ディレクトリの動的生成、そしてPDF/DXFの同時出力プロセスを統合している。
' ==============================================================================
' Module: DrawingExportEngine
' Description: SolidWorks Drawing Batch Converter (PDF & DXF)
' Author: Legendary Chief Architect
' ==============================================================================
Option Explicit
' Microsoft Scripting Runtime (FSO) への参照設定を推奨
' Microsoft VBScript Regular Expressions 5.5 (Regex) への参照設定を推奨
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim fileList As Collection
Dim filePath As Variant
Dim targetRoot As String
On Error GoTo ErrorHandler
Set swApp = Application.SldWorks
If swApp Is Nothing Then
MsgBox "SolidWorksが起動していません。", vbCritical
Exit Sub
End If
' --- 設定領域 ---
' 出力先のルートディレクトリ
targetRoot = "C:\Output\Project_Alpha\"
' 処理対象の図面ファイルが格納されているフォルダ
Dim sourceFolder As String
sourceFolder = "C:\Design\Drawings\"
' ----------------
' ファイルリストの取得(実際にはフォルダ内走査ロジックを実装)
Set fileList = GetFileList(sourceFolder)
Debug.Print "Engine Started. Total files: " & fileList.Count
' メイン・ループ
For Each filePath In fileList
' 各ファイルに対する独立したプロセスを実行
ProcessSingleDrawing swApp, CStr(filePath), targetRoot
' OSへの制御を戻し、メモリ解放の猶予を与える
DoEvents
Next filePath
MsgBox "全工程が完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
End Sub
''' <summary>
''' 個別の図面ファイルに対する変換・振り分けプロセス
''' </summary>
Private Sub ProcessSingleDrawing(ByRef swApp As SldWorks.SldWorks, ByVal fullPath As String, ByVal rootDir As String)
Dim swModel As SldWorks.ModelDoc2
Dim swDrawing As SldWorks.DrawingDoc
Dim fileName As String
Dim productID As String
Dim destinationDir As String
Dim exportStatus As Boolean
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
' 図面を開く(読み取り専用でメモリ負荷を軽減)
Set swModel = swApp.OpenDoc6(fullPath, swDocDRAWING, swOpenDocOptions_Silent, "", 0, 0)
If swModel Is Nothing Then
Debug.Print "Failed to open: " & fullPath
Exit Sub
End If
On Error GoTo 0
' 1. 製品番号の抽出 (例: "PART-12345-REV01.SLDDRW" -> "PART-12345")
' ここでは正規表現等を用いて、設計ルールに基づき厳格に抽出すること
productID = ExtractProductID(fso.GetBaseName(fullPath))
' 2. 出力先ディレクトリの構築と作成
destinationDir = rootDir & productID & "\"
If Not fso.FolderExists(destinationDir) Then
' 再帰的なディレクトリ作成が必要な場合は、自作のMakePath関数を使用
CreateRecursiveFolder fso, destinationDir
End If
' 3. PDF出力
exportStatus = SaveAsFormat(swModel, destinationDir & fso.GetBaseName(fullPath) & ".pdf", swDocExportData_PDF)
' 4. DXF出力 (図面全体または特定シートを指定)
exportStatus = SaveAsFormat(swModel, destinationDir & fso.GetBaseName(fullPath) & ".dxf", swDocExportData_DXF)
' --- ライフサイクル管理:極めて重要 ---
' オブジェクトを明示的に破棄し、メモリリークを防ぐ
swApp.CloseDoc swModel.GetTitle
Set swDrawing = Nothing
Set swModel = Nothing
Set fso = Nothing
Debug.Print "Successfully processed: " & productID
End Sub
''' <summary>
''' 指定したフォーマットでファイルを保存する抽象化レイヤー
''' </summary>
Private Function SaveAsFormat(ByRef swModel As SldWorks.ModelDoc2, ByVal savePath As String, ByVal formatType As Long) As Boolean
Dim swModelDocExt As SldWorks.ModelDocExtension
Dim errors As Long
Dim warnings As Long
Set swModelDocExt = swModel.Extension
' SaveAs3 または Extension.SaveAs を使用
' formatType に基づき、PDF/DXFの動作を制御
Select Case formatType
Case swDocExportData_PDF
' PDF出力時のオプション設定(必要に応じて)
Case swDocExportData_DXF
' DXF出力時のオプション設定(レイヤー、単位など)
End Select
Dim result As Boolean
result = swModelDocExt.SaveAs(savePath, swSaveAsCurrentVersion, swSaveAsOptions_Silent, Nothing, errors, warnings)
SaveAsFormat = result
End Function
' --- 以下、補助関数群 (実装詳細は設計思想に準拠) ---
Private Function ExtractProductID(ByVal rawName As String) As String
' 正規表現を用いて製品番号を抽出するロジック
' 例: "ABC-9999-01" から "ABC-9999" を取り出す
' ここでは簡略化のため、ハイフンによる分割を想定
Dim parts() As String
parts = Split(rawName, "-")
If UBound(parts) >= 1 Then
ExtractProductID = parts(0) & "-" & parts(1)
Else
ExtractProductID = rawName
End If
End Function
Private Sub CreateRecursiveFolder(fso As Object, ByVal path As String)
' 階層が深くても確実にディレクトリを作成する再帰的実装
If Not fso.FolderExists(fso.GetParentFolderName(path)) Then
CreateRecursiveFolder fso, fso.GetParentFolderName(path)
End If
If Not fso.FolderExists(path) Then fso.CreateFolder path
End Sub
' 定数の定義 (SolidWorks APIの列挙型を模倣、または参照設定を使用)
Private Const swDocDRAWING As Long = 3
Private Const swOpenDocOptions_Silent As Long = 1
Private Const swSaveAsCurrentVersion As Long = 0
Private Const swSaveAsOptions_Silent As Long = 1
Private Const swDocExportData_PDF As Long = 1 ' 実際はAPI定義に従う
Private Const swDocExportData_DXF As Long = 2
3. プロフェッショナルのための極限知見
Windows APIによるファイル操作の高速化
もし、数万件のファイルを扱う場合、FSOのオーバーヘッドすら無視できなくなる。その際は、`kernel32.dll` の `CreateDirectory` や `FindFirstFile` を直接呼び出すことで、システムコールの回数を最小化し、スループットを極限まで高めることができる。しかし、これは「堅牢性」を犠牲にする諸刃の剣であることを忘れてはならない。
DXF出力時の「シート選択」の罠
SolidWorksのDXF出力は、現在アクティブなシート、あるいは全てのシートを対象にするかによって、出力結果が劇的に変わる。バッチ処理においては、`swDrawing.ActivateSheet` を用いて、意図したシート(通常は正面図のあるシート)を明示的に制御してから `SaveAs` を実行する。これを怠ると、出力されたDXFが空のシートや、意図しない構成図を含んでしまうリスクがある。
エラーハンドリングの階層化
本エンジンでは、`ProcessSingleDrawing` 内で `On Error Resume Next` を局所的に使用している。これは、「一つのファイルの失敗が、全体のプロセスを停止させてはならない」という設計思想に基づいている。個別のファイルエラーはログ(`Debug.Print` またはファイル出力)に記録し、次のファイルへと処理を継続させる。これこそが、実務に耐えうるエンジニアリングである。
結論
自動化とは、単に作業を楽にすることではない。それは、「データの整合性を保ちつつ、ヒューマンエラーを排除した構造的なプロセスを構築すること」である。
メモリ管理、ファイルシステムの制御、そして例外への備え。これらを疎かにした自動化は、単なる「不安定なスクリプト」に過ぎない。本稿で示したアーキテクチャを基盤に、貴殿の設計環境に真の秩序をもたらしてほしい。
