Write in Windows-Eventlog with Delphi Event-ID not found

拥有回忆 提交于 2019-12-13 09:51:28

问题


I am writing a Service application for Windows in Delphi. On some events I write messages to the Windows EventLog. That works, but there is the following text in every log entry:

The description for Event ID xxx from source yyyyy cannot be found...

I don't want this.

What I have done:

  1. generate an ResouceEventlog.mc with this content:

    SeverityNames=(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=(German=0x407:MSG00407)
    
    MessageIdTypedef=WORD
    
    MessageID=0x1
    Symbolicname=CAT_ALL
    Language=German
    Allgemein
    .
    
    MessageID=0x2
    Symbolicname=CAT_CALL
    Language=German
    Anruf
    .
    
    MessageID=0x3
    Symbolicname=CAT_LIC
    Language=German
    Lizenzinformation
    .
    
    MessageID=0x4
    Symbolicname=CAT_INFO
    Language=German
    Informationen
    .
    
    MessageID=0x5
    Symbolicname=CAT_ERR
    Language=German
    Fehler
    .
    
    MessageIdTypedef=DWORD
    
    MessageID=0x1000
    Symbolicname=LIC_INFO
    Language=German
    Lizenzinformationen
    .
    
    MessageID=0x1001
    Symbolicname=LIC_EXP
    Language=German
    Lizenzinformationen
    .
    
    MessageID=0x2000
    Symbolicname=CALL_SiG
    Language=German
    Anruf signalisieren
    .
    
    MessageID=0x2001
    Symbolicname=CALL_DBL
    Language=German
    Anruf bereits erfasst
    .
    
    MessageID=0x2002
    Symbolicname=CALL_CAPI
    Language=German
    Anruf an CAPI
    .
    
    MessageID=0x2003
    Symbolicname=CALL_PROCESS
    Language=German
    Anruf verarbeiten
    .
    
    MessageID=0x3000
    Symbolicname=ERR_CAPI
    Language=German
    Capi Fehler
    .
    
    MessageID=0x3001
    Symbolicname=ERR_PATH
    Language=German
    Speicherpfad kann nicht erstellt weren
    .
    
    MessageID=0x3002
    Symbolicname=ERR_NOCAPI
    Language=German
    Keine CAPI gefunden
    .
    
    MessageID=0x3003
    Symbolicname=ERR_UDP
    Language=German
    UDP_Empfangs_Port ist 0
    
    .
    
  2. Compile ResourceEventlog.mc with mc.exe

  3. Compile RecourceEventLog.rc with brcc32.exe to ResourceEventlog.res

  4. Add {$R RecourceEventlog.res} to the main unit of my service application

  5. in the AfterInstall event, I create some Registry entries:

    Windows Registry Editor Version 5.00
    
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\Anrufmonitor]
    "EventMessageFile"="C:\\AM\\AMService.exe"
    "CategoryMessageFile"="C:\\AM\\AMService.exe"
    "CategoryCount"=dword:00000005
    "TypesSupported"=dword:00000007
    
  6. in my Service application I define some constants and use TService.LogEvent() to write messages to the eventlog:

    const
      CAT_ALL      :WORD    =$1;
      CAT_CALL     :WORD    =$2;
      CAT_LIC      :WORD    =$3;
      CAT_INFO     :WORD    =$4;
      CAT_ERR      :WORD    =$5;
      LIC_INFO     :DWORD   =$00001000;
      LIC_EXP      :DWORD   =$00001001;
      CALL_SIG     :DWORD   =$00002000;
      CALL_DBL     :DWORD   =$00002001;
      CALL_CAPI    :DWORD   =$00002002;
      CALL_PROCESS :DWORD   =$00002003;
      ERR_CAPI     :DWORD   =$00003000;
      ERR_PATH     :DWORD   =$00003001;
      ERR_NOCAPI   :DWORD   =$00003002;
      ERR_UDP      :DWORD   =$00003003;
    
    ...
    LogMessage('test an eventlog-entry', EVENTLOG_INFORMATION_TYPE, CAT_CALL, CALL_PROCESS);
    

The eventlog entry is created successfully, but the "Event ID cannot be found" text still appears.


回答1:


None of your messages in the .mc file are specifying a Severity or Facility. The default Severity is Success, which is in your SeverityName list, but the default Facility is Application (0xFFF), which is not in your FacilityNames list.

A message's Severity and Facility numbers are included as part of the final resource ID number that is stored in the compiled message resource. That is the number which must be passed to ReportEvent() (wrapped by TService.LogMessage()) in its dwEventID parameter so it can find the correct resource string. The exact format of that parameter is documented on MSDN:

Event Identifiers

 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+---+-+-+-----------------------+-------------------------------+
|Sev|C|R|     Facility          |               Code            |
+---+-+-+-----------------------+-------------------------------+

Sev

    Severity. The severity is defined as follows:

        00 - Success
        01 - Informational
        10 - Warning
        11 - Error

C

    Customer bit. This bit is defined as follows:

        0 - System code
        1 - Customer code

R

    Reserved bit.

Facility

    Facility code. This value can be FACILITY_NULL.

Code

    Status code for the facility.

This is also covered on MSDN Support:

HOWTO: Troubleshooting the "Event Message Not Found" Message

  1. Make sure the correct ID is passed to the ReportEvent function.

Many think that the literal ID number found in the .mc file is the correct ID. This is not so because the message compiler bitwise ORs the ID number into the LOWORD and bitwise ORs the severity and facility bits into the HIWORD. An application should always use the symbolic name in the header file that is output from the message compiler.

Verify the MessageIdTypedef= statement in the .mc file. Some example .mc files show how to define the MessageIDTypedef to WORD for Category IDs. However, this causes Event IDs to loose the HIWORD. To correct this issue, define MessageIdTypedef= only once and set it to DWORD.

Also be sure that the MC -c command line is consistently used for the message resources and header file. The -c switch turns on a bit in the HIWORD of the message ID.

The -c switch of mc.exe causes it to "set the customer bit (bit 28) in all message IDs."

However, your Delphi constants are not accounting for this format.

For example, your .mc file defines CALL_PROCESS with a MessageID (the Code above) of 0x2003 and no Severity or Facility, so Success=0x0 and Application=0xFFF are used, respectively. Thus, the actual EventID for CALL_PROCESS is 0x2FFF2003 (you can verify this by looking at the compiled message resource with any Resource viewer/editor tool).

But, your Delphi code is defining CALL_PROCESS as $00002003, which is NOT the correct number that you need to pass to LogMessage()!

The same applies to all of your other message EventIDs (LIC_INFO through ERR_UDP).

The MessageID of a message's category identifier is used as-is, so those category constants in your Delphi code (CAT_ALL through CAT_ERR) are fine.

Try this instead:

const
  CAT_ALL      :WORD    =$1;
  CAT_CALL     :WORD    =$2;
  CAT_LIC      :WORD    =$3;
  CAT_INFO     :WORD    =$4;
  CAT_ERR      :WORD    =$5;

  LIC_INFO     :DWORD   =$2FFF1000;
  LIC_EXP      :DWORD   =$2FFF1001;
  CALL_SIG     :DWORD   =$2FFF2000;
  CALL_DBL     :DWORD   =$2FFF2001;
  CALL_CAPI    :DWORD   =$2FFF2002;
  CALL_PROCESS :DWORD   =$2FFF2003;
  ERR_CAPI     :DWORD   =$2FFF3000;
  ERR_PATH     :DWORD   =$2FFF3001;
  ERR_NOCAPI   :DWORD   =$2FFF3002;
  ERR_UDP      :DWORD   =$2FFF3003;

Even if you fix your .mc file to explicitly specify correct Severity and Facility values for each message, make sure you also account for the Customer bit in your Delphi constants.

For example, if you set each message's Facility to 0x0, the correct EventIDs would look like this:

const
  CAT_ALL      :WORD    =$1;
  CAT_CALL     :WORD    =$2;
  CAT_LIC      :WORD    =$3;
  CAT_INFO     :WORD    =$4;
  CAT_ERR      :WORD    =$5;

  LIC_INFO     :DWORD   =$20001000;
  LIC_EXP      :DWORD   =$20001001;
  CALL_SIG     :DWORD   =$20002000;
  CALL_DBL     :DWORD   =$20002001;
  CALL_CAPI    :DWORD   =$20002002;
  CALL_PROCESS :DWORD   =$20002003;
  ERR_CAPI     :DWORD   =$20003000;
  ERR_PATH     :DWORD   =$20003001;
  ERR_NOCAPI   :DWORD   =$20003002;
  ERR_UDP      :DWORD   =$20003003;

And then, if you set the Severity to Error on the error messages, the correct EventIDs would look like this:

const
  CAT_ALL      :WORD    =$1;
  CAT_CALL     :WORD    =$2;
  CAT_LIC      :WORD    =$3;
  CAT_INFO     :WORD    =$4;
  CAT_ERR      :WORD    =$5;

  LIC_INFO     :DWORD   =$20001000;
  LIC_EXP      :DWORD   =$20001001;
  CALL_SIG     :DWORD   =$20002000;
  CALL_DBL     :DWORD   =$20002001;
  CALL_CAPI    :DWORD   =$20002002;
  CALL_PROCESS :DWORD   =$20002003;
  ERR_CAPI     :DWORD   =$E0003000;
  ERR_PATH     :DWORD   =$E0003001;
  ERR_NOCAPI   :DWORD   =$E0003002;
  ERR_UDP      :DWORD   =$E0003003;

So, defining the EventID constants correctly makes a BIG difference in whether ReportEvent() can find them in the message resource.



来源:https://stackoverflow.com/questions/47181193/write-in-windows-eventlog-with-delphi-event-id-not-found

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!