【テクニカル・上級編】【上級者向け】プロジェクトファイル内のバイナリ破損を検知するためのチェックサム検証マクロ – Project VBA解析バイブル

スポンサーリンク

プロジェクトファイルの「静かなる腐敗」を断つ:MS Project VBAにおけるバイナリ整合性検証の極意

MS Projectの`.mpp`ファイルは、一見すると単なるデータベースのように見えるが、その実態は複雑なOLE複合ドキュメント構造を持つブラックボックスだ。大規模なスケジュール管理を行う現場において、バックグラウンドでの保存失敗や、ネットワークI/Oの瞬断による「バイナリの静かなる腐敗」は、我々アーキテクトにとって悪夢以外の何物でもない。

今回は、VBAからWindows APIを叩き、ファイル保存という不可逆なプロセスを厳密に監視・検証する、極限の整合性ツールについて解説する。

なぜ「保存しました」を信じてはいけないのか

VBAの`FileSave`メソッドがエラーを返さなかったからといって、物理層での書き込みが完了しているとは限らない。特に、共有ドライブ上での運用や、巨大なベースラインを保持するプロジェクトファイルでは、セクタ書き込みの不整合が稀に発生する。

シニアエンジニアとして取るべき防衛策はただ一つ。「保存直前のハッシュ値」と「保存直後のハッシュ値」を比較することだ。

実装の核心:Windows APIによるハッシュ計算

VBA標準機能にはハッシュ計算ライブラリが存在しない。そこで、Windows標準の`bcrypt.dll`を直接呼び出し、メモリ上で高速にSHA-256計算を行う。COMオブジェクトの生成はメモリを浪費するため、APIを直接叩くのが「正解」である。

整合性検証モジュール(抜粋)

‘ 必要なAPI定義(モジュールレベルで宣言)
Private Declare PtrSafe Function BCryptOpenAlgorithmProvider Lib “bcrypt.dll” ( _
ByRef phAlgorithm As LongPtr, ByVal pszAlgId As LongPtr, ByVal pszImplementation As LongPtr, ByVal dwFlags As Long) As Long
Private Declare PtrSafe Function BCryptCreateHash Lib “bcrypt.dll” ( _
ByVal hAlgorithm As LongPtr, ByRef phHash As LongPtr, ByVal pbHashObject As LongPtr, _
ByVal cbHashObject As Long, ByVal pbSecret As LongPtr, ByVal cbSecret As Long, ByVal dwFlags As Long) As Long

‘ ※注:実運用ではさらにBCryptHashData、BCryptFinishHash等のAPI定義を揃える必要がある
‘ オブジェクトのライフサイクルを管理するため、APIハンドルは確実に閉じること

メモリ最適化とオブジェクト解放の鉄則

大規模プロジェクトファイルを取り扱う際、`Application.Projects`や`Project`オブジェクトを不用意に参照し続けると、VBAはメモリリークを起こす。

1. Set = Nothing の強制: ループ処理の最後には、必ず明示的にオブジェクトを破棄する。
2. イベントの抑止: `Application.EnableEvents = False` を徹底せよ。検証中のファイル再オープンが無限ループを招くリスクを排除する。
3. ストリームの直接操作を避ける: ファイルシステムを直接触る際、VBAの`Open`構文ではなく、`Scripting.FileSystemObject`を経由しつつ、最終的にはAPIでストリームをクローズすることが、OSレベルでのフラッシュを確実にする。

実践:整合性検証の自動化ロジック

以下は、保存処理をラップし、整合性を検証する高信頼性保存プロシージャの骨子である。

Public Sub SecureProjectSave(ByVal targetProject As Project)
Dim hashBefore As String, hashAfter As String
Dim filePath As String: filePath = targetProject.FullName

‘ 1. 保存前の状態をキャプチャ(ハッシュ計算)
hashBefore = CalculateFileHash(filePath)

‘ 2. 保存実行
On Error GoTo SaveError
targetProject.Save

‘ 3. 保存後の状態を比較
hashAfter = CalculateFileHash(filePath)

If hashBefore <> hashAfter Then
Err.Raise vbObjectError + 1001, “IntegrityManager”, “ファイル整合性チェックに失敗しました。破損の可能性があります。”
End If

Exit Sub

SaveError:
MsgBox “致命的エラー: ” & Err.Description, vbCritical
End Sub

レガシー環境への配慮とシステム間連携

この手法は、Project ServerやPWA(Project Web App)と連携するハイブリッド環境においても有効だ。ローカルキャッシュが汚染されている場合、サーバーへのチェックイン処理は「ゴミを正解として同期する」最悪の結果を生む。

  • チェックサムのログ出力: 計算したハッシュ値をCSV等の別ログに吐き出し、SIEM(セキュリティ情報イベント管理)等で監視させることで、企業レベルでのインフラ保護が可能になる。
  • バイナリバックアップ: 整合性エラーを検知した瞬間、Windows API `CopyFile` を使い、その瞬間の「破損バイナリ」を別名保存して解析用に隔離する。これが後にデバッグの唯一の手掛かりとなる。

アーキテクトからの提言

コードが「動くこと」と、システムが「永続的に信頼できること」は次元が異なる。

VBAはレガシーと言われるが、その背後にあるWindows APIは、現代のC#アプリケーションが依存しているものと本質的には同じだ。APIのレイヤーまで降り、メモリとバイナリを直接制御するこのアプローチこそが、複雑なプロジェクト管理を司るエンジニアの矜持である。

プロジェクトファイルは単なるデータではない。企業の戦略そのものだ。その整合性を守り抜くことは、エンジニアとして最も高潔な仕事の一つであると信じている。

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