こんにちは!SolidWorks VBAの世界へようこそ。
マクロの記録を卒業し、一歩進んだ自動化ツールを作ろうとしたとき、多くの人が最初にぶつかる「見えない壁」があります。それが「意図しないファイル(部品やアセンブリ)をマクロが勝手に操作して、エラーで止まる(最悪の場合はデータを壊してしまう)」という問題です。
その原因のほとんどは、コードの中で何気なく使われている `SldWorks.ActiveDoc`(現在見えているドキュメントを適当に掴む処理) にあります。
今回は、複数ファイルが開かれた複雑な環境でも、狙ったドキュメントだけを「ピンポイント」かつ「安全」に狙い撃ちして操作する、プロフェッショナルなドキュメント制御手法を解説します。
ここをマスターすれば、あなたの書くSolidWorks VBAの安定性は劇的に向上します。一歩ずつ、一緒に学んでいきましょう!
—
なぜ `ActiveDoc` だけを使うのは危険なのか?
マクロの記録を行うと、SolidWorksはよくこのようなコードを吐き出します。
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc ‘ ← これが潜伏するバグの温床!
`ActiveDoc` は「いま、ユーザーの画面で一番手前にあるドキュメント」を無条件で取得します。
一見シンプルで便利そうに見えますが、実務の現場では以下のような悲劇を引き起こします。
1. ユーザーの誤操作
マクロの実行処理(重いアセンブリの処理など)に数秒かかっている間、ユーザーが「あ、ちょっと別の部品を開いて確認しよう」と画面をクリックした瞬間、`ActiveDoc` はその「別の部品」にすり替わってしまいます。
2. バックグラウンド処理での混乱
アセンブリを開くと、内部的には多くの子部品(パーツ)が裏でロードされます。この読み込みのタイミングによって、マクロが「アセンブリを操作しているつもりなのに、なぜか子部品のドキュメントを掴んでしまっていた」という事故が起こります。
意図しないドキュメントに対して「カット押し出し」や「プロパティ書き換え」を実行してしまったら……想像するだけで冷や汗が出ますよね。
だからこそ、プロの開発者は「画面に見えているもの」を信じるのではなく、「メモリ上にロードされているドキュメントのリストから、名前を指定して直接ハンドル(操作権)を掴み取る」 という方法をとります。
—
安全なドキュメント制御を叶える「2つの武器」
安全な切り替えを実現するために、SolidWorks APIが用意してくれている強力な仕組みが2つあります。
1. DocumentCollection(ドキュメントの巡回走査)
SolidWorksが現在メモリ上に開いているすべてのファイルを、上から順番に「あなた誰ですか?」と聞いて回る仕組みです。
`SldWorks.GetFirstDocument` と `ModelDoc2.GetNext` というAPIを組み合わせて、お目当てのファイル名を持つドキュメントを探し出します。
2. SldWorks.ActivateDoc3
狙ったファイルを、安全かつ確実に「アクティブ(最前面で操作可能な状態)」にするメソッドです。
古い `ActivateDoc2` や `ActivateDoc` よりもエラーハンドリング(失敗したときの検知)が厳密に設計されており、現在のSolidWorks APIにおける標準的なアプローチです。
—
【実践コード】安全にドキュメントを探索して切り替えるテンプレート
では、具体的なコードを見てみましょう。
このコードは、「指定した名前のファイルが既に開かれているかを調べ、開かれていればそれを安全にアクティブにする」という、実務でそのまま使える極めて堅牢な関数(Subプロシージャ)です。
コピペして、お手元の標準モジュールに貼り付けて動かしてみてください。
Option Explicit
”’
”’
”’ 対象のファイル名(例: “bracket.sldprt” や “assembly1.sldasm”)
Public Sub SafeActivateDocument(ByVal targetFileName As String)
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim foundModel As SldWorks.ModelDoc2
Dim currentTitle As String
‘ SolidWorksのインスタンスを取得
Set swApp = Application.SldWorks
‘ 1. 現在メモリにロードされている最初のドキュメントを取得
Set swModel = swApp.GetFirstDocument
‘ ターゲットが見つかったかを示すフラグの代わりとして、オブジェクト変数を使う
Set foundModel = Nothing
‘ 2. 開かれているすべてのドキュメントをループで走査する
Do While Not swModel Is Nothing
‘ ドキュメントのタイトル(ファイル名)を取得
‘ ※ GetTitleは拡張子がつかない場合や、[読み取り専用]などの文字列が含まれることがあるため、
‘ 実務では GetPathName からファイル名を取り出すのがより確実です。
currentTitle = swModel.GetTitle
‘ 大文字・小文字を区別せずに比較するため、LCase関数を使用
If InStr(1, LCase(currentTitle), LCase(targetFileName), vbTextCompare) > 0 Then
‘ 合致するドキュメントが見つかった!
Set foundModel = swModel
Exit Do ‘ ループを抜ける
End If
‘ 次のドキュメントへ移動
Set swModel = swModel.GetNext
Loop
‘ 3. 結果に応じて処理を分岐
If foundModel Is Nothing Then
‘ 指定されたファイルが開かれていなかった場合
MsgBox “エラー: 「” & targetFileName & “」はSolidWorksで開かれていません。”, vbExclamation, “ドキュメント未検出”
Exit Sub
End If
‘ 4. 見つかったドキュメントを安全にアクティブ化する
Dim errors As Long
Dim activatedDoc As SldWorks.ModelDoc2
‘ ActivateDoc3 の引数:
‘ 引数1: 対象のドキュメント名 (パスを含まないタイトル名でも可)
‘ 引数2: アクティブ化する際に再構築(Rebuild)するかどうか (True = する, False = しない)
‘ 引数3: オプション (swActivateDocOptions_Silent = 1 を指定すると、警告ダイアログ等を非表示にできる)
‘ 引数4: エラーを受け取る変数
Set activatedDoc = swApp.ActivateDoc3( _
foundModel.GetTitle, _
True, _
swActivateDocOptions_e.swActivateDoc_Silent, _
errors)
‘ アクティブ化が成功したかチェック
If activatedDoc Is Nothing Or errors <> 0 Then
MsgBox “ドキュメントの切り替えに失敗しました。エラーコード: ” & errors, vbCritical, “エラー”
Else
MsgBox “「” & activatedDoc.GetTitle & “」を安全にアクティブにしました!”, vbInformation, “成功”
End If
End Sub
‘ — テスト呼び出し用コード —
Sub Test()
‘ ※実際にSolidWorksで開いているファイル名(拡張子含む)に書き換えて実行してください
Call SafeActivateDocument(“Part1.SLDPRT”)
End Sub
—
コードのポイントを徹底解説!
このコードには、初心者を脱出するための重要なエッセンスが散りばめられています。ポイントを絞って解説しますね。
① `GetFirstDocument` と `GetNext` による「数珠つなぎ」の走査
SolidWorksの中にロードされているドキュメントは、メモリ上で「数珠つなぎ(リンクドリスト)」のように保持されています。
[最初のドキュメント] ──(GetNext)──> [2番目のドキュメント] ──(GetNext)──> [なし(Nothing)]
これを `Do While Not swModel Is Nothing` のループを使って、端から端まで漏れなくチェックしています。この手法を使えば、画面上に表示されていない(裏で非表示で開かれている)ドキュメントであっても、正確に捕捉することができます。
② `LCase` と `InStr` による安全な名前比較
Windowsのファイルシステムは「大文字・小文字」を区別しませんが、VBAの単純な比較(`=`)はデフォルトで厳密に区別してしまいます。
例えば、ユーザーが `part1.sldprt` と入力したのに、実際のファイルが `PART1.SLDPRT` だった場合、単純な `=` 比較では不一致になってしまいます。
そこで、双方を `LCase`(すべて小文字に変換)した上で比較する工夫を施しています。
③ `ActivateDoc3` の引数設計
これが本テーマの主役です。
Set activatedDoc = swApp.ActivateDoc3(Name, Rebuild, Option, Errors)
- 第一引数(Name): アクティブにしたいドキュメントの「タイトル(ファイル名)」を渡します。
- 第三引数(Option): ここに `swActivateDoc_Silent` を指定するのがプロの技です。もしファイルを開く際や切り替える際に、ちょっとした警告や確認ダイアログ(「再構築しますか?」など)が出そうになっても、それを裏で静かに処理(サイレントモード)してマクロが途中で止まるのを防ぎます。
- 第四引数(Errors): 万が一切り替えに失敗した場合、その原因(ファイルが見つからない、メモリ不足など)が数値として格納されます。これがあるおかげで、「なぜ失敗したのか」を突き止めることができます。
—
まとめ:ここをクリアすれば、SolidWorks VBAの基本はバッチリ!
今回ご紹介した「ドキュメントの走査」と「安全なアクティブ化」は、一見すると少し遠回りで難しく思えるかもしれません。マクロの記録が書き出す1行のコードに比べたら、行数も多くなっています。
しかし、「意図したファイルだけを確実に操作する」という堅牢さこそが、ツールを実際に現場で使ってもらうための「信頼性」に直結します。
- 「いま見えているドキュメント」を信じるのではなく、「メモリにあるドキュメント」を自分で探しに行く。
- `ActiveDoc` から卒業し、`GetFirstDocument` や `ActivateDoc3` を使いこなす。
これができれば、複数の部品をアセンブリに組み立てたり、図面と3Dモデルを自動で行き来して一括PDF出力したりするような、高度な自動化プログラムもバグなしで美しく組めるようになります。
まずは開いている適当なパーツで `Test()` を走らせて、その確実な動きを実感してみてください。あなたのSolidWorks VBA開発が、より楽しく、よりプロフェッショナルなものになることを応援しています!
