【テクニカル・上級編】【初心者向け】Predecessorsプロパティの文字列操作:Excelの先行タスクIDをProject形式に変換するコツ – Project VBA解析バイブル

スポンサーリンク

【Project VBA極限解説】Predecessorsプロパティの文字列操作:Excelの先行タスクIDをProject形式への安全な架橋

シニアエンジニア、そして組織のインフラをコードで支えるシステム管理者諸君。
日々の業務で、Excelで管理された数千行のWBS(Work Breakdown Structure)をMicrosoft Projectへ流し込む作業に疲弊していないか?

「Excel上では『1, 2, 3』とカンマ区切りで入力されている先行タスクIDを、Projectの`Predecessors`プロパティにそのまま代入したら、実行時エラーで弾かれた」
――この壁にぶつかった者は数知れない。

今回は、この単純に見えて奥が深い「先行タスクIDの文字列変換と依存関係の自動設定」について、Project VBAのオブジェクトモデルの裏側、そして実務で耐えうる堅牢な文字列操作の極意を授ける。

—

1. なぜExcelの「1,2,3」はそのままProjectに通じないのか?

初心者が最初に陥る罠は、Excelのセル値(例: `”1, 2, 3″` や `”1,3″`)をそのまま `Task.Predecessors` に代入することだ。

‘ 【アンチパターン】絶対にやってはいけない実装
Dim t As Task
Set t = ActiveProject.Tasks(5)
t.Predecessors = “1, 2, 3” ‘ 環境や言語設定によってはエラー、あるいは意図しない解釈をされる

Microsoft Projectの内部エンジン(PJS)は、タスクの依存関係を解釈する際、OSのロケール設定(区切り文字:カンマかセミコロンか)、リンクの種類(FS, SS, FF, SF)、そしてラグ(遅延時間)を厳密に評価している。

特に多国籍チームやレガシーなWindows環境が混在する現場では、カンマ(`,`)区切りをセミコロン(`;`)区切りに変更しなければならないケースや、タスクID(ID)ではなくユニークID(UniqueID)での指定が求められるシステム間連携の要件が存在する。

プロフェッショナルであれば、「入力値のサニタイジング」「区切り文字の正規化」「タスク存在確認」の3ステップをコードで担保しなければならない。

—

2. 実装アーキテクチャ:堅牢なPredecessors変換エンジン

以下に、Excelから取得したカンマ区切りの文字列を解析し、Projectが確実に理解できる形式へ変換して安全に適用するプロダクション品質のVBAコードを提示する。

メモリリークを防ぐため、オブジェクトのライフサイクル管理(特に `Tasks` コレクションや `Task` オブジェクトの適切な参照解放)にも配慮している。

Option Explicit

‘ ==============================================================================
‘ 担当: チーフアーキテクト
‘ 概要: Excel側の先行タスクID文字列を安全にProjectのPredecessors形式に変換・設定する
‘ ==============================================================================
Public Sub SetTaskPredecessorsSafely(ByVal targetTask As MSProject.Task, ByVal rawPredecessorString As String)

‘ 1. ガード節:入力値が空の場合は処理をスキップ
If Trim$(rawPredecessorString) = “” Then Exit Sub

On Error GoTo ErrorHandler

Dim idArray() As String
Dim cleanedString As String
Dim i As Long
Dim predecessorId As String
Dim translatedList As String

‘ 2. カンマや全角スペースを正規化し、配列へ分解
‘ ※実務では全角カンマやタブが混入するため、事前に置換処理を入れるのが鉄則
rawPredecessorString = Replace(rawPredecessorString, “,”, “,”) ‘ 全角→半角
rawPredecessorString = Replace(rawPredecessorString, ” “, “”) ‘ スペース除去

idArray = Split(rawPredecessorString, “,”)
translatedList = “”

‘ 3. 分割された各IDの妥当性検証と再構築
For i = LBound(idArray) To UBound(idArray)
predecessorId = Trim$(idArray(i))

If predecessorId <> “” Then
‘ 数値であることの簡易バリデーション
If IsNumeric(predecessorId) Then
Dim targetIDNum As Long
targetIDNum = CLng(predecessorId)

‘ 存在確認(プロジェクト内に該当IDのタスクが存在するか)
If DoesTaskExist(ActiveProject, targetIDNum) Then
‘ リンク形式の構築(デフォルトはFS: Finish-to-Start)
‘ 必要に応じてここで “+2days” などのラグをパースして結合することも可能
If translatedList <> “” Then
translatedList = translatedList & “;” ‘ Projectの標準区切り文字(環境依存対策としてセミコロンを推奨)
End If
translatedList = translatedList & targetIDNum
Else
Debug.Print “警告: タスクID [” & targetIDNum & “] はプロジェクト内に存在しません。”
End If
End If
End If
Next i
ンス:
‘ 4. 構築した安全な文字列を適用
If translatedList <> “” Then
targetTask.Predecessors = translatedList
End If

Exit Sub

ErrorHandler:
‘ 本番環境ではエラーログ基盤へスローすること
MsgBox “Predecessorsの設定中にエラーが発生しました: ” & Err.Description, vbCritical, “VBA Architecture Error”
End Sub

‘ ==============================================================================
‘ 補助関数: 指定したIDのタスクがプロジェクト内に存在するか検証
‘ ==============================================================================
Private Function DoesTaskExist(ByVal prj As MSProject.Project, ByVal taskId As Long) As Boolean
Dim t As MSProject.Task
On Error Resume Next
Set t = prj.Tasks(taskId)
If Not t Is Nothing Then
DoesTaskExist = True
Else
DoesTaskExist = False
End If
On Error GoTo 0
‘ オブジェクトの明示的解放
Set t = Nothing
End Function

—

3. シニアエンジニアが知るべき「見落としがちな罠」と最適化

上記のコードを実運用するにあたり、大規模プロジェクト(タスク数10,000件超)を扱うアーキテクトが考慮すべきポイントを共有する。

① UI描画の抑制(ScreenUpdatingとCalculation)

大量のタスクに対してループで `Predecessors` を設定していくと、Projectのガントチャート描画エンジンやクリティカルパスの再計算が都度走り、パフォーマンスが著しく低下する。
一括処理を行う際は、必ず以下のスコープでアプリケーションの挙動を制御せよ。

‘ 処理開始前
App.ScreenUpdating = False
‘ ※Projectオブジェクトモデルには直接的な Calculation 停止プロパティがないため、
‘ 大規模バッチでは Task.CalculationMode などを適切に管理する。

‘ — ここに大量処理を記述 —

‘ 処理終了後
App.ScreenUpdating = True

② IDとUniqueIDのジレンマ

今回のサンプルコードでは `Tasks(id)`(行番号ベースのID)を使用しているが、WBSの行挿入や削除が頻発するシステム連携では、行番号ベースのIDは容易に破綻する。
堅牢性を極限まで高めるシステムでは、`Task.UniqueID` をキーにしたマップ構造を構築し、先行タスクの紐付けを行うべきだ。これにより、タスクの順序が入れ替わっても依存関係が崩れなくなる。

—

総括

VBAにおける文字列操作は一見泥臭く見えるかもしれない。しかし、その背後にあるオブジェクトのライフサイクル、エラーハンドリング、そしてホストアプリケーション(Microsoft Project)の内部仕様を熟知していれば、それはただの「文字合わせ」ではなく、極めて高度なデータインテグレーション・エンジニアリングへと昇華する。

レガシーとモダンが交差する現場において、貴殿が書くコードがシステム全体の命綱となることを忘るな。さらなる高みを目指せ。

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