こんにちは。Project VBAの世界へようこそ。
あなたが今、このページを開いているということは、「マクロの記録」で作成したコードを動かしてみたものの、「なぜか別のファイルが書き換わってしまった」「複数のプロジェクトを開いていると動作が不安定になる」といった壁にぶつかっているのではないでしょうか。
安心してください。それはあなたが「Project VBAの真の入り口」に立った証拠です。
今日は、多くの初学者が陥り、そしてプロでも時折足元をすくわれる「ActiveProject」の罠についてお話しします。ここをマスターすれば、あなたの書くコードの信頼性は劇的に向上し、複雑なマルチプロジェクト管理も自由自在になりますよ。
—
1. なぜ `ActiveProject` を使い続けると危険なのか?
多くの入門書やマクロの記録では、操作対象を `ActiveProject` と記述します。これは「今、目の前で見えている(フォーカスが当たっている)プロジェクト」を指します。
一見便利ですが、ここには大きな落とし穴があります。
ユーザーの操作で「Active」は変わる
マクロの実行中に、もしあなたが(あるいは他のユーザーが)別のプロジェクトのウィンドウをカチッとクリックしたらどうなるでしょうか?
その瞬間に `ActiveProject` は切り替わります。処理の途中で対象が入れ替わり、「Aプロジェクトの予算を書き換えるつもりが、Bプロジェクトのタスクを消してしまった」という悲劇が起こり得るのです。
「マクロの記録」から卒業するための第一歩
「記録」されたコードは、常にその瞬間の状態に依存します。しかし、プロのエンジニアが書く自動化ツールは、「どのプロジェクトを操作するか」を最初に確定させ、最後まで離しません。
—
2. Projectオブジェクトモデルの階層を理解する
Project VBAを制御するコツは、住所を特定するように「階層」で捉えることです。
- Application: Microsoft Project 自体
- Projects: 開いているすべてのプロジェクトの集まり(コレクション)
- Project: 個別のプロジェクトファイル(.mpp)
- Task / Resource: プロジェクトの中にあるタスクやリソース
図解するとこのようなイメージです。
Application (Projectアプリ)
└ Projects (開いている全ファイルのリスト)
├ Project(1) “基幹システム構築.mpp” ← これを直接捕まえたい!
├ Project(2) “保守運用マニュアル.mpp”
└ ActiveProject (← 今たまたま見ているもの:不安定)
私たちが目指すのは、`ActiveProject` という「不安定な指名」ではなく、「変数」という箱にプロジェクトをしっかり閉じ込めて固定する手法です。
—
3. 実践:プロジェクトを「変数」に代入して固定する
では、具体的にどう書くのが正解なのでしょうか。
「危ない書き方」と「安全な書き方」を比較してみましょう。
❌ 危ない書き方(ActiveProject 依存)
このコードは、実行中にウィンドウを切り替えると、意図しないプロジェクトに対してタスクを追加してしまいます。
Sub UnsafeTaskAdd()
‘ 実行した瞬間に「たまたまアクティブなプロジェクト」を対象にする
ActiveProject.Tasks.Add Name:=”新しいタスク”
‘ 途中でユーザーが別のファイルをクリックすると…
MsgBox “タスクを追加しました。”
End Sub
✅ 安全な書き方(オブジェクト変数への代入)
プロの書き方はこうです。最初に「このプロジェクトですよ」と宣言し、変数に格納します。
Sub SafeTaskAdd()
‘ 1. プロジェクトを入れるための「箱(変数)」を用意する
Dim pj As Project
‘ 2. 操作したいプロジェクトを特定して変数にセットする
‘ ここでは「今アクティブなもの」をセットしますが、一度セットすれば途中で画面が変わってもpjは変わりません
Set pj = ActiveProject
‘ 3. 以降、ActiveProject ではなく 変数 pj を使う
If Not pj Is Nothing Then
pj.Tasks.Add Name:=”確実に追加されるタスク”
Debug.Print “対象プロジェクト: ” & pj.Name
End If
End Sub
—
4. 応用:特定の名前のプロジェクトを確実に操作する
複数のプロジェクトが開いているとき、「特定の名前のファイル」を操作したいこともありますよね。その場合は、`Projects` コレクションの中から名前で探すのが最も安全です。
以下のコードは、開いているプロジェクトの中から特定の名前を探し出し、見つかった場合のみ処理を行う実戦的なテンプレートです。
Sub ControlSpecificProject()
Dim targetPj As Project
Dim pjName As String
pjName = “システム開発計画_2023.mpp” ‘ 操作したいファイル名
‘ プロジェクトを探す
On Error Resume Next ‘ エラーを一旦無視(見つからない場合に備える)
Set targetPj = Application.Projects(pjName)
On Error GoTo 0 ‘ エラー復旧
‘ 見つかったかどうかで分岐
If targetPj Is Nothing Then
MsgBox “プロジェクト「” & pjName & “」が開かれていません。”, vbExclamation
Exit Sub
End If
‘ 以降、targetPj に対して処理を行う
‘ 画面が切り替わっても、targetPj はこのファイルを指し続けます
With targetPj
.Tasks.Add Name:=”自動生成タスク”
MsgBox .Name & ” のタスク数は ” & .Tasks.Count & ” 個です。”
End With
End Sub
—
5. 黄金のルール:`ActiveProject` を使うのは「最初の一瞬」だけ
誤解しないでいただきたいのは、`ActiveProject` が絶対に悪ではないということです。
「ユーザーがいま開いているこのファイルに対して処理を始めたい」という入り口としては正解です。
大切なのは、「最初の一瞬で変数に Set して、以降は ActiveProject という言葉をコードから消す」という習慣です。
チーフアーキテクトからのアドバイス
1. Dim pj As Project を必ず書く。
2. Set pj = ActiveProject で、対象を固定する。
3. コード内で pj.Tasks や pj.Resources と書くようにし、`ActiveProject` を直接参照しない。
—
まとめ
`ActiveProject` の落とし穴を避ける方法は、意外とシンプルだったはずです。
「対象を明確に指し示し、変数という鎖でつなぎ止める」。この意識を持つだけで、あなたのVBAスキルは初心者レベルを軽々と脱却し、プロの領域へと足を踏み入れることができます。
Project VBAは、大規模なプロジェクトを支える強力な武器になります。
基本を一つずつ積み上げていけば、必ず「Projectを完全に掌握する」日が来ますよ。
ここをクリアすれば、Project VBAの基本はバッチリです。次はタスクやリソースの細かな操作に挑戦してみましょう!応援しています。
