代码之家  ›  专栏  ›  技术社区  ›  robsoft

将Windows事件日志更新到Delphi 5应用程序

  •  4
  • robsoft  · 技术社区  · 16 年前

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

    我看到的一些解决方案/组件似乎建议我们需要创建一个资源dll,当试图读取“条目”时,Windows事件日志查看器将链接到该dll。虽然这看起来不太麻烦,但我想如果/当我们在将来进一步开发应用程序时,应该记住这一点——我们需要保持这个DLL是最新的。

    在将来的某个时候,我们将希望将应用程序转换为服务,可能是用d2007编写的。

    那么,有人能推荐一个合适的路径来将事件添加到D5中的事件日志中吗?我在找具体的 我们用过这个没问题 “评论而不是谷歌搜索(我可以自己做!)不管是免费的还是付费的,真的不介意——但是我将来可以迁移到2007年的一些东西是很重要的。

    4 回复  |  直到 10 年前
        1
  •  6
  •   Community CDub    8 年前

    摘要:使用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。 测温仪 undocumented 帮助程序类,用于tservice写入本地计算机的Windows事件日志,如前所述 在这里 , here 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;
    

    您还可以使用Windows API ReportEvent 功能如前所述 here here .

    我创建了一个简单的类来简化它 available on 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.
    

    报告者 支持将日志项写入本地或远程计算机的事件日志。有关远程示例,请参见 John Kaster's EDN article .


    请注意,您还必须 create a message file register your event source 否则,所有日志消息都将以如下方式开始:

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

    如果事件源自另一台计算机,则显示信息 必须与事件一起保存。

    活动包括以下信息:

    1,有关如何创建消息文件的详细信息,请参阅 Finn Tolderlund's tutorial Michael Hex's article 或者可以使用现有的mc和 RES file included in the GitHub project .

    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事件日志和其他日志记录要求,也可以使用日志记录框架,例如 log4d TraceTool


    here 如果要写入DelphiIDE中的事件日志窗口。

        2
  •  4
  •   Rob Kennedy    16 年前

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

    • 在uses子句中添加“svcmgr”
    • 使用此代码添加文本消息和ID号(日志消息行的最后一个参数)

      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;
      
        3
  •  3
  •   J__    16 年前

    我在Delphi6中使用了标准的VCL,我不能告诉你Delphi5中是否有这个功能。你自己试试看,让我们知道这些东西在D5中是否存在。

    1. 声明teventlogger类型的全局/窗体变量。这在svcmgr单元中声明,因此需要将此单元添加到用户列表中。如果这是正常的应用程序(即不是服务),请确保在表单单元后添加svcmgr。

      MyEventLog:TeventLogger;

    2. 创建记录器的实例。

      myEventLog:=teventLogger.create(“myApplication”);

    3. 要写入事件日志:

      myEventLog.logMessage(“myApplication Started.”),eventlog_information_type);

    4. 别忘了在最后释放它:

      自由的MyEventLog;

    在Windows事件日志中注册应用程序时,您还需要做一些其他事情,这样消息就会在前面显示而不显示此消息:

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

        4
  •  1
  •   robsoft    16 年前

    多亏了 J 彼得的回答是,我马上把我的代码写进了事件日志。还有一些事情要做,特别是如果您希望事件在事件日志中“很好地”显示,而没有关于找不到描述的标准Windows消息(根据 J 的帖子)

    我遵循提示 here 生成一个合适的dll并将其输入注册表,很快就把它全部整理好了。

    根据问题,这都是在德尔菲5,但我没有看到什么让我觉得它在2007年也不会起作用。