【Project VBA】「タスクが選択されていません」という甘えを排除する――堅牢なオブジェクト取得の極意
現場で動くマクロを書くエンジニアにとって、ユーザーの操作は「制御不能な外部変数」であると心得よ。
多くの開発者が陥る罠がある。`ActiveSelection.Tasks` に無邪気にアクセスし、ユーザーがガントチャート上で何も選んでいない瞬間に爆死するコードだ。これはバグではない。「設計の怠慢」だ。
今日は、Project VBAの最深部で「選択範囲の不確実性」を完璧に制圧し、プロダクション環境で耐えうる堅牢な実装パターンを伝授する。
—
なぜ `ActiveSelection` をそのまま信用してはいけないのか
VBAで最も安易な記述はこれだ。
‘ 絶対にやってはいけないアンチパターン
Set myTask = ActiveSelection.Tasks(1) ‘ 選択がないとここで実行時エラー発生
Projectのオブジェクトモデルにおいて、`ActiveSelection` はユーザーの現在のフォーカス状態をダイレクトに反映する。しかし、ユーザーは「タスクを選択せずに、プロジェクト内の何もない空間(あるいはヘッダー)」をクリックしているかもしれない。
ここでエラーを吐くツールは、ユーザーにとって「不安定なゴミ」だ。我々が作るべきは、例外を握りつぶすのではなく、例外が発生する余地を最初から消し去るコードである。
—
実践:堅牢な「タスク選択判定」モジュール
以下のコードは、単にエラーを避けるだけではない。選択範囲が「タスク」なのか「リソース」なのか、あるいは「複数選択」なのかを判別し、後続の処理に安全なデータを渡すための「ゲートウェイ」となる関数だ。
プロダクション・コード例
‘ 選択範囲を安全に取得し、タスクオブジェクトを返す堅牢な関数
Public Function GetSelectedTask() As Task
‘ 1. アクティブな選択範囲のタイプを確認
‘ pjSelectionTask 以外(リソースや何もない場所)なら処理を中断
If ActiveSelection.SelectionType <> pjSelectionTask Then
MsgBox “タスクが選択されていません。対象のタスクを選択してから実行してください。”, vbExclamation
Exit Function
End If
‘ 2. 選択されているタスクがあるか確認(0のチェックは必須)
If ActiveSelection.Tasks.Count = 0 Then
MsgBox “タスクが選択されていません。”, vbExclamation
Exit Function
End If
‘ 3. 最初のタスクを安全にセット
Set GetSelectedTask = ActiveSelection.Tasks(1)
End Function
‘ — 利用側のコード例 —
Sub ProcessSelectedTask()
Dim t As Task
Set t = GetSelectedTask
‘ オブジェクトがNothingでないか確認してから処理に入る
If t Is Nothing Then Exit Sub
‘ ここから安全なビジネスロジックを展開
Debug.Print “処理対象: ” & t.Name
End Sub
—
アーキテクトの視点:なぜこの実装なのか
1. SelectionType の先行ガード:
`ActiveSelection.SelectionType` を先に判定することで、タスク以外の選択オブジェクトに対する無駄なプロパティアクセスを排除している。これにより、メモリの無駄遣いと予期せぬ挙動を遮断する。
2. Count プロパティによる存在確認:
`Tasks(1)` にアクセスする前に `Count` を見る。これは、APIの仕様に対する最低限の敬意だ。コレクションが空の時に添字アクセスを試みるのは、崖っぷちを走るようなものだ。
3. Nothing を活用したフロー制御:
関数が `Nothing` を返すことを仕様に含めることで、呼び出し側は「処理が続行可能か」を `If t Is Nothing` という非常に可読性の高い形式で制御できる。
—
データベース連携・ファイル出力時の注意点
この「選択範囲の不確実性」は、外部システムとの連携時に致命的なバグを誘発する。
- データベース連携: 選択範囲が未定義のままDBへクエリを投げると、ID `0` や `Null` が混入し、データ不整合を引き起こす。上記のように「関数でバリデーションをクリアしたオブジェクトのみを処理に回す」ルールを徹底せよ。
- ファイル出力: CSVやExcelへのエクスポート処理中にユーザーが別のタスクを選択し直すリスクがある。大規模な処理を行う場合は、処理開始時に `Application.ScreenUpdating = False` を実行し、UI操作によるオブジェクト参照のズレを物理的に封印する知恵も持っておくべきだ。
最後に
「エラーが出ないこと」は、プロフェッショナルなツールにとっての最低条件だ。ユーザーがどんなに無茶な操作をしても、あなたの書いたコードが静かに、そして毅然と「それはできません」と伝える、あるいは「何もしない」という安全な選択肢を選べるように設計すること。
それが、Project VBAを真に掌握する者の仕事だ。
さあ、あなたのプロジェクトで、その「甘いコード」を今すぐ書き換えたまえ。
