【テクニカル・上級編】【初心者向け】AutoCADのシステム変数(SETVAR)をVBAで制御!OSNAPやPICKBOXの設定を自動で最適化する – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:システム変数制御のアンチパターンと「真の安全設計」

AutoCAD VBAの初学者が最初に直面する壁、そしてベテランですら時として見落とす罠が「システム変数の汚染」だ。

`OSNAP`(スナップ)、`PICKBOX`(選択ボックス)、`ORTHOMODE`(直交モード)。これらのシステム変数は、作図者の指先の感覚に直結する。もし、あなたの書いたマクロが異常終了したり、エラーハンドリングの不備によってこれらの設定を書き換えたまま沈黙したらどうなるか? 現場のオペレーターは「AutoCADが壊れた」と錯覚し、阿鼻叫叫の地獄絵図が展開されることだろう。

今回は、単なる `SetVariable` の使い方という退屈な解説ではない。オブジェクトのライフサイクル、COMのマーシャリングコスト、そして予期せぬクラッシュをも見越した「実戦で生き残るためのシステム変数制御アーキテクチャ」を授けよう。

1. なぜ `ThisDrawing.SetVariable` だけでは不十分なのか?

多くの解説書では、次のようなコードが平然と紹介されている。

‘ 【アンチパターン】よくある素朴な実装
Sub BadExample()
‘ システム変数を強制変更
ThisDrawing.SetVariable “OSMODE”, 16 ‘ 端点のみ
ThisDrawing.SetVariable “PICKBOX”, 5

‘ ここにメイン処理…

‘ 元に戻す
ThisDrawing.SetVariable “OSMODE”, 4133
ThisDrawing.SetVariable “PICKBOX”, 3
End Sub

このコードのどこが致命的なのか?
もし「ここにメイン処理…」の中で、ゼロ除算エラー、オブジェクトの参照エラー、あるいはユーザーによる `Ctrl + Break` による中断が発生した場合、後半の「元に戻す」コードには絶対に到達しない。

VBAの実行時エラーは、適切にトラップされなければその瞬間にスタックを巻き戻し、変数は書き換わったまま放置される。これが「システム変数の汚染」の正体である。

2. 障害耐性を持つ「RAII風」ステート管理パターン

C++の世界には RAII (Resource Acquisition Is Initialization) というイディオムがある。リソースの取得と解放をオブジェクトの寿命に結びつける手法だ。
VBAには厳密なデストラクタこそ存在しないが、「クラスモジュール」と「エラートラップの確実な実行(GoToクリーンアップ)」を組み合わせることで、これと同等の堅牢性を手に入れることができる。

ここでは、システム変数を退避・復元する専用の構造を構築する。

実装コード:堅牢なシステム変数マネージャー

まずは、標準モジュールまたはクラスモジュールを駆使し、確実に状態を復元する仕組みを実装する。実業務でそのまま使えるレベルの設計に落とし込んでいる。

Option Explicit

‘ ==============================================================================
ਤ 業務自動化アーキテクチャ:システム変数トランザクション管理
‘ ==============================================================================

Private Type SystemVariableState
VariableName As String
SavedValue As Variant
End Type

‘ 保持するシステム変数の最大数(必要に応じて拡張)
Private p_States() As SystemVariableState
Private p_Count As Long

‘ — トランザクションの開始(現在の値を退避し、新しい値を適用) —
Public Sub BeginTransaction(varName As String, newValue As Variant)
ReDim Preserve p_States(p_Count)

‘ 現在の値を安全に取得して退避
p_States(p_Count).VariableName = varName
p_States(p_Count).SavedValue = ThisDrawing.GetVariable(varName)

p_Count = p_Count + 1

‘ 新しい値を適用
ThisDrawing.SetVariable varName, newValue
End Sub

‘ — トランザクションの終了(スタックの逆順で確実に復元) —
Public Sub RollbackStates()
If p_Count = 0 Then Exit Sub

Dim i As Long
‘ 適用順とは逆に(LIFO構造で)復元する
For i = p_Count – 1 To 0 Step -1
On Error Resume Next ‘ 復元時の万が一の失敗をマスク(AutoCADのセッション保護)
ThisDrawing.SetVariable p_States(i).VariableName, p_States(i).SavedValue
On Error GoTo 0
Next i

p_Count = 0
Erase p_States
End Sub

これを呼び出すメインルーチン側では、以下のように「確実なクリーンアップパス」を担保する。

Sub EnterpriseBatchProcess()
Dim sysMgr As Object
Set sysMgr = New SystemVariableManager ‘ ※実際にはクラスモジュール名に合わせる

‘ エラーハンドリングの有効化
On Error GoTo ErrorHandler

‘ 1. トランザクション開始(OSNAPを端点のみ[16]に、PICKBOXを[5]に最適化)
sysMgr.BeginTransaction “OSMODE”, 16
sysMgr.BeginTransaction “PICKBOX”, 5
sysMgr.BeginTransaction “CMDECHO”, 0 ‘ コマンドのエコーバックを抑制してパフォーマンス向上

‘ ==========================================
‘ 2. メインの重たい一括処理
‘ ==========================================
Call ExecuteHeavyProcessing_Core

‘ 3. 正常終了時のクリーンアップ
sysMgr.RollbackStates
Set sysMgr = Nothing
Exit Sub

ErrorHandler:
‘ 4. 異常終了時も必ず設定を元の状態へ復元
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “AutoCAD VBA Engine”

If Not sysMgr Is Nothing Then
sysMgr.RollbackStates
Set sysMgr = Nothing
End If
End Sub

Private Sub ExecuteHeavyProcessing_Core()
‘ ここに実際の作図・編集ロジックが入る
‘ 例: 大量のエンティティ操作など
‘ わざとエラーを起こすテスト: Dim x As Integer: x = 1 / 0
End Sub

この設計であれば、いかなる例外が発生しようとも、AutoCADの環境は処理前の清浄な状態へと必ず巻き戻される。これがプロフェッショナルのコードだ。

3. パフォーマンスの極み:COMオブジェクトのマーシャリングとキャッシュ戦略

シニアエンジニアとして、もう一歩踏み込んだ最適化の知見を共有しよう。

`ThisDrawing.SetVariable` や `GetVariable` は、内部でAutoCADのCOM(Component Object Model)インターフェースを叩いている。VBAから宿主であるAutoCADのプロセスへ跨るため、ラウンドトリップ(プロセス間通信)のコストが発生する。

もし、ループ内で何千回もシステム変数を読み書きするような愚行を犯せば、パフォーマンスは劇的に低下する。

最適化の鉄則

1. ループの外側で取得・設定する: ループ内で `GetVariable` を呼ぶのは避ける。必ずローカル変数にキャッシュせよ。
2. `CMDECHO` と `REGENMODE` の制御: 大量のエンティティを動かす際は、`CMDECHO`(コマンドエコー)を `0` に、`REGENMODE`(再描画モード)を `0` にすることで、AutoCADの画面描画スレッドの負荷を極限まで削減できる。

‘ パフォーマンスチューニングの極致
Sub OptimizedBatchLoop()
Dim oldCmdEcho As Integer
oldCmdEcho = ThisDrawing.GetVariable(“CMDECHO”)

‘ 描画・ログ出力を停止
ThisDrawing.SetVariable “CMDECHO”, 0
ThisDrawing.SetVariable “REGENMODE”, 0

On Error GoTo CleanUp

‘ — 高速バッチ処理ループ —
Dim i As Long
For i = 1 to 10000
‘ ジオメトリの操作
Next i

CleanUp:
‘ 確実に復元
ThisDrawing.SetVariable “CMDECHO”, oldCmdEcho
ThisDrawing.SetVariable “REGENMODE”, 1
ThisDrawing.Regen acActiveViewport

If Err.Number <> 0 Then Err.Raise Err.Number, , Err.Description
End Sub

4. チーフアーキテクトからの提言

AutoCAD VBAはレガシーな技術として語られることが多い。しかし、AutoCADの内部構造(ObjectARXのラッパーとしてのCOM)の本質を理解していれば、これほど手軽に強力なCADオートメーションを実現できる手段他にはない。

システム変数の制御は、単なる「設定の変更」ではない。それは「ホストアプリケーションの実行コンテキストを一時的にジャックし、安全に原状復帰させる高度なトランザクション管理」なのだ。

この概念をあなたのコードに導入した瞬間から、マクロの安定性は次元を変える。エラーで現場を止める開発者から、静かに、確実に成果物を出し続けるプロフェッショナルへ――。今すぐそのコードの設計思想をアップデートしてほしい。

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