将Windows事件日志改造为Delphi 5应用程序

时间:2009-03-26 08:18:54

标签: delphi delphi-5 event-log

我正在寻找一种(相当无痛)的方法,将一些Windows应用程序事件日志支持添加到一个小型的传统Delphi 5应用程序中。我们只是希望它在启动,关闭,无法连接到数据库等时进行记录。

我见过的几个解决方案/组件似乎暗示我们需要创建一个资源DLL,Windows事件日志查看器将在尝试读取我们的“条目”时链接到该资源DLL。虽然这似乎并不太繁琐,但我想如果/我们将来进一步开发应用程序时要记住这一点 - 我们需要保持这个DLL是最新的。

在未来的某个时刻,我们希望将应用程序转变为服务,可能是在D2007中编写的。

那么有人可以推荐一个合适的路径来为D5中的事件日志添加事件吗?我正在寻找具体的'我们用过这个,它没关系'评论而不是Google拖网(我可以自己做!)免费或付费,真的不介意 - 但是有些东西我将来可以迁移到D2007很重要。

4 个答案:

答案 0 :(得分:6)

摘要:使用Delphi写入Windows事件日志

如果您正在编写Windows服务并需要写入本地计算机的Windows事件日志,则可以调用 提到的TService.LogMessage here

//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。 TEventLogger undocumented帮助程序类来为TService编写本地计算机的Windows事件日志,如上所述here,{ {3}}和here

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;

您还可以使用上述hereReportEvent提供的Windows API here功能。

我创建了一个简单的类,以便更轻松,它是here

//----------------- 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.

available on GitHub支持将日志条目写入本地或远程计算机的事件日志。有关远程示例,请参阅ReportEvent

请注意,您还必须John Kaster's EDN articlecreate a message file ,否则您的所有日志消息都将以以下内容开头:

  

源xxxx的事件ID xxx的描述不能   找到。未安装引发此事件的组件   您的本地计算机或安装已损坏。你可以安装   或修复本地计算机上的组件。

     

如果事件源自另一台计算机,则显示信息   不得不与事件一起得救。

     

活动中包含以下信息:

1,有关如何创建消息文件的详细信息,请参阅register your event sourceFinn Tolderlund's tutorial 或者您可以使用现有的MC和Michael Hex's article

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,一次性注册需要管理员权限写入注册表,因此我们通常在应用程序的安装过程中完成。

//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事件日志记录和其他日志记录要求,您还可以使用日志框架,例如RES file included in the GitHub projectlog4d

如果要写入Delphi IDE中的“事件日志”窗口,请参阅TraceTool

答案 1 :(得分:4)

对于D5中的简单事件记录,我使用以下代码将消息添加到应用程序日志。

  • 将“SvcMgr”添加到uses子句
  • 使用此代码添加短信和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;
    

答案 2 :(得分:3)

我在Delphi 6中使用标准VCL,我无法告诉你这是否在Delphi 5中可用。请亲自尝试一下,如果D5中存在这些内容,请告诉我们。

  1. 声明TEventLogger类型的全局/表单变量。这是在SvcMgr单元中声明的,因此需要将此单元添加到您的使用列表中。如果这是一个普通的应用程序(即不是服务),那么请确保在Forms单元之后添加SvcMgr。

    MyEventLog:TEventLogger;

  2. 创建记录器的实例。

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

  3. 要写入事件日志:

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

  4. 不要忘记在最后发布它:

    MyEventLog.Free;

  5. 使用Windows事件日志注册应用程序时还需要执行其他操作,以便在此前面显示消息:

    找不到源(Microsoft Internet Explorer)中事件ID(1000)的说明。本地计算机可能没有必要的注册表信息或消息DLL文件来显示来自远程计算机的消息。以下信息是活动的一部分:

答案 3 :(得分:1)

感谢 J 和Peter的回复,我立即将代码写入事件日志。还有一点要做,特别是如果你希望你的事件在事件日志中“很好地”出现而没有关于无法找到描述的标准窗口消息(根据 J 的帖子)。

我按照提示here制作了一个合适的DLL并将其输入到注册表中,很快就完成了整理。

根据问题,这完全在Delphi5中,但我没有看到任何让我觉得它在D2007中也不会起作用的东西。