<p><prompt_strategy: efficient_automation_design=""></prompt_strategy:></p>
<p>本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">VBAで実現するWMIプロセス監視:特定アプリの暴走とリソース枯渇の自動検知</h1>
<h3 class="wp-block-heading">【背景と目的】</h3>
<p>外部連携ソフトのフリーズや、VBA実行中のメモリリークによるPC停止を未然に防ぐため、WMIを用いてOSのプロセス負荷を監視し、異常時に警告を発します。</p>
<h3 class="wp-block-heading">【処理フロー図】</h3>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A["開始"] --> B["WMIサービスへ接続"]
B --> C["特定プロセスのリソース取得"]
C --> D{"閾値を超過しているか?"}
D -- Yes --> E["異常検知ログの書き出し"]
D -- No --> F["正常終了/待機"]
E --> G["指定プロセスの強制終了検討"]
G --> H["終了"]
F --> H
</pre></div>
<h3 class="wp-block-heading">【実装:VBAコード】</h3>
<pre data-enlighter-language="generic">Option Explicit
' --- Win32 API 宣言 (64bit環境対応) ---
#If Win64 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
''' <summary>
''' 指定したプロセスのCPU使用率とメモリ使用量を監視し、Excelシートへ記録する
''' </summary>
Public Sub MonitorProcessPerformance()
Dim strComputer As String: strComputer = "."
Dim strProcessName As String: strProcessName = "Excel.exe" ' 監視対象プロセス名
Dim objWMIService As Object
Dim colProcesses As Object
Dim objProcess As Object
Dim results() As Variant
Dim i As Long: i = 1
' 描画停止による高速化
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
' WMIサービスへの接続
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
' プロセス情報の取得 (Win32_PerfFormattedData_PerfProc_Process を使用して計算済み負荷を取得)
Set colProcesses = objWMIService.ExecQuery( _
"SELECT * FROM Win32_PerfFormattedData_PerfProc_Process WHERE Name = '" & Left(strProcessName, InStrRev(strProcessName, ".") - 1) & "'")
' 結果格納用の配列準備 (行: 項目, 列: データ)
ReDim results(1 To 2, 1 To 4)
results(1, 1) = "プロセス名"
results(1, 2) = "CPU使用率(%)"
results(1, 3) = "メモリ使用量(MB)"
results(1, 4) = "取得時刻"
For Each objProcess In colProcesses
i = i + 1
ReDim Preserve results(1 To 2, 1 To i)
results(2, 1) = objProcess.Name
results(2, 2) = objProcess.PercentProcessorTime
results(2, 3) = Round(objProcess.WorkingSetPrivate / 1024 / 1024, 2) ' Byte -> MB
results(2, 4) = Now
' 異常検知ロジック (例: CPU 90%以上 または メモリ 1GB以上)
If objProcess.PercentProcessorTime > 90 Or (objProcess.WorkingSetPrivate / 1024 / 1024) > 1024 Then
MsgBox "警告: " & objProcess.Name & " の負荷が閾値を超えました。", vbCritical
End If
Next
' シートへの一括書き出し (セルへの個別アクセスを避けて高速化)
If i > 1 Then
Range("A1").Resize(UBound(results, 2), UBound(results, 1)).Value = Application.Transpose(results)
Else
Debug.Print "対象プロセスが見つかりませんでした。"
End If
CleanUp:
Set colProcesses = Nothing
Set objWMIService = Nothing
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbExclamation
Resume CleanUp
End Sub
</pre>
<h3 class="wp-block-heading">【技術解説】</h3>
<ol class="wp-block-list">
<li><p><strong>WMI (Windows Management Instrumentation)</strong>:
Windowsのシステム情報を取得するための標準インターフェースです。今回は <code>Win32_PerfFormattedData_PerfProc_Process</code> クラスを利用し、OS側で計算済みのCPU使用率を直接取得しています(手動計算不要)。</p></li>
<li><p><strong>PtrSafe 宣言</strong>:
<code>Sleep</code> などの API を使用する場合、64bit Office環境でのクラッシュを防ぐために必須の記述です。</p></li>
<li><p><strong>配列による一括出力</strong>:
セルに対してループ内で書き込みを行うと極端に動作が重くなるため、一度配列に格納してから <code>Resize</code> メソッドで一括出力しています。</p></li>
</ol>
<h3 class="wp-block-heading">【注意点と運用】</h3>
<ul class="wp-block-list">
<li><p><strong>WMIの負荷</strong>:
WMIクエリは強力ですが、頻繁(1秒未満の間隔など)に実行すると、監視自体がCPUリソースを消費します。監視間隔は5秒〜1分程度を推奨します。</p></li>
<li><p><strong>権限の問題</strong>:
他ユーザーのプロセス情報を取得する場合、Excelを「管理者として実行」する必要がある場合があります。</p></li>
<li><p><strong>プロセス名の指定</strong>:
<code>Win32_PerfFormattedData</code> クラスでは、拡張子(.exe)を除いた名前を指定する必要がある点に注意してください。</p></li>
</ul>
<h3 class="wp-block-heading">【まとめ】</h3>
<ul class="wp-block-list">
<li><p>WMIを活用することで、VBAからOSレベルのリソース監視が容易になる。</p></li>
<li><p>配列処理とAPIの適切な宣言(PtrSafe)により、高速かつ安定したツールが構築可能。</p></li>
<li><p>異常検知時はメッセージボックスだけでなく、ログファイルへの追記や自動メール送信へ拡張するのが実用的。</p></li>
</ul>
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
VBAで実現するWMIプロセス監視:特定アプリの暴走とリソース枯渇の自動検知
【背景と目的】
外部連携ソフトのフリーズや、VBA実行中のメモリリークによるPC停止を未然に防ぐため、WMIを用いてOSのプロセス負荷を監視し、異常時に警告を発します。
【処理フロー図】
graph TD
A["開始"] --> B["WMIサービスへ接続"]
B --> C["特定プロセスのリソース取得"]
C --> D{"閾値を超過しているか?"}
D -- Yes --> E["異常検知ログの書き出し"]
D -- No --> F["正常終了/待機"]
E --> G["指定プロセスの強制終了検討"]
G --> H["終了"]
F --> H
【実装:VBAコード】
Option Explicit
' --- Win32 API 宣言 (64bit環境対応) ---
#If Win64 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
''' <summary>
''' 指定したプロセスのCPU使用率とメモリ使用量を監視し、Excelシートへ記録する
''' </summary>
Public Sub MonitorProcessPerformance()
Dim strComputer As String: strComputer = "."
Dim strProcessName As String: strProcessName = "Excel.exe" ' 監視対象プロセス名
Dim objWMIService As Object
Dim colProcesses As Object
Dim objProcess As Object
Dim results() As Variant
Dim i As Long: i = 1
' 描画停止による高速化
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
' WMIサービスへの接続
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
' プロセス情報の取得 (Win32_PerfFormattedData_PerfProc_Process を使用して計算済み負荷を取得)
Set colProcesses = objWMIService.ExecQuery( _
"SELECT * FROM Win32_PerfFormattedData_PerfProc_Process WHERE Name = '" & Left(strProcessName, InStrRev(strProcessName, ".") - 1) & "'")
' 結果格納用の配列準備 (行: 項目, 列: データ)
ReDim results(1 To 2, 1 To 4)
results(1, 1) = "プロセス名"
results(1, 2) = "CPU使用率(%)"
results(1, 3) = "メモリ使用量(MB)"
results(1, 4) = "取得時刻"
For Each objProcess In colProcesses
i = i + 1
ReDim Preserve results(1 To 2, 1 To i)
results(2, 1) = objProcess.Name
results(2, 2) = objProcess.PercentProcessorTime
results(2, 3) = Round(objProcess.WorkingSetPrivate / 1024 / 1024, 2) ' Byte -> MB
results(2, 4) = Now
' 異常検知ロジック (例: CPU 90%以上 または メモリ 1GB以上)
If objProcess.PercentProcessorTime > 90 Or (objProcess.WorkingSetPrivate / 1024 / 1024) > 1024 Then
MsgBox "警告: " & objProcess.Name & " の負荷が閾値を超えました。", vbCritical
End If
Next
' シートへの一括書き出し (セルへの個別アクセスを避けて高速化)
If i > 1 Then
Range("A1").Resize(UBound(results, 2), UBound(results, 1)).Value = Application.Transpose(results)
Else
Debug.Print "対象プロセスが見つかりませんでした。"
End If
CleanUp:
Set colProcesses = Nothing
Set objWMIService = Nothing
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbExclamation
Resume CleanUp
End Sub
【技術解説】
WMI (Windows Management Instrumentation):
Windowsのシステム情報を取得するための標準インターフェースです。今回は Win32_PerfFormattedData_PerfProc_Process クラスを利用し、OS側で計算済みのCPU使用率を直接取得しています(手動計算不要)。
PtrSafe 宣言:
Sleep などの API を使用する場合、64bit Office環境でのクラッシュを防ぐために必須の記述です。
配列による一括出力:
セルに対してループ内で書き込みを行うと極端に動作が重くなるため、一度配列に格納してから Resize メソッドで一括出力しています。
【注意点と運用】
WMIの負荷:
WMIクエリは強力ですが、頻繁(1秒未満の間隔など)に実行すると、監視自体がCPUリソースを消費します。監視間隔は5秒〜1分程度を推奨します。
権限の問題:
他ユーザーのプロセス情報を取得する場合、Excelを「管理者として実行」する必要がある場合があります。
プロセス名の指定:
Win32_PerfFormattedData クラスでは、拡張子(.exe)を除いた名前を指定する必要がある点に注意してください。
【まとめ】
WMIを活用することで、VBAからOSレベルのリソース監視が容易になる。
配列処理とAPIの適切な宣言(PtrSafe)により、高速かつ安定したツールが構築可能。
異常検知時はメッセージボックスだけでなく、ログファイルへの追記や自動メール送信へ拡張するのが実用的。
コメント