4

小さなレガシー Delphi 5 アプリケーションに Windows アプリケーション イベント ログのサポートを追加する (かなり痛みのない) 手段を探しています。起動、シャットダウン、データベースへの接続の失敗などをログに記録したいだけです。

私が見たソリューション/コンポーネントのいくつかは、「エントリ」を読み取ろうとするときに Windows イベント ログ ビューアーがリンクするリソース DLL を作成する必要があることを示唆しているようです。これはそれほど面倒ではないように思えますが、将来アプリケーションをさらに開発する場合は、この DLL を最新の状態に保つ必要があることを念頭に置いておく必要があると思います。

将来のある時点で、おそらく D2007 で記述されたアプリケーションをサービスに変えたいと思うでしょう。

D5 のイベント ログにイベントを追加するための適切なルートを推奨できる人はいますか? Google トロールではなく、特定の「これを使用しましたが、問題ありませんでした」というコメントを探しています (これは自分で行うことができます)。将来が重要です。

4

4 に答える 4

6

概要: Delphi を使用した Windows イベント ログへの書き込み


Windows サービスを作成していて、ローカル マシンの Windows イベント ログに書き込む必要がある場合は、 TService を呼び出すことができます。ここで述べたLogMessage

//TMyTestService = class(TService)

procedure TMyTestService.ServiceStart(Sender: TService; var Started: Boolean);
begin
  LogMessage('This is an error.');
  LogMessage('This is another error.', EVENTLOG_ERROR_TYPE);
  LogMessage('This is information.', EVENTLOG_INFORMATION_TYPE);
  LogMessage('This is a warning.', EVENTLOG_WARNING_TYPE);
end;

他のタイプのアプリケーションでは、SvcMgr を使用できます。ここここここで説明されているように、ローカル マシンの Windows イベント ログを書き込む TService のTEventLogger ドキュメント化されていないヘルパー クラス。

uses
  SvcMgr;

procedure TForm1.EventLoggerExampleButtonClick(Sender: TObject);
begin
  with TEventLogger.Create('My Test App Name') do
  begin
    try
      LogMessage('This is an error.');
      LogMessage('This is another error.', EVENTLOG_ERROR_TYPE);
      LogMessage('This is information.', EVENTLOG_INFORMATION_TYPE);
      LogMessage('This is a warning.', EVENTLOG_WARNING_TYPE);
    finally
      Free;
    end;
  end;
end;

hereおよびhere で説明されているように、Windows API ReportEvent関数を使用することもできます。

簡単にするために簡単なクラスを作成しました。これはGitHubで入手できます。

//----------------- EXAMPLE USAGE: ---------------------------------

uses
  EventLog;

procedure TForm1.EventLogExampleButtonClick(Sender: TObject);
begin
  TEventLog.Source := 'My Test App Name';

  TEventLog.WriteError('This is an error.');
  TEventLog.WriteInfo('This is information.');
  TEventLog.WriteWarning('This is a warning.');
end;

//------------------------------------------------------------------


unit EventLog;

interface

type
  TEventLog = class
  private
    class procedure CheckEventLogHandle;
    class procedure Write(AEntryType: Word; AEventId: Cardinal; AMessage: string); static;
  public
    class var Source: string;
    class destructor Destroy;

    class procedure WriteInfo(AMessage: string); static;
    class procedure WriteWarning(AMessage: string); static;
    class procedure WriteError(AMessage: string); static;

    class procedure AddEventSourceToRegistry; static;
  end;

threadvar EventLogHandle: THandle;

implementation

uses Windows, Registry, SysUtils;

class destructor TEventLog.Destroy;
begin
  if EventLogHandle > 0 then
  begin
    DeregisterEventSource(EventLogHandle);
  end;
end;

class procedure TEventLog.WriteInfo(AMessage: string);
begin
  Write(EVENTLOG_INFORMATION_TYPE, 2, AMessage);
end;

class procedure TEventLog.WriteWarning(AMessage: string);
begin
  Write(EVENTLOG_WARNING_TYPE, 3, AMessage);
end;

class procedure TEventLog.WriteError(AMessage: string);
begin
  Write(EVENTLOG_ERROR_TYPE, 4, AMessage);
end;

class procedure TEventLog.CheckEventLogHandle;
begin
  if EventLogHandle = 0 then
  begin
   EventLogHandle := RegisterEventSource(nil, PChar(Source));
  end;
  if EventLogHandle <= 0 then
  begin
    raise Exception.Create('Could not obtain Event Log handle.');
  end;
end;

class procedure TEventLog.Write(AEntryType: Word; AEventId: Cardinal; AMessage: string);
begin
  CheckEventLogHandle;
  ReportEvent(EventLogHandle, AEntryType, 0, AEventId, nil, 1, 0, @AMessage, nil);
end;

// This requires admin rights. Typically called once-off during the application's installation
class procedure TEventLog.AddEventSourceToRegistry;
var
  reg: TRegistry;
begin
  reg := TRegistry.Create;
  try
    reg.RootKey := HKEY_LOCAL_MACHINE;
    if reg.OpenKey('\SYSTEM\CurrentControlSet\Services\Eventlog\Application\' + Source, True) then
    begin
      reg.WriteString('EventMessageFile', ParamStr(0)); // The application exe's path
      reg.WriteInteger('TypesSupported', 7);
      reg.CloseKey;
    end
    else
    begin
      raise Exception.Create('Error updating the registry. This action requires administrative rights.');
    end;
  finally
    reg.Free;
  end;
end;

initialization

TEventLog.Source := 'My Application Name';

end.

ReportEventは、ローカルまたはリモート マシンのイベント ログへのログ エントリの書き込みをサポートしています。リモートの例については、 John Kaster の EDN 記事を参照してください。


また、メッセージ ファイルを作成してイベント ソースを登録する必要があることに注意してください。そうしないと、すべてのログ メッセージが次のような内容で始まります。

ソース xxxx からのイベント ID xxx の説明が見つかりません。このイベントを発生させるコンポーネントがローカル コンピューターにインストールされていないか、インストールが破損しています。コンポーネントをローカル コンピューターにインストールまたは修復できます。

イベントが別のコンピューターで発生した場合、表示情報をイベントと共に保存する必要がありました。

イベントには次の情報が含まれていました。

1、メッセージ ファイルの作成方法の詳細については、Finn Tolderlund のチュートリアルまたはMichael Hex の記事を参照するか、GitHub プロジェクトに含まれて いる既存の MC および RES ファイルを使用できます。

2. DPR ファイルに MessageFile.res を含めて、RES ファイルをアプリケーションに埋め込みます。または、メッセージ用の dll を作成することもできます。

program MyTestApp;

uses
  Forms,
  FormMain in 'FormMain.pas' {MainForm},
  EventLog in 'EventLog.pas';

{$R *.res}
{$R MessageFile\MessageFile.res}

begin
  Application.Initialize;

3. 1 回限りの登録には管理者権限によるレジストリへの書き込みが必要なため、通常はアプリケーションのインストール プロセスの一部として行います。

//For example
AddEventSourceToRegistry('My Application Name', ParamStr(0));
//or
AddEventSourceToRegistry('My Application Name', 'C:\Program Files\MyApp\Messages.dll');

//--------------------------------------------------

procedure AddEventSourceToRegistry(ASource, AFilename: string);
var
  reg: TRegistry;
begin
  reg := TRegistry.Create;
  try
    reg.RootKey := HKEY_LOCAL_MACHINE;
    if reg.OpenKey('\SYSTEM\CurrentControlSet\Services\Eventlog\Application\' + ASource, True) then
    begin
      reg.WriteString('EventMessageFile', AFilename);
      reg.WriteInteger('TypesSupported', 7);
      reg.CloseKey;
    end
    else
    begin
      raise Exception.Create('Error updating the registry. This action requires administrative rights.');
    end;
  finally
    reg.Free;
  end;
end;

Windows イベント ログやその他のログ要件が必要な場合は、log4dTraceToolなどのログ フレームワークを使用することもできます。


Delphi IDE のイベント ログ ウィンドウに書き込みたい場合は、こちらを参照してください。

于 2015-05-14T06:41:37.203 に答える
4

D5 での簡単なイベント ログのために、次のコードを使用してアプリケーション ログにメッセージを追加しました。

  • uses 句に「SvcMgr」を追加
  • このコードを使用して、テキスト メッセージと ID 番号を追加します (LogMessage 行の最後のパラメーター)。

    with TEventLogger.create('My Application Name') do
    begin
      try
        LogMessage('Information Message!', EVENTLOG_INFORMATION_TYPE, 0, 1);
        LogMessage('Error Message!', EVENTLOG_ERROR_TYPE, 0, 2);
        LogMessage('Warning Message!', EVENTLOG_WARNING_TYPE, 0, 3);
        LogMessage('Audit Success Message!', EVENTLOG_AUDIT_SUCCESS, 0, 4);
        LogMessage('Audit Failure Message!', EVENTLOG_AUDIT_FAILURE, 0, 5);
      finally
        free;
      end;
    end;
    
于 2009-03-26T11:15:45.200 に答える
3

これには Delphi 6 で標準の VCL を使用しています。これが Delphi 5 で利用できるかどうかはわかりません。自分で試してみて、D5 にこの機能があるかどうかをお知らせください。

  1. TEventLogger 型のグローバル/フォーム変数を宣言します。これは SvcMgr ユニットで宣言されているため、このユニットを uses リストに追加する必要があります。これが通常のアプリケーション (つまり、サービスではない) の場合は、Forms ユニットの後に SvcMgr が追加されていることを確認してください。

    MyEventLog: TEventLogger;

  2. ロガーのインスタンスを作成します。

    MyEventLog := TEventLogger.Create('MyApplication');

  3. イベント ログに書き込むには:

    MyEventLog.LogMessage('MyApplication started.'), EVENTLOG_INFORMATION_TYPE);

  4. 最後にリリースすることを忘れないでください:

    MyEventLog.Free;

アプリケーションを Windows イベント ログに登録して、メッセージが前に表示されずに表示されるようにするために必要な作業は他にもあります。

ソース (Microsoft Internet Explorer) のイベント ID (1000) の説明が見つかりません。ローカル コンピュータに、リモート コンピュータからのメッセージを表示するために必要なレジストリ情報またはメッセージ DLL ファイルがない可能性があります。以下の情報はイベントの一部です。

于 2009-03-26T10:40:31.637 に答える
1

JとPeterの応答のおかげで、コードをイベントログにすぐに書き込むことができました。特に、説明が見つからないという標準のWindowsメッセージなしでイベントログにイベントを「きれいに」表示したい場合は、もう少しやることがあります(Jの投稿の下部にあります)。

ここでのヒントに従って、適切なDLLを作成してレジストリに入力し、すぐにすべてを整理しました。

質問によると、これはすべてDelphi5に含まれていましたが、D2007でも機能しないと思わせるようなものは何も見ていません。

于 2009-03-27T07:20:34.887 に答える