イベント ログ ファイルの形式

Windows Vista 以降のイベント ログは、拡張子 .evtx という新しいフォーマットになりました。
この変更により、従来のイベント ログ拡張子 .evt 形式の互換性ですが、保存はできず、読み込みだけが可能です。
ただし、WMI の API である BackupEventLog() をプログラムで実装することで、拡張子 .evt で保存することができます。
ここで拡張子 .evt について、一つ注意事項があります。
.evt 形式ですが、従来のイベントログ形式 (.evt) と Windows Vista 以降で API BackupEventLog() で作成した .evt は
同じ拡張子でも、フォーマット形式が異なります。

  1. 旧イベントログ フォーマット形式 (拡張子 .evt)
    Windows Server 2003 までの OS で使用していたイベントログ フォーマット形式
  2. レガシー イベントログ フォーマット形式 (拡張子 .evt)
    Windows Vista 以降の OS で BackupEventLog() を使い、出力したイベントログ フォーマット形式
    このイベントログは、Windows Server 2003 までの OS では正しく読み込めないので、
    Windows Vista 以降の OS で読み込む必要がある
  3. 新イベントログ フォーマット形式 (拡張子 .evtx)
    Windows Vista 以降の OS で採用されているイベントログ フォーマット形式

同じ拡張子で、フォーマットが異なるのは悩ましいところです。
なお、拡張子 .evt のフォーマットを .evtx に変換するには、イベントビューアーで .evt を開いて、.evtx で保存するか
wevtuil.exe というコマンドラインツールを使う方法があります。

例えば、wevtuil.exe を使うなら

wevtutil epl application.evt app_new.evtx /lf:true

という具合です。

なお、新イベントログ フォーマット形式 (拡張子 .evtx) を操作するには、新しい API セットがありますので
こちらを使うようにしましょう。

イベントログは奥が非常に深いです。

イベントログで使うメッセージファイル DLLを作成する

Windows Vista & 2008 では新しいイベントログ システムにバージョンアップしました。
Windows Event Log という名前になっています。
従来のイベントログは、*.evt という形式で保存されていましたが、Windows Event Log では
*.evtx という XML 形式で保存されています。
また、サブスクライバモデルが導入されているため、イベントログを別の Windows に転送することも
できちゃいます。便利ですね~。でも、今回のネタは新機能ではなく、従来からの SDK ネタです。
ちょっと古いような気もしますが、まだまだ需要はあると思います。
MSDN のイベントログに関する内容は

にあります。ぜひ、参照してみてください。
プログラムでイベントログにイベントを出力する際には

BOOL ReportEvent(
  HANDLE hEventLog,    // イベントログのハンドル
  WORD wType,          // ログに書き込むイベントの種類
  WORD wCategory,      // イベントの分類
  DWORD dwEventID,     // イベント識別子
  PSID lpUserSid,      // ユーザーセキュリティ識別子(省略可能)
  WORD wNumStrings,    // メッセージにマージする文字列の数
  DWORD dwDataSize,    // バイナリデータのサイズ(バイト数)
  LPCTSTR *lpStrings,  // メッセージにマージする文字列の配列
  LPVOID lpRawData     // バイナリデータのアドレス
);

という API を使用します。この API を使って、書き出したい文字列を渡してもいいのですが
多国語対応するときには、ちょっと面倒です。そのため、イベントログでは、メッセージファイルという専用の
バイバリリソースを持つことで言語をニュートラルにすることができます。
今回は、そのメッセージファイルを作成してみます。

まずは、全体の流れです。

メッセージDLL作成

1. メッセージファイルの作成

拡張子 mc というメッセージファイル(テキストファイル)を作成します。
どのような構文なのかは、以下の URL を参考にしてください。

今回は、EventlogMsg.mc というファイルを作成します。
このファイルで英語と日本語のメッセージをサポートしてみます。

; // ***** EventlogMsg.mc *****
; // This is the header section.MessageIdTypedef=DWORDSeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
    Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
    Warning=0x2:STATUS_SEVERITY_WARNING
    Error=0x3:STATUS_SEVERITY_ERROR
    )FacilityNames=(System=0x0:FACILITY_SYSTEM
    Runtime=0x2:FACILITY_RUNTIME
    Stubs=0x3:FACILITY_STUBS
    Io=0x4:FACILITY_IO_ERROR_CODE
)LanguageNames=(English=0x409:MSG00409)
LanguageNames=(Japanese=0x411:MSG00411); // The following are message definitions.MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=MSG_BAD_COMMAND
Language=English
You have chosen an incorrect command.
.
Language=Japanese
誤ったコマンドが選択されました。
.
MessageId=0x2
Severity=Warning
Facility=Io
SymbolicName=MSG_BAD_CONN
Language=English
Cannot connect to the server.
.
Language=Japanese
サーバーに接続できません。
.
MessageId=0x3
Severity=Error
Facility=System
SymbolicName=MSG_CMD_DELETE
Language=English
File %1 contains %2 which is in error
.
Language=Japanese
ファイル %1 にエラーはある %2 が含まれています。
.
MessageId=0x4
Severity=Informational
Facility=System
SymbolicName=MSG_RETRYS
Language=English
There have been %1!d! attempts with %2!d!%% success%! Disconnect from the server and try again later.
.
Language=Japanese
%1!d! 回再試行し、%2!d!%% 回成功しました %! サーバーから切断してから再試行してください。
.

メッセージファイルを作成する際の注意事項ですが、メッセージの区切り「.(ピリオド)」を正しく入力してください
後ろにスペースがあったりすると、メッセージコンパイラでコンパイルエラーになります。

2. メッセージコンパイラでコンパイルする

1. で作成したメッセージファイルをコンパイルします。
Visual Studio をインストールすると、メッセージコンパイラ(MC.EXE)がインストールされます。[スタートメニュー]-[Microsoft Visual Studio 2008]-[Visual Studio Tools]にある「Visual Studio 2008 コマンド プロンプト」を開いてみます。

mc

そのコマンドプロンプトで mc と入力してみてください。

パラメーターが必要なことがわかります。
今回は、

mc -s -U EventlogMsg.mc

というコマンドを入力します。すると

  • MSG00409.bin
  • MSG00411.bin
  • EventlogMsg.h
  • EventlogMsg.rc

という 4 つのファイルが生成されます。

3. Visual Studio で DLL を作成する ここまで来たら、あとは、DLL を作成するだけです。

EventlogMsg_プロジェクト作成1

EventlogMsg_プロジェクト作成2

ここに先ほど作成された 4つのファイルをプロジェクトのソースがあるところにコピーしておきます。
そして、プロジェクトに EventlogMsg.h と EventlogMsg.rc を追加します。
bin ファイルはバイナリファイルなので、プロジェクトに追加する必要はありません。
これで DLL のビルドを行えば完成なのですが、その前に少しだけチューニングします。
まず、この DLL は、メッセージリソースファイルだけの DLL にしたいので、
リンカの設定で「エントリポイントなし」「はい」にしておきます。(/NOENTRY の設定)

リンカの設定1

次にマニフェストも必要ないので「マニフェストの生成」「いいえ」「埋め込みマニフェスト」「いいえ」にしておきます。

リンカの設定2

リンカの設定3

これですべて準備完了です。ビルドしてみると、EventlogMsg.dll ができます。では、本当にメッセージ DLL ができたのか
確認してみます。
何か適当なリソースエディタでビルドした DLL を開いてください。(今回は Resource Hacker を使ってみます)

ResHac_メッセージ確認

きちんとリソースとしてメッセージができていますね。
あとはアプリケーションから ReportEvent() を使い、イベントログに書き込めばいいわけです。

メッセージファイルをレジストリ登録するのをお忘れなく。

それでは。