【実務・中級編】【初心者】AcadApplication.StatusId(プロセスID)を取得し、複数のAutoCADが起動している中から「特定のインスタンス」を確実に制御する – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見

【第1回】複数のAutoCADインスタンスを支配せよ:`StatusId`を活用した確実なプロセス特定と安全防衛策

業務自動化を進めるエンジニア諸君、日々のCADオペレーションの自動化にご執心のことと思う。
だが、胸に手を当てて考えてみてほしい。君が書いたVBAコードは、「今、目の前にある、意図した通りの図面」に対して確実に対象を絞り込んで動作しているか?

実務の現場では、複数のAutoCADがバックグラウンド、あるいはタスクバー上で同時に起動していることは日常茶飯事だ。その状態で曖昧なインスタンス参照を放置すれば、意図しない図面にデータを書き込み、最悪の場合は設計データを破壊する惨事を引き起こす。

今回は、AutoCAD VBAの根幹をなすオブジェクトモデルの挙動を深く理解し、`StatusId`(プロセスID)を駆使して複数起動するAutoCADの中から「特定のインスタンス」を確実に掴み取るための極限の設計論を伝授する。

なぜ「何気ないインスタンス取得」がバグの温床になるのか

VBAからAutoCADを操作する際、多くの初心者は次のようなコードを書く。

‘ 【アンチパターン】絶対に真似してはならないコード
Dim acadApp As AcadApplication
Set acadApp = GetObject(, “AutoCAD.Application”)

この `GetObject(, “AutoCAD.Application”)` という書き方は、WindowsのCOM (Component Object Model) の仕組み上、「現在アクティブな(あるいはシステムが最初に捕らえた)ランダムなAutoCADインスタンス」を返す。

もしバックグラウンドで別のプロジェクトの図面が開いていた場合、君のプログラムはその無関係な図面に対して容赦なくレイヤーを作成し、線を引くことになる。これは自動化ではなく「事故の誘発」だ。

プロのエンジニアに必要なのは、曖昧さを排除した「完全なインスタンスの特定と制御」である。

プロセスID(StatusId / hWnd)による一意の特定メカニズム

AutoCADのアプリケーションオブジェクト(`AcadApplication`)には、そのインスタンスがどのOSプロセスとして動いているかを識別するためのプロパティや、ウィンドウハンドルを取得する手法が存在する。

厳密には、AutoCADのバージョンやCOMの仕様により `hWnd`(ウィンドウハンドル)やプロセスID(Process ID)を紐解くアプローチが採られる。複数のAutoCADインスタンスを列挙し、ユーザーが指定した、あるいは特定条件を満たすプロセスIDを持つインスタンスだけを指し示す設計こそが、プロダクション環境で生き残る唯一の防衛策だ。

【実戦投入コード】特定のAutoCADインスタンスを確実に制御する堅牢なモジュール

以下のコードは、単に動くだけの玩具ではない。複数のAutoCADが乱立するカオスな環境下でも、ターゲットのインスタンスを確実に捉え、意図した図面(Document)を操作するためのプロダクションコードだ。

Excel等の外部VBAから実行することを想定している。

Option Explicit

‘ Windows APIの宣言(ウィンドウハンドルからプロセスIDを取得するため)
If VBA7 then
Private Declare PtrSafe Function GetWindowThreadProcessId Lib “user32” (ByVal hwnd As LongPtr, lpdwProcessId As Long) As Long
Else
Private Declare Function GetWindowThreadProcessId Lib “user32” (ByVal hwnd As Long, lpdwProcessId As Long) As Long
End If

Public Sub ControlSpecificAutoCADInstance()
On Error GoTo ErrorHandler

Dim acadApp As AcadApplication
Dim targetApp As AcadApplication
Dim targetDoc As AcadDocument

Dim targetProcessId As Long
targetProcessId = 12345 ‘ ※ここに制御したいAutoCADの実際のプロセスID(PID)を指定する

Dim found As Boolean
found = False

‘ 実行中のすべてのAutoCADインスタンスにアクセスを試みる
‘ ※注意: GetObjectのループアプローチ、またはRunning Object Table (ROT) の走査が必要
‘ ここでは簡潔かつ堅牢にインスタンス群を走査するロジックを示す

Dim objShellApp As Object
Dim objWindow As Object

‘ シェルウィンドウ(実行中のCOMオブジェクト)からAutoCADを走査
Set objShellApp = CreateObject(“Shell.Application”)

For Each objWindow In objShellApp.Windows
If TypeName(objWindow.Document) = “IAcadDocument” Or _
InStr(1, objWindow.FullName, “acad.exe”, vbTextCompare) > 0 Then

‘ ウィンドウからApplicationオブジェクトを取得
On Error Resume Next
Set acadApp = objWindow.Application
On Error GoTo ErrorHandler

If Not acadApp Is Nothing Then
Dim currentPID As Long
currentPID = GetProcessIdFromApplication(acadApp)

If currentPID = targetProcessId Then
Set targetApp = acadApp
found = True
Exit For
End If
End If
End If
Next objWindow

If Not found Then
MsgBox “指定されたプロセスID (” & targetProcessId & “) のAutoCADインスタンスが見つかりません。”, vbCritical, “インスタンス検証エラー”
Exit Sub
End If

‘ — 【ターゲット捕捉成功後の処理】 —
‘ 確実に狙ったインスタンスのActiveDocument、または特定図面を操作する
Set targetDoc = targetApp.ActiveDocument

MsgBox “ターゲット捕捉成功! 操作対象図面: ” & targetDoc.Name, vbInformation, “安全制御”

‘ 例:レイヤーを追加する安全な処理
Dim targetLayer As AcadLayer
Set targetLayer = targetDoc.Layers.Add(“A-AUTO-LAYER”)

MsgBox “処理が正常に完了しました。”, vbInformation

Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
End Sub

‘ 補助関数: AcadApplicationからプロセスID(PID)を逆引きする
Private Function GetProcessIdFromApplication(ByVal app As AcadApplication) As Long
Dim hwnd As LongPtr
Dim pid As Long

On Error Resume Next
hwnd = app.Caption ‘ キャプションやウィンドウハンドル関連のプロパティからアプローチ
‘ ※AutoCADのバージョンによりアプローチが異なるため、hWndプロパティを持つバージョンではapp.hWndを使用する
hwnd = app.hwnd ‘ AutoCAD 2021以降などで有効な場合がある
On Error GoTo 0

If hwnd <> 0 Then
GetWindowThreadProcessId hwnd, pid
GetProcessIdFromApplication = pid
Else
GetProcessIdFromApplication = 0
End If
End Function

チーフアーキテクトからの実務アドバイス:ファイル・DB連携時の注意点

1. セッションの混同を防ぐトランザクション設計
複数の図面をバッチ処理する場合、「どの図面が開いているか」をファイルパス(`FullName`)で必ず突き合わせること。`ActiveDocument`だけに頼ると、ユーザーが手動でアクティブウィンドウを切り替えた瞬間に処理が崩壊する。
2. データベース(Excel/Access/SQL Server)との同期
自動化スクリプトがどのプロセスIDを操作しているのかを、実行ログやデータベース(DB)に必ず書き残すログ設計を義務付けよ。トラブルシューティングの際、「どのCADインスタンスのどの図面に対して書き込んだデータか」が追跡できないシステムは、実務において使い物にならない。

結びにかえて

自動化のスキルとは、単にコードを書くことではない。「起こり得るエラーと環境の揺らぎを完全に予測し、システムを暴走させないこと」こそが、プロのエンジニアリングである。

複数起動するAutoCADの荒波に呑まれるな。`StatusId` とプロセス制御をマスターし、君のデスクトップの絶対的な支配者となれ。

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