【入門編】【上級者向け】カスタムフィールドの依存関係を可視化する依存グラフ生成ツール – Project VBA解析バイブル

スポンサーリンク
スポンサーリンク

Project VBAの深淵へようこそ:カスタムフィールドの「依存関係」を解き明かす設計図の作り方

こんにちは。自動化の世界へようこそ。

MS Projectを使って複雑な進捗管理やコスト管理を行っていると、必ずと言っていいほど「カスタムフィールド(ユーザー定義フィールド)」の迷宮に迷い込むことがありますよね。「Text1にこの数式を入れたら、Text5の結果がおかしくなった……」「どのフィールドがどのフィールドを参照しているのか、もう自分でもわからない!」といった経験、あなたにもありませんか?

マクロの記録ボタンを押して、記録されたコードを眺める段階から、一歩踏み出して「システムの構造」を理解しようとしているあなた。その視点こそが、単なる「作業者」から「エンジニア」へと進化する境界線です。

今日は、そんな中級者への階段を駆け上がるための、非常に強力で、かつ実用的なテクニックを伝授します。テーマは「カスタムフィールドの依存関係を可視化する解析ツール」です。

なぜ「依存関係」を知る必要があるのか?

MS Projectのカスタムフィールドは、単なる「箱」ではありません。数式(Calculation)によって、他のフィールドの値を参照し、計算結果を導き出す「ロジックの連鎖」です。

例えば、以下のような連鎖があったとしましょう。

1. `[Text1]` に「プロジェクト区分」を入力
2. `[Number1]` に `IIf([Text1]=”A”, 10, 20)` という数式を設定
3. `[Cost1]` に `[Number1] * 1000` という数式を設定

ここで、もし誰かが「`Text1` の仕様が変わったから、計算ロジックも変えなきゃ」と思ったとき、`Number1` と `Cost1` も連鎖的に影響を受けることを忘れてしまうと、プロジェクト全体のデータ整合性が崩壊します。これを「ドミノ倒し」のようなリスクと呼びます。

このリスクを回避するために、「どのフィールドが、どのフィールドを食べているのか(参照しているのか)」を自動で洗い出すツールが必要なのです。

核心となるロジック:正規表現による「数式解析」

このツールを作るための鍵は、「正規表現(Regular Expressions)」という技術です。

カスタムフィールドの数式は、`[Text1]` や `[Cost]` のように、角括弧 `[]` で囲まれた形でフィールド名を指定します。私たちは、数式という「文字列」の中から、この `[…]` のパターンを抽出することを目指します。

解析のステップ

1. プロジェクト内のすべてのカスタムフィールド(Task/Resource)をループで回す。
2. 各フィールドの `.Calculation` プロパティ(数式が入っている場所)を取得する。
3. 正規表現を使って、`[フィールド名]` のパターンを探し出す。
4. 見つかったフィールド名を、「依存元」として記録する。

実装コード:Dependency Analyzer

それでは、実際に動くコードを見てみましょう。このコードは、タスクのカスタムフィールドをスキャンし、どのフィールドが何を参照しているかをイミディエイトウィンドウに出力します。

【準備】
VBAエディタのメニューから `ツール` -> `参照設定` を開き、「Microsoft VBScript Regular Expressions 5.5」にチェックを入れてください。これがないと正規表現が使えません。

Option Explicit

''' <summary>
''' カスタムフィールドの依存関係を解析し、イミディエイトウィンドウに出力するツール
''' </summary>
Sub AnalyzeCustomFieldDependencies()
    Dim regEx As RegExp
    Dim matches As MatchCollection
    Dim match As Match
    Dim tf As TaskCustomField
    Dim fieldName As String
    Dim formula As String
    
    ' 1. 正規表現オブジェクトの設定
    ' [ ] で囲まれた中身を抽出するパターン
    Set regEx = New RegExp
    With regEx
        .Pattern = "\[([^\]]+)\]" ' 「[」で始まり、「]」で終わる中身をキャプチャ
        .Global = True            ' 全ての該当箇所を見つける
        .IgnoreCase = True        ' 大文字小文字を区別しない
    End With

    Debug.Print "--- Custom Field Dependency Report ---"
    Debug.Print "Generated at: " & Now
    Debug.Print "--------------------------------------"

    ' 2. タスクのカスタムフィールドをループ処理
    ' TaskCustomFieldsコレクションには、プロジェクトに定義された定義情報が入っています
    For Each tf In ActiveProject.TaskCustomFields
        formula = tf.Calculation ' 数式を取得
        
        ' 数式が空でない場合のみ解析を実行
        If formula <> "" Then
            Debug.Print "Target Field: " & tf.FieldName & " (Type: " & tf.Type & ")"
            Debug.Print "  Formula: " & formula
            
            ' 3. 数式の中から [フィールド名] を抽出
            Set matches = regEx.Execute(formula)
            
            If matches.Count > 0 Then
                Debug.Print "  => Depends on:"
                Dim depFound As Boolean
                depFound = False
                
                Dim i As Integer
                For i = 0 To matches.Count - 1
                    ' matches(i).SubMatches(0) は、正規表現の ( ) で囲った部分(中身)を指す
                    fieldName = matches(i).SubMatches(0)
                    Debug.Print "     - " & fieldName
                    depFound = True
                Next i
                
                If Not depFound Then Debug.Print "     (No dependencies found)"
            Else
                Debug.Print "  => No dependencies detected."
            End If
            Debug.Print "--------------------------------------"
        End If
    Next tf

    MsgBox "解析が完了しました。イミディエイトウィンドウを確認してください。", vbInformation
End Sub

コードの解説:ここがエンジニアの視点!

  • `tf.Calculation` の重要性:

カスタムフィールドには「値(Value)」と「計算式(Calculation)」があります。私たちが解析したいのは、個々のタスクに入っている値ではなく、「フィールドそのものに設定されたルール」です。そのため、`TaskCustomFields` コレクションの `.Calculation` プロパティにアクセスしています。

  • 正規表現のパターン `\[([^\]]+)\]`:

ここが一番の肝です。

  • `\[` : 文字としての `[` にマッチさせます(`[` は正規表現の特殊記号なので `\` でエスケープします)。
  • `([^\]]+)` : 「`]` 以外の文字」が「1文字以上続く」ことを意味します。これを `( )` で囲むことで、後で中身だけを取り出せるようにしています。
  • `\]` : 文字としての `]` にマッチさせます。
  • `SubMatches(0)`:

正規表現で `( )` を使った場合、その中身だけをスマートに取り出すことができます。これを使わずにマッチ全体を取得すると、`[Text1]` という文字列が取れてしまいますが、これを使えば `Text1` だけが取れるのです。美しいでしょう?

陥りやすいエラーと回避策

プロフェッショナルの道は、エラーとの戦いです。以下の点に注意してください。

1. 参照設定の忘れ:
`User-defined type not defined` というエラーが出たら、ほぼ間違いなく「Microsoft VBScript Regular Expressions 5.5」の参照設定が漏れています。これは初学者が最も躓きやすいポイントです。
2. 数式内の特殊記号:
MS Projectの数式には、時として複雑なネスト(入れ子)や関数が含まれます。今回のコードは「どのフィールド名が含まれているか」を抽出することに特化していますが、数式の論理構造(IF文の条件分岐など)まで完全に解釈するには、さらに高度な「構文解析(パーサ)」の知識が必要になります。まずは「依存関係の特定」という目的を達成することに集中しましょう。
3. パフォーマンス:
プロジェクトが数万タスクある場合でも、このコードは「フィールドの定義」のみをループするため、非常に高速に動作します。もし「全タスクの値を一つずつチェックする」という設計にしてしまうと、処理が終わらなくなります。「どこをループさせるべきか」を見極めること、これが設計のセンスです。

まとめ:設計図を持つ者に、自由が訪れる

「マクロの記録」は、あなたの手足となって動いてくれる便利なツールです。しかし、今回のように「構造を解析するコード」を書くことは、あなたの「脳」を拡張することに他なりません。

カスタムフィールドの依存関係を可視化できるようになれば、大規模なプロジェクトのメンテナンスにおいて、あなたは「壊すのが怖い人」から「安心して変更を加えられる設計者」へと変わります。

ここをクリアすれば、Project VBAの基本、そして応用への扉はバッチリ開いていますよ。
さあ、次はもっと複雑な自動化に挑戦してみましょう。応援しています!

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