Project VBAの深淵:FileSystemObjectを用いた堅牢なプロジェクト・アーカイブの自動化
諸君、現場の戦場へようこそ。
MS ProjectのVBA(PJVBA)は、Officeアプリケーションの中でも特に「オブジェクトの相関関係」が複雑で、メモリリークや未定義の挙動に足元を掬われやすい難所だ。今回は、プロジェクト終了時に発生する「成果物の一括アーカイブ」という、一見単純だが、システム管理の根幹を揺るがす業務自動化について解説する。
低レベルなライブラリの呼び出しから、ガベージコレクションが不在のVBA環境におけるメモリ最適化まで、私が長年培った知見をここに記す。
—
1. なぜ「今さら」FSOなのか?
Projectから外部ファイルを操作する場合、`VBA.FileCopy`や`Name`ステートメントを使うのが初心者レベルの常識だ。しかし、シニアエンジニアであれば、`Scripting.FileSystemObject (FSO)` 一択であるべきだ。
理由は単純。エラーハンドリングの柔軟性と、パスの解析能力、そしてWindows APIとの親和性だ。特に、プロジェクトの終了処理において「ファイルが存在しない場合」や「書き込み権限がない場合」の振る舞いを細かく制御するには、FSOの `File` オブジェクトが提供するプロパティが不可欠となる。
2. 堅牢なアーカイブ設計:コード実装
以下は、Projectの終了時にタスクの付随資料を自動収集し、タイムスタンプを付与してアーカイブするプロシージャだ。
Option Explicit
‘ 参照設定: Microsoft Scripting Runtime
‘ 可能な限りLate Bindingは避け、Early Bindingでコンパイル時の型チェックを通すのが鉄則。
Public Sub ArchiveProjectFiles(ByVal sourceDir As String, ByVal targetDir As String)
Dim fso As Scripting.FileSystemObject
Dim sourceFolder As Scripting.Folder
Dim fileItem As Scripting.File
Dim archiveName As String
‘ メモリ最適化: インスタンス化は必要最小限に
Set fso = New Scripting.FileSystemObject
If Not fso.FolderExists(sourceDir) Then
Err.Raise vbObjectError + 1001, “Archive”, “ソースディレクトリが存在しません。”
End If
Set sourceFolder = fso.GetFolder(sourceDir)
‘ タイムスタンプの生成 (YYYYMMDD形式)
archiveName = Format(Now, “yyyyMMdd”) & “_”
On Error GoTo ErrorHandler
For Each fileItem In sourceFolder.Files
‘ ファイル名の衝突を避けるためのリネーム処理
fso.CopyFile fileItem.Path, targetDir & “\” & archiveName & fileItem.Name
Next fileItem
‘ 終了処理: メモリの明示的解放
‘ VBAの参照カウンタをリセットし、オブジェクトの生存期間を制御する
Set sourceFolder = Nothing
Set fso = Nothing
Exit Sub
ErrorHandler:
Debug.Print “Critical Error: ” & Err.Description
‘ ここでWindows APIのログ出力等へ接続する
Set fso = Nothing
End Sub
3. レガシー環境におけるメモリ管理の極意
VBAにおいて「`Set Object = Nothing`」を怠る者は、大規模な運用保守において必ず地獄を見る。
特にProject VBAは、アプリケーションを終了してもバックグラウンドでインスタンスが残存することが多々ある。`FileSystemObject`のような外部ライブラリを多用する場合、その背後でCOMオブジェクトがメモリを占有し続ける。
- 循環参照を避ける: モジュールレベルの変数でオブジェクトを保持しないこと。可能な限りローカルスコープで完結させ、プロシージャ終了時に即座に破棄せよ。
- APIによる監視: 長大な処理を行う場合、`GetProcessMemoryInfo` APIを叩き、メモリ使用量をログに出力するラッパーを用意しておくのが、伝説的なアーキテクトの嗜みだ。
4. 拡張性:APIとの連携
もし、アーカイブ先のディレクトリがネットワーク共有ドライブであり、認証が必要な場合、FSOだけでは限界がある。その際は、`WNetAddConnection2` APIを呼び出し、セッションをプログラム的に制御する必要がある。
‘ Windows APIの宣言例
Private Declare PtrSafe Function WNetAddConnection2 Lib “mpr.dll” Alias “WNetAddConnection2W” _
(lpNetResource As Any, ByVal lpPassword As LongPtr, ByVal lpUsername As LongPtr, ByVal dwFlags As Long) As Long
このように、VBAを「単なるマクロ」ではなく「Windowsシステムの一部」として捉えること。これが、システム間連携を成功させる唯一の道だ。
—
最後に:エンジニアへの提言
諸君、コードを書くことは手段に過ぎない。重要なのは、「いつ、誰が、どんな状況でこのツールを動かすのか」という運用設計だ。
Projectファイルは、常にビジネスの最前線にある。アーカイブが失敗すれば、それは単なるバグではなく、企業の歴史的資産の損失を意味する。だからこそ、FSOのような枯れた技術であっても、徹底的に磨き込み、完璧なエラーハンドリングを施す必要がある。
「動けばいい」という時代は終わった。
「止めさせない」「壊させない」それが、我々シニアエンジニアの矜持だ。
質問があればいつでも受け付ける。だが、まずは目の前のプロジェクトのメモリリークを一つでも潰すことから始めよ。健闘を祈る。
