我的Delphi應用程序如何輕鬆寫入Windows事件日誌?使用Delphi寫入Windows事件日誌
TEventLogger和ReportEvent有什麼區別? 如何使用ReportEvent功能?
我的Delphi應用程序如何輕鬆寫入Windows事件日誌?使用Delphi寫入Windows事件日誌
TEventLogger和ReportEvent有什麼區別? 如何使用ReportEvent功能?
如果你正在寫一個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。 TEventLoggerundocumented TService的助手類,用於寫入本地計算機的Windows事件日誌,如here,0 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.
ReportEvent支持編寫日誌條目以本地或遠程計算機的事件日誌。有關遠程示例,請參閱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如果你想寫入事件日誌Delphi IDE中的窗口。
幹得好!只是你的日誌類。我希望他們的方法是實例方法而不是類方法,以避免重複註冊和註銷事件源。我會在創建類的實例時註冊事件源,並在銷燬時取消註冊。或者創建一個全局threadvar並初始化一次。 – TLama
如果您在實例銷燬時取消註冊,是否不會導致無法再讀取現有的事件日誌條目?換句話說,實例必須處於活動狀態才能讓操作員查看舊的事件日誌條目?我寧願認爲註冊事件源應該是安裝的一部分,並取消註冊到可執行文件的卸載。 –
嗨,TOndrey,我懷疑TLama意味着「RegisterEventSource」API調用,而不是「通過將註冊事件源添加到註冊表」:-) –
搜索堆棧溢出這個看似簡單的問題返回的答案在許多問題之間傳播。我創建了一個新的簡單問題,並花費時間將答案合併在一起,並添加了其他答案中沒有的額外信息。我這樣做是因爲這不是我第一次來這裏尋找這個答案,並認爲詳細的答案和示例項目可能也會幫助其他人。 –
你可以在其他問題上做到這一點。這裏也很好。這些問題現在聯繫在一起。都很好。 http://blog.stackoverflow.com/2010/11/dr-strangedupe-or-how-i-learned-to-stop-worrying-and-love-duplication/ –
好的,謝謝大衛,我現在明白了更好有用。 –