【テクニカル・上級編】【上級】AcadApplication.Preferences.Files.SupportPathの優先順位を一時的に書き換え、プロジェクト専用フォントを強制認識させる – AutoCAD VBA解析バイブル

スポンサーリンク

【上級】AcadApplication.Preferences.Files.SupportPathの優先順位を一時的に書き換え、プロジェクト専用フォントを強制認識させる

AutoCAD VBAの現場において、最も静かに、そして確実にプロジェクトを崩壊させる要因は何か。それは「フォントとシェイプ(SHX/TTF)の欠落」、そして「カスタムハッチングパターン(PAT)の迷子」である。

クライアントや協力会社から納品された図面を開いた瞬間、コンソールに鳴り響く「不明なフォントを置き換えました」の警告。あるいは、文字化けしたレイアウト空間。
標準的な開発アプローチであれば、「全PCのサポートパスに専用フォルダを手動で追加しろ」という時代遅れの運用マニュアルを配るか、インストーラーでレジストリを無理やり書き換える暴挙に出るだろう。

だが、プロフェッショナルな自動化エンジニアリングにおいて、「グローバル環境を汚すこと」は最大の悪である。
他の業務プロセスに影響を与えず、マクロの実行瞬間のみ、AutoCADの検索パスの最優先にプロジェクト専用リポジトリをねじ込み、処理完了と同時に完全なる原状復帰を果たす。

今回は、`AcadApplication.Preferences.Files.SupportPath` をプログラムのライフサイクルに合わせて動的にスイッチングし、メモリリークや設定汚染を完全に排除した「環境スイッチング術」の極限実装を公開する。

—

1. AutoCADサポートパスの内部構造と破壊的リスク

AutoCADの検索パス(SupportPath)は、セミコロン(`;`)区切りの文字列として `Preferences.Files` オブジェクトに保持されている。このプロパティは単なる文字列ではなく、AutoCADプロセス全体のファイル探索キャッシュの基盤だ。

これを安易に直接書き換えたり、エラーハンドリングの不備によって途中でマクロが異常終了(Crash / User Interrupt)したりすると、どうなるか。
パスが書き換わったままの状態でAutoCADがゾンビ化し、次からの通常業務で標準フォントやフォントマッピングファイル(.shx, .fmp)が読み込めなくなるという、ヘルプデスク直行の致命的障害を引き起こす。

したがって、我々が実装すべきアーキテクチャの要件は以下の3点に集約される。

1. アトミック(不可分)な操作: パスの退避、書き込み、処理実行、復元の一連の流れが必ず保証されること(トランザクション概念の導入)。
2. エラー耐性の極限化: 実行中にいかなるランタイムエラーが発生しようとも、`Finally` 相当のクリーンアップブロックで確実に元のパスに戻すこと。
3. パスの重複排除と正規化: 文字列操作の過程で余分なセミコロンやパスの重複を生じさせない堅牢なパーシング。

—

2. 実装コード:環境スイッチング・トランซクショナルモジュール

以下のコードは、指定したプロジェクト固有のフォルダパスを、実行中のみ `SupportPath` の最先頭に強制挿入し、安全にクリーンアップを行うクラスライブラリ的な標準モジュールである。

Option Explicit

‘ Windows APIの宣言:VBAの実行停止や予期せぬ中断時における安全性の担保
‘ (※今回はVBAの強固なエラーハンドリングモデルで完結させるが、実務ではCOMのライフサイクル管理と併用する)

Private Const ERR_PATH_NOT_FOUND As Long = 53

Public Sub ExecuteWithCustomSupportPath(ByVal TargetFolderPath As String, ByVal SubToExecute As String)
Dim acadApp As AcadApplication
Dim originalPath As String
Dim newPath As String

‘ 1. 堅牢なアプリケーション参照の取得(GetObjectのフォールバック)
On Error Resume Next
Set acadApp = GetObject(, “AutoCAD.Application”)
If acadApp Is Nothing Then
Set acadApp = New AcadApplication
End If
On Error GoTo 0

If acadApp Is Nothing Then
MsgBox “AutoCADのインスタンスが見つかりません。”, vbCritical, “Critical Error”
Exit Sub
End If

‘ 2. ターゲットパスの存在確認(I/O例外の事前排除)
If Not FolderExists(TargetFolderPath) Then
MsgBox “指定されたプロジェクト専用パスが存在しません: ” & TargetFolderPath, vbExclamation, “Path Error”
Exit Sub
End If

‘ 3. 現在のサポートパスを完全に退避(スナップショットの取得)
originalPath = acadApp.Preferences.Files.SupportPath

‘ 4. パスの最適化と最優先挿入(先頭へのアタッチ)
‘ 既にパスが含まれている場合は一度削除し、重複を防ぐ
Dim cleanedPath As String
cleanedPath = RemovePathFromCollection(originalPath, TargetFolderPath)

‘ 先頭に結合(末尾のセミコロン処理に注意)
If Right$(TargetFolderPath, 1) = “;” Then
newPath = TargetFolderPath & cleanedPath
Else
newPath = TargetFolderPath & “;” & cleanedPath
End If

‘ — 【トランザクション開始】 —
On Error GoTo TransactionError

‘ 一時的に環境を書き換え
acadApp.Preferences.Files.SupportPath = newPath

‘ デバッグ出力:環境スイッチングの確認
Debug.Print “[EnvSwitch] SupportPath Temporarily Overridden.”
Debug.Print “[EnvSwitch] Injected: ” & TargetFolderPath

‘ 5. メイン処理の動的ディスパッチ(CallByNameによる疎結合実行)
‘ ※実際の業務ではここで図面のオープンやバッチ処理を行う
CallByName Me, SubToExecute, VbMethod, acadApp

‘ — 【正常終了時のクリーンアップ】 —
acadApp.Preferences.Files.SupportPath = originalPath
Debug.Print “[EnvSwitch] SupportPath Successfully Restored.”
Exit Sub

TransactionError:
‘ — 【異常終了時の強制クリーンアップ(極めて重要)】 —
Dim errDesc As String
errDesc = Err.Description

On Error Resume Next
acadApp.Preferences.Files.SupportPath = originalPath
Debug.Print “[EnvSwitch] ERROR OCCURRED. SupportPath forcibly restored. Error: ” & errDesc

On Error GoTo 0
MsgBox “予期せぬエラーが発生したため、AutoCAD環境を復元しました。” & vbCrLf & _
“詳細: ” & errDesc, vbCritical, “Fatal Execution Error”
End Sub

‘ — ヘルパー関数群 —

Private Function FolderExists(ByVal path As String) As Boolean
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
FolderExists = fso.FolderExists(path)
Set fso = Nothing
End Function

Private Function RemovePathFromCollection(ByVal fullPathString As String, ByVal pathToRemove As String) As String
Dim paths() As String
Dim i As Long
Dim resultList As String

‘ 末尾のセミコロンを正規化
If Right$(pathToRemove, 1) = “;” Then
pathToRemove = Left$(pathToRemove, Len(pathToRemove) – 1)
End If

paths = Split(fullPathString, “;”)
resultList = “”

For i = LBound(paths) To UBound(paths)
Dim currentPath As String
currentPath = Trim$(paths(i))
If currentPath <> “” Then
‘ 大文字小文字を区別せずにパスを比較(Windowsファイルシステムの特性に準拠)
If StrComp(currentPath, pathToRemove, vbTextCompare) <> 0 Then
If resultList = “” Then
resultList = currentPath
Else
resultList = resultList & “;” & currentPath
End If
End If
End If
Next i

RemovePathFromCollection = resultList
End Function

‘ テスト用プロシージャ(メイン処理のディスパッチ先)
Public Sub SampleBatchProcess(ByVal app As AcadApplication)
‘ ここにプロジェクト専用フォント(SHX)を必要とする図面処理を記述
Dim doc As AcadDocument
Set doc = app.ActiveDocument

MsgBox “現在のサポートパス最優先枠は確保されました。” & vbCrLf & _
“現在アクティブな図面: ” & doc.Name, vbInformation, “Execution State”

‘ 例:図面の再読み込みやフォント依存の処理
doc.Regen acAllViewports
End Sub

—

3. コードのアーキテクチャ解説:なぜこの実装なのか

1. `CallByName` による処理のディスパッチ

トランザクションのラッパー(`ExecuteWithCustomSupportPath`)の中に実際の業務ロジックを直書きするのではなく、`CallByName` を用いて動的にプロシージャを呼び出す設計にしている。これにより、「環境のスイッチング・保護」という横断的関心事(Cross-Cutting Concerns)と、「個別のCAD処理」を完全に分離(AOP: アスペクト指向プログラミングのVBA的実装)できる。

2. パスの厳密な正規化とデデュプリケーション(重複排除)

`RemovePathFromCollection` 関数は、単にパスを追加するだけでなく、もし既にそのプロジェクトパスがレジストリや既存のSupportPathの中間、あるいは末尾に存在していた場合、それを一度綺麗に「削ぎ落としてから先頭に再配置」する。
これを怠ると、SupportPathの文字列長がAutoCAD内部のバッファ制限(レジストリの制限含む)をじわじわと圧迫し、やがて設定が保存できなくなるというマニアックなバグを踏むことになる。さらに、Windowsのファイルパスの大文字小文字を無視する特性(`vbTextCompare`)を考慮した比較を行っている。

3. トランザクション保証(`Error GoTo TransactionError`)

VBAにはVB.NETのような `Try…Finally` 構文が存在しない。そのため、明示的なジャンプラベルを用いたエラーハンドリングブロックが必須となる。
万が一、`CallByName` の内部でヌル参照エラーやAutoCAD固有のCOM例外が発生した場合でも、エラーハンドラに処理が落ち、必ず元の `originalPath` が `acadApp.Preferences.Files.SupportPath` に書き戻される。この防壁があるおかげで、開発者がデバッグ中にコードを強制停止させても、CAD環境が汚染されることはない。

—

4. 現場で活きる応用:システム間連携と保守性の極限化

このテクニックは、単なる「フォントの強制認識」にとどまらない。例えば、以下のような高度なEnterprise環境への展開が可能だ。

  • Git / 共有サーバーとの完全連動:

CI/CDパイプラインや社内共有リポジトリから、プロジェクトごとに異なるフォントパックやテンプレートをローカルのテンポラリフォルダ(例: `C:\Temp\CAD_Projects\Proj_XYZ\Fonts`)に自動同期し、そのパスをこのマクロに渡すことで、「どの端末で実行しても絶対にフォントが見つからないと言われない自律型図面処理システム」が完成する。

  • レガシーCAD環境の保護:

部署ごとに異なる古いCAD規格(JIS/ISOの混在など)が強制されている環境において、特定のレガシー図面群を変換・処理する瞬間だけ専用の環境プロファイルに切り替えることで、全体設定に触れずに安全なバッチ処理を担保できる。

結びにかえて

VBAはレガシーな言語と揶揄されることがある。しかし、オブジェクトモデルの挙動、COMのライフサイクル、そしてWindows環境のメモリとレジストリの制約を熟知したエンジニアが操るとき、VBAは最前線の現場を支える最も強靭なオートメーション・武器へと変貌する。

環境を汚さず、痕跡を残さず、ただ確実に仕事をやり遂げる。それこそが、真の自動化エンジニアリングの美学である。

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