【入門編】【アクティブ文書の罠】ActiveDocとDocumentCollectionの挙動の違いと意図したモデルを確実に掴む方法 – SolidWorks VBA解析バイブル

スポンサーリンク

こんにちは!SolidWorks自動化の世界へようこそ。
マクロの記録ボタンを押してコードを生成し、「よし、動いた!」と感動したのも束の間、いざ図面を2枚、3枚と開いた状態で実行した途端に、全く関係ないパーツが書き換わったり、謎の「Object variable not set(オブジェクト変数が設定されていません)」エラーに直面したり……そんな冷や汗をかいた経験はありませんか?

「マクロの記録」が吐き出すコードの主役、それは`ActiveDoc`です。
今回は、複数ドキュメントが乱立する戦場(CAD画面)において、この`ActiveDoc`が抱える致命的な罠と、私たちが意図したモデルを確実に、そしてエレガントに掴み取るための「プロの極意」を伝授します。

ここをクリアすれば、あなたのVBAスキルは「記録のモグラ叩き」から卒業し、揺るぎないエンジニアリングの領域に到達します。さあ、一緒に扉を開きましょう!

—

1. なぜ「ActiveDoc」は裏切るのか?(アクティブ文書の罠)

SolidWorksを立ち上げ、複数の部品やアセンブリ、図面を開いている状態を想像してください。
画面の最前面に表示され、ユーザーが今まさにマウスでクリックしているウィンドウ――これが「アクティブ文書(Active Document)」です。

マクロの記録を行うと、大体こんなコードが出力されます。

Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2

Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc ‘ ← ここに罠がある!

一見、何の問題もないように見えますよね。しかし、ここに重大な罠があります。

  • 罠の正体①:ユーザーの気まぐれ

マクロの実行ボタンを押すコンマ数秒前に、ユーザーが別のウィンドウをチラッとクリックしてアクティブを切り替えたら? ターゲットではないモデルに対して処理が走り、最悪の場合、大切な設計データを意図せず上書きしてしまうリスクがあります。

  • 罠の正体②:そもそも「何もアクティブではない」瞬間

SolidWorksを起動した直後や、すべてのドキュメントを閉じている状態、あるいはバックグラウンドで処理を行っている最中には、`ActiveDoc`は`Nothing`(空っぽ)を返します。ここで `swModel.Extension` などのプロパティを叩こうものなら、容赦なく実行時エラー(24番:オブジェクト変数または With ブロック変数が設定されていません)が炸裂します。

「今、ユーザーがどの画面を見ているか」という曖昧な状態に依存するコードは、実務の現場では使い物になりません。プロは、アクティブ文書という「幻」を追いかけません。確実にそこに存在する「実体」を掴みにいきます。

—

2. 確実なアプローチ:「DocumentCollection」という思想

では、どうすればいいのか?
SldWorksアプリケーションには、現在メモリ上にロードされているすべてのドキュメントを管理する仕組みがあります。それが`GetDocuments`メソッド、いわゆるドキュメントコレクション(Document Collection)の概念です。

これを使うと、「今開いているすべてのモデルの配列」をダイレクトに取得できます。つまり、アクティブかどうかなんて関係なく、「名前がこれと一致するドキュメント」「一番新しく開かれたドキュメント」といった条件で、狙い撃ちできるのです。

—

3. 【実践】意図したモデルを確実に掴むベストプラクティス

ここからは、現場でそのまま使える実用的なコードを見ていきましょう。
「現在アクティブなドキュメントの安全な取得」から、「ファイル名指定での確実なキャッチ」までを網羅したテンプレートです。

パターンA:安全なActiveDocの取得(エラーハンドリング付き)

どうしてもアクティブ文書を対象にしたい場合でも、`Nothing` チェックと「本当にモデルが開かれているか」の型チェックを行うのがプロの作法です。

Option Explicit

Sub GetActiveModelSafely()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2

Set swApp = Application.SldWorks

‘ 1. SldWorksアプリケーション自体の取得確認
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。”, vbCritical
Exit Sub
End If

‘ 2. アクティブドキュメントの取得
Set swModel = swApp.ActiveDoc

‘ 3. 【最重要】何も開いていない場合のガード節
If swModel Is Nothing Then
MsgBox “現在、アクティブなドキュメントはありません。” & vbCrLf & _
“モデルを開いてから実行してください。”, vbExclamation
Exit Sub
End If

‘ — ここから安全な処理 —
MsgBox “現在操作中のモデル: ” & swModel.GetTitle, vbInformation, “取得成功”

End Sub

パターンB:ファイル名を指定して確実にドキュメントを掴む(DocumentCollectionの活用)

「複数ウィンドウが開いていても、特定のパーツ(例: “bracket.sldprt”)を絶対に操作したい!」という場合は、開かれているドキュメント群をループして検索します。

Option Explicit

Sub GetSpecificModelByName()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim vDocs As Variant
Dim i As Long
Dim targetFileName As String
Dim isFound As Boolean

Set swApp = Application.SldWorks
targetFileName = “bracket.sldprt” ‘ 狙い撃ちしたいファイル名
isFound = False

‘ メモリ上にロードされている全ドキュメントの配列を取得
vDocs = swApp.GetDocuments

If IsEmpty(vDocs) Then
MsgBox “ドキュメントが1つも開かれていません。”, vbExclamation
Exit Sub
End If

‘ 配列をループして目的のモデルを探す
For i = LBound(vDocs) To UBound(vDocs)
Set swModel = vDocs(i)

‘ 取得したドキュメントのタイトル(ファイル名)が一致するか比較
‘ ※ 拡張子の大文字小文字を区別しない場合は LCase等で調整してください
If LCase(swModel.GetTitle) = LCase(targetFileName) Then
isFound = True
Exit For ‘ 見つかったらループを抜ける
End If
Next i

‘ 結果の判定
If isFound Then
‘ 目的のモデルを確実に掴んだ状態で処理を実行
MsgBox “ターゲットを捕捉しました: ” & swModel.GetTitle, vbInformation

‘ 例:アクティブウィンドウを強制的にこれに切り替える場合
swApp.ActivateDoc3 swModel.GetTitle, False, 0, 0

Else
MsgBox “指定されたファイル ‘” & targetFileName & “‘ が開かれていません。”, vbCritical
End If

End Sub

—

4. エンジニアからのワンポイント・アドバイス

SolidWorks VBAのオブジェクトモデルにおいて、`ModelDoc2` はすべての基本(パーツ `PartDoc`、アセンブリ `AssemblyDoc`、図面 `DrawingDoc` の親クラス)です。

だからこそ、「どのモデルを操作しているのか」が曖昧なコードは、巨大なアセンブリを破壊する大惨事に繋がりかねません。

1. `ActiveDoc` は「オマケ」程度に捉える(単一テスト用と割り切る)
2. 実務では `GetDocuments` やファイル名指定で確実にオブジェクトをバインドする
3. 処理の最初とオブジェクト取得直後には必ず `If obj Is Nothing` のガード節を入れる

この3つを徹底するだけで、あなたの書くマクロの信頼性はプロ基準へと劇的に跳ね上がります。

ここをクリアすれば、SolidWorks VBAの基本はバッチリです!
ぜひ明日の業務から、安全で堅牢なコードを組み立ててみてくださいね。それでは、また次回の極限知見でお会いしましょう!

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