イベントログと戦う
Vista以降で追加されたAPIでイベントログの数を調べつつ1件以上データがあればクリアするように書きたい(切望)
有効か無効か調べないとどうも正しい件数が取得できないのかな?
その辺で苦戦してる。
※以下駄文は管理者として動かす必要があります。
※あんまりテストしてないので正しく動かないかもしれません。
※ごっちゃごちゃのぎったぎたですが気にしないでください。
以下途中経過
#include <cstdio> #include <clocale> #include <algorithm> #include <vector> #include <Windows.h> #include <WinEvt.h> #pragma comment( lib, "Wevtapi.lib" ) using namespace std; typedef vector<wstring> EvtArray; namespace { enum class ReturnStatus { EvtOK = 0, EvtLogDisabled, EvtOpenChannelConfigFailed, EvtGetChannelConfigPropertyFailed, EvtOpenLogFailed, EvtGetLogInfoFailed, }; const wchar_t *evtLogEntries[] = { L"SYSTEM\\CurrentControlSet\\services\\eventlog", L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Channels", }; const unsigned entriesSize = sizeof( evtLogEntries ) / sizeof( evtLogEntries[0] ); bool collectLogs( EvtArray& evtArray ) { for ( unsigned i = 0U; i < entriesSize; i++ ) { HKEY hKey = nullptr; unsigned regIndex = 0; LONG lRes = 0; lRes = RegOpenKeyEx( HKEY_LOCAL_MACHINE, evtLogEntries[i], 0, KEY_READ | KEY_WOW64_64KEY, &hKey ); if ( FAILED( lRes ) ) { wprintf( L"Error: レジストリキー %s が開けなかった\n", evtLogEntries[i] ); return false; } while ( true ) { wchar_t buffer[1024] = { 0 }; DWORD bufferLen = sizeof( buffer ) / sizeof( buffer[0] ); FILETIME tmp = { 0 }; lRes = RegEnumKeyEx( hKey, regIndex, buffer, &bufferLen, nullptr, nullptr, nullptr, &tmp ); // 各条件で分ける if ( lRes == ERROR_NO_MORE_ITEMS ) break; else if ( FAILED( lRes ) ) { wprintf( L"Error: エントリの列挙に失敗\n" ); wprintf( L"lRes: %u\n", lRes ); return false; } evtArray.push_back( buffer ); regIndex++; } } return true; } bool getEvtLogEnabled( wstring &logName, ReturnStatus *res ) { EVT_HANDLE hEvt = nullptr; EVT_VARIANT evtVar = { 0 }; DWORD dUserdBuffer = 0; BOOL bRes = FALSE; // ログ開く! hEvt = EvtOpenChannelConfig( nullptr, logName.c_str(), 0 ); if ( hEvt == nullptr ) { if ( res != nullptr ) *res = ReturnStatus::EvtOpenChannelConfigFailed; return false; } // 有効か調べる! bRes = EvtGetChannelConfigProperty( hEvt, EVT_CHANNEL_CONFIG_PROPERTY_ID::EvtChannelConfigEnabled, 0, sizeof( EVT_VARIANT ), &evtVar, &dUserdBuffer ); if ( FAILED( bRes ) ) { if ( res != nullptr ) *res = ReturnStatus::EvtGetChannelConfigPropertyFailed; return false; } EvtClose( hEvt ); if ( res != nullptr ) *res = evtVar.BooleanVal == TRUE ? ReturnStatus::EvtOK : ReturnStatus::EvtLogDisabled; return evtVar.BooleanVal == TRUE; } UINT64 getEvtLogRecords( wstring &logName, ReturnStatus *res ) { EVT_HANDLE hEvt = nullptr; EVT_VARIANT evtVar = { 0 }; DWORD dUserdBuffer = 0; BOOL bRes = FALSE; if ( !getEvtLogEnabled( logName, res ) ) return 0ULL; hEvt = EvtOpenLog( nullptr, logName.c_str(), EvtOpenChannelPath ); if ( hEvt == nullptr ) { if ( res != nullptr ) *res = ReturnStatus::EvtOpenLogFailed; return 0ULL; } bRes = EvtGetLogInfo( hEvt, EVT_LOG_PROPERTY_ID::EvtLogNumberOfLogRecords, sizeof( EVT_VARIANT ), &evtVar, &dUserdBuffer ); if ( FAILED( bRes ) ) { if ( res != nullptr ) *res = ReturnStatus::EvtGetLogInfoFailed; EvtClose( hEvt ); return 0ULL; } EvtClose( hEvt ); if ( res != nullptr ) *res = ReturnStatus::EvtOK; return evtVar.Int64Val; } void arraySort( EvtArray &evtArray ) { stable_sort( evtArray.begin(), evtArray.end(), [=]( wstring a, wstring b ) { transform( a.begin(), a.end(), a.begin(), tolower ); transform( b.begin(), b.end(), b.begin(), tolower ); return a < b; } ); } } int wmain( const int argc, const wchar_t **argv ) { EvtArray evtArray; _wsetlocale( LC_ALL, L"" ); collectLogs( evtArray ); arraySort( evtArray ); for ( wstring str : evtArray ) { ReturnStatus status; UINT64 logRecordsNum = getEvtLogRecords( str, &status ); wprintf( L"%s: ", str.c_str() ); if ( status == ReturnStatus::EvtOK ) wprintf( L"%I64u\n", logRecordsNum ); else if ( status == ReturnStatus::EvtLogDisabled ) wprintf( L"(disabled)\n" ); else wprintf( L"(error)\n" ); } return 0; }