JNAからWindows Event Log APIを呼び出してイベントログを取得してみる(EvtFormatMessage関数を利用)

以下のエントリーでは EvtRender関数を利用してイベントログのレンダリングを行っていましたが、EvtFormatMessage関数というのもあるみたいなので、こちらの関数を使うサンプルを書いてみました。

a4dosanddos.hatenablog.com

以下のドキュメントのコードを参考に実装しています。

Formatting Event Messages (Windows)

あまり使い分けとかわかってないですが、EvtFormatMessage関数を使った場合、RenderingInfoセクションあたりの情報も取れてくるって感じなんですかね。

EvtRender function (Windows)
EvtFormatMessage function (Windows)


実際のサンプルは以下の感じ。EvtFormatMessage関数の呼び出しにはプロバイメタデータ(この詳細はわかっていない・・・)のハンドルを与えてやる必要があるみたいなので、EvtOpenPublisherMetadata関数の結果を引数に渡してやっています。

※ しかし、EvtOpenPublisherMetadata関数の第二引数に何を渡したらいいのかがわかりません・・・とりあえず空文字(new WString(""))でも動いたので正しいかどうかはさておき今回はこれで・・・
これはドキュメントに書いてあるままプロバイダ名でいいようです。

EvtOpenPublisherMetadata function (Windows)

※ zabbixのソースコードも見てみましたが、プロバイダ名を渡していそうです。

https://support.zabbix.com/secure/attachment/13369/eventlog.c


・サンプル(EvtFormatMessage関数の呼び出し箇所のみ抜粋)

	private String formatEvent(HANDLE h) throws Exception {
		HANDLE hProviderMetadata = null;
		try {
			hProviderMetadata = Wevtapi.INSTANCE.EvtOpenPublisherMetadata(null, new WString(""), null, 0, 0);
			if(hProviderMetadata == null)
				throw new Exception("EvtOpenPublisherMetadata Error errorCode=" + getLastErrorWrapper());
			
			Pointer buffer = null;
		    int bufferSize = 0;
		    IntByReference bufferUsed = new IntByReference(0);

		    if (!Wevtapi.INSTANCE.EvtFormatMessage(hProviderMetadata, h, 0, 0, null, Wevtapi.INSTANCE.EvtFormatMessageXml, bufferSize, buffer, bufferUsed)) {
		    	if (getLastErrorWrapper() == WinError.ERROR_INSUFFICIENT_BUFFER) {
		    		bufferSize = bufferUsed.getValue();
		    		buffer = new Memory(bufferSize);
		    		if(buffer != null)
		    			Wevtapi.INSTANCE.EvtFormatMessage(hProviderMetadata, h, 0, 0, null, Wevtapi.INSTANCE.EvtFormatMessageXml, bufferSize, buffer, bufferUsed);
		    		else 
		    			throw new Exception("malloc Error errorCode=" + getLastErrorWrapper());
		    	}
		    	if(WinError.ERROR_SUCCESS != getLastErrorWrapper())
		    		throw new Exception("EvtFormatMessage Error errorCode=" + getLastErrorWrapper());
		    }
		    return buffer.getWideString(0);
		} finally {
			if(hProviderMetadata != null)
				Wevtapi.INSTANCE.EvtClose(hProviderMetadata);
		}
	}


EvtRender関数との取得結果を比較すると以下のようになります。確かに EvtFormatMessage関数では RenderingInfoセクションの情報が取れますね。

・EvtRender関数の場合

<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Cmd'/><EventID Qualifiers='0'>100</EventID><Level>4</Level><Task>0</Task><Keywords>0x80000000000000</Keywords><TimeCreated SystemTime='2016-08-11T01:23:09.130579500Z'/><EventRecordID>5889</EventRecordID><Channel>System</Channel><Computer>test-pc</Computer><Security UserID='*****'/></System><EventData><Data>test</Data></EventData></Event>

・EvtFormatMessage関数の場合

<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Cmd1'/><EventID Qualifiers='0'>100</EventID><Level>4</Level><Task>0</Task><Keywords>0x80000000000000</Keywords><TimeCreated SystemTime='2016-08-12T01:48:47.005387300Z'/><EventRecordID>4990</EventRecordID><Channel>Application</Channel><Computer>test-pc</Computer><Security UserID='*****'/></System><EventData><Data>test</Data></EventData>
<RenderingInfo Culture='ja-JP'><Message></Message><Level>情報</Level><Task></Task><Opcode>情報</Opcode><Channel></Channel><Provider></Provider><Keywords><Keyword>クラシック</Keyword></Keywords></RenderingInfo></Event>


以上になります。

[環境情報]
Windows 10
Java SE 8 Update 92
JNA 4.2.2