The Grimoire of Nonsense

個人的なメモを残すブログ

イベントログと戦う

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;
}