「動けばいい」マクロを卒業せよ。図面データ一括更新を支える、堅牢な自動化エンジニアリングの極意
現場のエンジニアが「図面の表題欄を書き換える作業が面倒だ」と言い出したとき、初心者はこう答える。
「簡単なマクロを書いて、一括で書き換えればいいじゃないですか」
しかし、プロのアーキテクトはこう問い返す。
「そのマクロは、設計者が勝手にノートを追加したり、名前を変えたりしても壊れないか? 100枚の図面を処理中に1枚のファイルが読み取り専用だったら、それまでの処理はどうなる? メモリリークでSolidWorksが落ちるリスクは計算しているか?」
単なる「コピペで動くコード」は、誰でも書ける。しかし、実務の最前線で、数千枚の図面を、ミスなく、高速に、安全に処理できる「プロダクション・グレード(製品品質)」のツールを書ける者は極めて少ない。
本記事では、図面シート上の「承認欄」や「改訂日」といった特定のテキストノートを一括更新するツールを題材に、「壊れにくく、メンテナンスしやすい」自動化ツールの設計思想を伝授する。
1. 設計思想:なぜ「ノートの検索」は失敗するのか
多くの初心者が陥る罠は、ノートを「インデックス(何番目のノートか)」や「現在の文字列(”承認:” という文字を探す)」で特定しようとすることだ。
これは極めて危険な設計である。
- インデックス指定: 設計者が図面に新しい注釈を一つ追加しただけで、番号がズレて、全く関係のない箇所を書き換える致命的なバグを引き起こす。
- 文字列一致: 「承認:」という文字を検索対象にすると、設計者が「承認者:」と表記を変えた瞬間に、マクロは「対象なし」と判断して沈黙する。
アーキテクトの解法:ノートへの「名前」の付与
SolidWorks APIにおいて、最も堅牢な識別方法は、ノート自体に「名前(Name)」を定義しておくことである。
SolidWorksのプロパティマネージャーで、各ノートに `Note_Approval` や `Note_RevisionDate` といった一意の識別名を付与しておく。これにより、ノートの表示内容がどう変わろうとも、プログラムは確実に「そのノート」を捕捉できる。
2. プロダクション・コードの構造
優れた自動化ツールは、以下の3つのレイヤーに分離して設計すべきである。
1. Data Layer (データ供給部): ExcelやCSVから「どのファイルに」「何を」書き込むかのリストを取得する。
2. Logic Layer (制御部): ファイルのオープン、エラーハンドリング、保存、クローズのライフサイクルを管理する。
3. Driver Layer (実行部): SolidWorks APIを叩き、個別のノートを書き換える。
以下に、これらを高いレベルで統合した、実務に耐えうるVBAコードのテンプレートを示す。
実装例:Robust Drawing Updater
Option Explicit
' ==============================================================================
' 構成要素:
' 1. Dictionaryオブジェクトを使用するため、参照設定で "Microsoft Scripting Runtime"
' を有効にすることを強く推奨します。
' ==============================================================================
Sub Main()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
' --- 設定エリア ---
' 本来はExcel等から取得するが、ここではデモ用にハードコード
Dim targetFiles As Variant
targetFiles = Array("C:\Temp\Drawing1.SLDDRW", "C:\Temp\Drawing2.SLDDRW")
' 更新内容の定義 (Key: ノートの名前, Value: 書き込む内容)
Dim updateData As Object
Set updateData = CreateObject("Scripting.Dictionary")
updateData.Add "Note_Approval", "Chief Engineer"
updateData.Add "Note_RevDate", Date
' ------------------
Dim filePath As Variant
Dim successCount As Integer: successCount = 0
Dim errorCount As Integer: errorCount = 0
' プロセスの開始
Debug.Print "--- Automation Start ---"
For Each filePath In targetFiles
If UpdateDrawingText(swApp, CStr(filePath), updateData) Then
successCount = successCount + 1
Else
errorCount = errorCount + 1
End If
Next filePath
' 最終報告
MsgBox "処理完了" & vbCrLf & _
"成功: " & successCount & " 件" & vbCrLf & _
"失敗: " & errorCount & " 件", vbInformation
Debug.Print "--- Automation End ---"
End Sub
''' <summary>
''' 個別の図面ファイルを処理するコアロジック
''' </summary>
Function UpdateDrawingText(swApp As SldWorks.SldWorks, filePath As String, data As Object) As Boolean
Dim swModel As SldWorks.ModelDoc2
Dim swDraw As SldWorks.DrawingDoc
Dim swSheet As SldWorks.Sheet
Dim swView As SldWorks.View
Dim swNote As SldWorks.Note
Dim swAnn As SldWorks.Annotation
Dim key As Variant
Dim isUpdated As Boolean: isUpdated = False
On Error GoTo ErrorHandler
' 1. ファイルのオープン (読み取り専用を避けるため、通常モードで開く)
' 第3引数は、読み取り専用フラグ。実務では、ファイルがロックされている可能性を考慮。
Set swModel = swApp.OpenDoc6(filePath, swDocDRAWING, swOpenDocOptions_Silent, "", 0, 0)
If swModel Is Nothing Then
Debug.Print "Error: ファイルを開けません -> " & filePath
UpdateDrawingText = False
Exit Function
End If
Set swDraw = swModel
' 2. 図面内の全ビューを走査してノートを探す
' 図面には「シート自体」のビューと「配置されたビュー」がある。
' 全てのノートを網羅するため、Viewの階層を辿る。
Set swView = swDraw.GetFirstView ' これはSheet Viewを指す
Do While Not swView Is Nothing
Set swNote = swView.GetFirstNote
Do While Not swNote Is Nothing
Set swAnn = swNote.GetAnnotation
' ノートの「名前」に基づいて、更新が必要か判定
' swAnn.GetName は、プロパティマネージャーで設定した名前を取得する
Dim noteName As String
noteName = swAnn.GetName
If data.Exists(noteName) Then
' テキストの書き換え
swNote.SetText data(noteName)
isUpdated = True
End If
Set swNote = swNote.GetNext
Loop
Set swView = swView.GetNext
Loop
' 3. 変更がある場合のみ保存して閉じる
If isUpdated Then
swModel.Save3 swSaveAsOptions_Silent, 0, 0
Debug.Print "Success: 更新完了 -> " & filePath
Else
Debug.Print "Info: 更新対象なし -> " & filePath
End If
' 4. 後処理
swApp.CloseDoc swModel.GetTitle
UpdateDrawingText = True
Exit Function
ErrorHandler:
Debug.Print "Critical Error in " & filePath & ": " & Err.Description
If Not swModel Is Nothing Then swApp.CloseDoc swModel.GetTitle
UpdateDrawingText = False
End Function
3. エンジニアリング・ポイントの解説
このコードが、なぜ「単なるコピペ」を超えているのか。その理由は以下の設計に集約される。
① 階層的なノート探索 (View-based Traversal)
`swDraw.GetFirstView` から始まるループは、図面内の「シートビュー」および「配置されたすべてのビュー」を走査する。SolidWorksにおいて、ノートは特定の「View」に属している。この階層構造を正しく辿ることで、表題欄(Sheet View)にあるノートも、部品図(Drawing View)の中にある注釈も、漏れなく捕捉できる。
② `swAnn.GetName` による厳格な識別
ここが最大の肝だ。`swNote.GetText`(中身の文字)ではなく、`swAnn.GetName`(管理用の名前)を使用している。これにより、「中身が何であれ、名前が `Note_Approval` であるノートを更新する」という、意図に忠実な動作を実現している。
③ エラーハンドリングとリソース管理
`On Error GoTo ErrorHandler` を実装し、万が一ファイルが破損していたり、ネットワークエラーで開けなかったりしても、マクロ全体がクラッシュして停止しないようにしている。また、`swApp.CloseDoc` を確実に行うことで、メモリ上に「開いたままの図面」が蓄積し、SolidWorksが重くなる(あるいはクラッシュする)リスクを排除している。
④ パフォーマンスへの配慮
`swOpenDocOptions_Silent` を使用し、ダイアログボックス(「保存しますか?」などの警告)を抑制している。自動化において、ユーザーの入力を待つダイアログの出現は、自動化の完全な失敗を意味する。
4. 実務への応用:さらに高みを目指すなら
このツールをさらに進化させるためのロードマップを提示する。
- Excel連携: `UpdateDrawingText` の引数として、ExcelのRangeオブジェクトを渡すように拡張する。
- ログ出力: `Debug.Print` ではなく、実行結果をCSVやテキストファイルに書き出す機能を実装する。これにより、後から「どの図面が失敗したか」を監査できる。
- 差分チェック: `swNote.GetText` で現在の値を取得し、`data(noteName)` と比較して、「値が異なる場合のみ書き換える」ロジックにすれば、保存によるファイル更新日時(Modified Date)の無駄な変更を防げる。
結論
自動化とは、単に「手作業をコンピュータに肩代わりさせること」ではない。「不確実な手作業を、決定論的なプロセスへと変換すること」である。
「動く」コードを書く段階から、「管理できる」コードを書く段階へ。この視点の転換こそが、あなたを単なるユーザーから、信頼される自動化エンジニアへと進化させる。
