【テクニカル・上級編】リソースの「割り当て」削除時に発生する「実績工数の整合性」を保つ安全な削除処理 – Project VBA解析バイブル

スポンサーリンク

亡霊のような「不整合」を封じる:Project VBAにおけるリソース割り当て削除の外科手術

Project VBA(MS Projectのオブジェクトモデル)を扱う際、多くの開発者は「Assignments.Delete」という安易な破壊メソッドに手を出す。だが、実績工数(Actual Work)が刻まれたリソースを、単なるプロパティ操作だけで引き剥がせると思ったら大間違いだ。

実績が存在する状態で割り当てを削除すれば、Projectのエンジンは算術的な不整合を起こし、タスクの進捗率が狂い、コストは計算不能な浮動小数点のゴミを吐き出す。

今日は、システムに傷跡を残さず、整合性を保ったままリソースを「摘出」する極限のロジックを伝授する。

—

1. 破壊の前に:実績工数の「凍結」という思想

実績工数が入力されているリソースを削除する場合、単に `Assignment.Delete` を呼ぶのは、心臓手術中に心拍モニターを引っこ抜くようなものだ。

我々がやるべきは、「実績工数を保持したまま、残存予定工数(Remaining Work)をゼロに叩き落とす」という工程である。これにより、Projectの計算エンジンは「このタスクに対するリソースの役割は終わった」と認識し、整合性を保ったまま安全な削除許可を出す。

2. 実装コード:安全な摘出手術のプロトコル

以下は、メモリリークを許さず、オブジェクトのライフサイクルを厳密に管理する実装例だ。

‘ @brief 実績工数を考慮した安全なリソース割り当て削除
‘ @param targetTask 処理対象のTaskオブジェクト
‘ @param resID 削除対象のリソースID
Public Sub SafeRemoveAssignment(ByRef targetTask As Object, ByVal resID As Long)
Dim asn As Object
Dim found As Boolean

‘ オブジェクトの明示的探索
For Each asn In targetTask.Assignments
If asn.ResourceID = resID Then
found = True
Exit For
End If
Next asn

If Not found Then Exit Sub

‘ 【重要】残存工数をゼロにすることで、実績との不整合を防ぐ
‘ これを行わずに削除すると、Projectのスケジュールエンジンが再計算時に値を補完し、謎のコストが発生する
If asn.RemainingWork > 0 Then
asn.RemainingWork = 0
End If

‘ 実績工数を保持したまま、割り当てそのものを削除
‘ COMインターフェース経由でDeleteを叩く際は、必ず親オブジェクトの整合性を確認せよ
On Error Resume Next
asn.Delete
If Err.Number <> 0 Then
‘ ここでログを吐く。Windows APIでイベントログに書き込むのがプロの流儀
Debug.Print “Critical Error: Assignment Delete Failed for Task ” & targetTask.ID
End If
On Error GoTo 0

‘ オブジェクトの解放(VBAでは自動だが、複雑な処理の中では明示的にNothingを代入し、スタックを整理する)
Set asn = Nothing
End Sub

—

3. メモリとオブジェクトのライフサイクル管理

VBAのガーベジコレクションは、我々が思うほど賢くはない。特にMS Projectの `Assignments` コレクションは、バックグラウンドでCOMインターフェースを大量に掴んでいる。

  • 明示的なNothing代入: `For Each` ループ内で `Assignment` オブジェクトを使い回す際、ループの最後で明示的に `Set asn = Nothing` を行うことは、大規模プロジェクトにおけるメモリ断片化を防ぐ必須の儀式だ。
  • イベントの無効化: `Application.Calculation = pjManual` を使用し、削除処理中の自動再計算を一時的に停止せよ。大量の割り当て削除を行う際、計算エンジンが走るたびにメモリ消費が跳ね上がり、最悪の場合「Application.Hwnd」がフリーズする。

—

4. シニアエンジニアへの提言:レガシーとの共存

この手法を導入する際、最も障壁となるのは「UI側の表示」と「バックエンドのデータ」の乖離だ。

もし貴殿がVB.NETから `MSProject.Application` を操作する外付けの自動化ツールを作っているなら、`Project.ProjectSummaryInfo` にアクセスする前に必ず `Project.Calculate` を呼び出し、メモリ上の計算結果を強制的にコミットさせろ。

「動くコードを書く」のは初学者だ。「整合性を壊さないコードを書く」のがエンジニアだ。

ProjectのバックエンドにあるガチガチのDB構造を理解していれば、`Delete` 一つ叩くにも恐怖を感じるはずだ。その恐怖こそが、君を一段上のエンジニアへと引き上げる。システムを破壊するな。設計の意図を汲み取り、外科医のようにメスを入れよ。

—

次回の極限知見:
「COM/OLEオートメーションにおける非同期処理の限界と、Windows APIを用いたプロセス間通信によるProjectの高速化」について語る。乞うご期待。

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