本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
【VBA×WMI】Windowsプロセス監視とメモリ・増殖異常を自動検知する仕組みの構築
【背景と目的】
外部システムのバッチ処理や特定プロセスのフリーズ・増殖によりExcelが極端に重くなる課題を、WMIによる常時監視と異常検知で解決します。(68文字)
【処理フロー図】
graph TD
A["監視処理の開始"] --> B["WMIでプロセス情報を取得"]
B --> C{"メモリ使用量・個数の閾値判定"}
C -->|異常あり| D["配列に異常データを格納"]
C -->|正常| E["次の判定へ"]
D --> F["シートへ一括書き出し・アラート表示"]
E --> F
F --> G["処理終了"]
【実装:VBAコード】
※Win32 API宣言を含め、参照設定なし(遅延結合)で動作する設計です。
Option Explicit
' --- Win32 APIの宣言 (64bit/32bit両対応) ---
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
' 監視メイン処理
Public Sub MonitorWindowsProcesses()
On Error GoTo ErrorHandler
' 高速化設定
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
' 監視設定(例: メモリ使用量が200MB以上のプロセス、または特定のプロセス名)
Const MEMORY_THRESHOLD_MB As Double = 200.0
Const TARGET_PROCESS_NAME As String = "excel.exe"
' WMIオブジェクトのバインド(遅延結合)
Dim wmiService As Object
Set wmiService = GetObject("winmgmts:\\.\root\cimv2")
' プロセス一覧のクエリ実行
Dim processList As Object
Set processList = wmiService.ExecQuery("SELECT * FROM Win32_Process")
' ログ出力用配列の準備 (最大1000行 x 4列)
Dim logData() As Variant
ReDim logData(1 To 1000, 1 To 4)
Dim logIndex As Long: logIndex = 0
Dim proc As Object
Dim memUsageMB As Double
Dim procCount As Long: procCount = 0
' プロセスループ
For Each proc In processList
' メモリ使用量(WorkingSetSize)の算出 (Byte -> MB)
If Not IsNull(proc.WorkingSetSize) Then
memUsageMB = CDbl(proc.WorkingSetSize) / 1024 / 1024
Else
memUsageMB = 0
End If
' 同一プロセスの個数カウント
If LCase(proc.Name) = LCase(TARGET_PROCESS_NAME) Then
procCount = procCount + 1
End If
' 異常条件判定(指定メモリ超え、またはターゲットプロセスの監視)
If memUsageMB > MEMORY_THRESHOLD_MB Or LCase(proc.Name) = LCase(TARGET_PROCESS_NAME) Then
logIndex = logIndex + 1
If logIndex <= UBound(logData, 1) Then
logData(logIndex, 1) = Now ' 検知日時
logData(logIndex, 2) = proc.Name ' プロセス名
logData(logIndex, 3) = proc.ProcessId ' PID
logData(logIndex, 4) = Round(memUsageMB, 2) & " MB" ' メモリ使用量
End If
End If
Next proc
' ワークシートへの一括書き出し処理
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
' 見出しの設定
ws.Range("A1:D1").Value = Array("検知日時", "プロセス名", "PID", "メモリ使用量")
' 既存データのクリアと一括出力
If logIndex > 0 Then
ws.Range("A2:D1001").ClearContents
ws.Range("A2").Resize(logIndex, 4).Value = logData
MsgBox "監視完了: " & logIndex & " 件の対象プロセスを検出しました。" & vbCrLf & _
TARGET_PROCESS_NAME & " の起動数: " & procCount & " 個", vbInformation, "プロセス監視完了"
Else
MsgBox "異常プロセスは検出されませんでした。", vbInformation, "プロセス監視完了"
End If
CleanUp:
' 設定のリストア
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Set wmiService = Nothing
Set processList = Nothing
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "エラー"
Resume CleanUp
End Sub
【技術解説】
WMI (Win32_Process) の活用:
GetObject("winmgmts:\\.\root\cimv2")を使用することで、外部参照設定を追加することなく遅延結合でローカル環境のシステムプロセス情報へアクセスしています。配列を活用した超高速出力: セルへ1行ずつ書き込むと描画オーバーヘッドが大きく処理速度が低下します。そのため、VBA内部の2次元配列
logDataに結果を集約し、Resizeメソッドで一括書き出しを行っています。64bit互換のWin32 API宣言: 今回は直接使用していませんが、定期監視ループなどで待機を入れる場合を想定し、
PtrSafeキーワードを使用したSleepAPI 宣言を含めています。
【注意点と運用】
権限の問題: 実行するユーザーアカウントの権限(管理者権限の有無)によっては、一部のシステムプロセス情報(WorkingSetSize 等)が取得できず Null を返す場合があります。
IsNullチェックで実行時エラーを防止してください。WMIクエリのオーバーヘッド:
ExecQuery("SELECT * FROM Win32_Process")は強力ですが、高頻度(数秒置き等)で実行するとVBA自体のCPU使用率が上昇します。一定の間隔(数分置き等)での定期実行にとどめてください。
【まとめ】
WMI×遅延結合で環境に依存しないプロセス監視を実現する。
2次元配列による一括出力で、監視ログ書き込みの処理負荷を最小化する。
API宣言はPtrSafeを徹底し、64bit Office環境での安全性を確保する。

コメント