Delphi Windows ETW中,内核使用者为何长期不接收EventCallback或BufferCallback事件回调?

2026-04-10 18:133阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计571个文字,预计阅读时间需要3分钟。

Delphi Windows ETW中,内核使用者为何长期不接收EventCallback或BufferCallback事件回调?

我正在尝试收集ETW内核事件。步骤1:调用OpenTrace,指定在调用ProcessTrace期间将调用的EventCallback和可选的BufferCallback函数:var logFile: EVENT_TRACE_LOGFILE; currentTrace: TRACEHANDLE; begin ZeroMemory();

我正在尝试收听ETW内核事件.

>步骤1:调用OpenTrace,指定在调用ProcessTrace期间将调用的EventCallback和可选BufferCallback函数:

var logFile: EVENT_TRACE_LOGFILE; currentTrace: TRACEHANDLE; begin ZeroMemory(@logFile, sizeof(logFile)); logFile.LoggerName := KERNEL_LOGGER_NAME; logFile.LogFileName := 'C:\Users\Ian\foo.etl'; logFile.ProcessTraceMode := 0; logFile.EventCallback := RealtimeEventCallback; logFile.BufferCallback := BufferCallback; //optional currentTrace := OpenTrace(@logFile); if (currentTrace = INVALID_PROCESSTRACE_HANDLE) or (currentTrace = -1) then RaiseLastWin32Error();

>步骤2:Enable kernel events.这是通过调用StartTrace完成的.在我的情况下,我想跟踪内核interrupts(EVENT_TRACE_FLAG_INTERRUPT)和deferred procedure calls(EVENT_TRACE_FLAG_DPC):

var sessionProperties: PEVENT_TRACE_PROPERTIES; bufferSize: Int64; th: TRACEHANDLE; loggerName: string; logFilePath: string; begin loggerName := KERNEL_LOGGER_NAME; logFilePath := 'C:\Users\Ian\foo.etl'; bufferSize := sizeof(EVENT_TRACE_PROPERTIES) + 1024 //maximum session name is 1024 characters + 1024; //maximum log file name is 1024 characters sessionProperties := AllocMem(bufferSize); ZeroMemory(sessionProperties, bufferSize); sessionProperties.Wnode.BufferSize := bufferSize; sessionProperties.Wnode.ClientContext := 1; //QPC clock resolution sessionProperties.Wnode.Flags := WNODE_FLAG_TRACED_GUID; sessionProperties.Wnode.Guid := SystemTraceControlGuid; sessionProperties.EnableFlags := EVENT_TRACE_FLAG_INTERRUPT or EVENT_TRACE_FLAG_DPC; sessionProperties.LogFileMode := EVENT_TRACE_FILE_MODE_CIRCULAR; sessionProperties.MaximumFileSize := 5; // 5 MB sessionProperties.LoggerNameOffset := sizeof(EVENT_TRACE_PROPERTIES); sessionProperties.LogFileNameOffset := sizeof(EVENT_TRACE_PROPERTIES)+1024; //Copy LoggerName to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+sessionProperties.LoggerNameOffset), PChar(loggerName), Length(loggerName)+1); //Copy LogFilePath to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+sessionProperties.LogFileNameOffset), PChar(logFilePath), Length(logFilePath)+1); hr := StartTrace({var}th, PChar(loggerName), sessionProperties); if (hr <> ERROR_SUCCESS) then raise EWin32Error.Create(SysErrorMessage(hr));

并且日志成功启动(我可以看到foo.etl开始增长到它的5 MB circuluar限制).
>步骤3:调用ProcessTrace,阻止它将所有挂起事件传递给步骤1中指定的EventCallback处理程序:

var res: LongWord; begin res := EventTrace.ProcessTrace(@currentTrace, 1, nil, nil); if (res <> ERROR_SUCCESS) then raise EWin32Error.Create(SysErrorMessage(res));

除了ProcessTrace立即重复返回,并且没有调用回调 – 即使etl文件存在并且正在增长.

如果我将记录从基于文件更改为实时日志记录:

>第1步 – OpenTrace更改以支持实时:

logFile.ProcessTraceMode := PROCESS_TRACE_MODE_REAL_TIME;

>第2步 – StartTrace更改以支持实时:

sessionProperties.LogFileMode := EVENT_TRACE_REAL_TIME_MODE;

在这种情况下,ProcessTrace永远不会返回,但是从未调用过EventCallback或BufferCallback.

我究竟做错了什么?

更新:我的回调函数:

function BufferCallback(Logfile: PEVENT_TRACE_LOGFILE): LongWord; stdcall; begin ShowMessage('BufferCallback'); Result := 1; //return true to keep processing rows end; procedure RealtimeEventCallback(pEvent: PEVENT_TRACE); stdcall; begin ShowMessage('EventCallback'); nEvents := nEvents+1; end; 我发现了这个问题.

我使用的标题不是四字对齐的.

在Delphi的说法中,正在使用关键字packed.

Delphi Windows ETW中,内核使用者为何长期不接收EventCallback或BufferCallback事件回调?

本文共计571个文字,预计阅读时间需要3分钟。

Delphi Windows ETW中,内核使用者为何长期不接收EventCallback或BufferCallback事件回调?

我正在尝试收集ETW内核事件。步骤1:调用OpenTrace,指定在调用ProcessTrace期间将调用的EventCallback和可选的BufferCallback函数:var logFile: EVENT_TRACE_LOGFILE; currentTrace: TRACEHANDLE; begin ZeroMemory();

我正在尝试收听ETW内核事件.

>步骤1:调用OpenTrace,指定在调用ProcessTrace期间将调用的EventCallback和可选BufferCallback函数:

var logFile: EVENT_TRACE_LOGFILE; currentTrace: TRACEHANDLE; begin ZeroMemory(@logFile, sizeof(logFile)); logFile.LoggerName := KERNEL_LOGGER_NAME; logFile.LogFileName := 'C:\Users\Ian\foo.etl'; logFile.ProcessTraceMode := 0; logFile.EventCallback := RealtimeEventCallback; logFile.BufferCallback := BufferCallback; //optional currentTrace := OpenTrace(@logFile); if (currentTrace = INVALID_PROCESSTRACE_HANDLE) or (currentTrace = -1) then RaiseLastWin32Error();

>步骤2:Enable kernel events.这是通过调用StartTrace完成的.在我的情况下,我想跟踪内核interrupts(EVENT_TRACE_FLAG_INTERRUPT)和deferred procedure calls(EVENT_TRACE_FLAG_DPC):

var sessionProperties: PEVENT_TRACE_PROPERTIES; bufferSize: Int64; th: TRACEHANDLE; loggerName: string; logFilePath: string; begin loggerName := KERNEL_LOGGER_NAME; logFilePath := 'C:\Users\Ian\foo.etl'; bufferSize := sizeof(EVENT_TRACE_PROPERTIES) + 1024 //maximum session name is 1024 characters + 1024; //maximum log file name is 1024 characters sessionProperties := AllocMem(bufferSize); ZeroMemory(sessionProperties, bufferSize); sessionProperties.Wnode.BufferSize := bufferSize; sessionProperties.Wnode.ClientContext := 1; //QPC clock resolution sessionProperties.Wnode.Flags := WNODE_FLAG_TRACED_GUID; sessionProperties.Wnode.Guid := SystemTraceControlGuid; sessionProperties.EnableFlags := EVENT_TRACE_FLAG_INTERRUPT or EVENT_TRACE_FLAG_DPC; sessionProperties.LogFileMode := EVENT_TRACE_FILE_MODE_CIRCULAR; sessionProperties.MaximumFileSize := 5; // 5 MB sessionProperties.LoggerNameOffset := sizeof(EVENT_TRACE_PROPERTIES); sessionProperties.LogFileNameOffset := sizeof(EVENT_TRACE_PROPERTIES)+1024; //Copy LoggerName to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+sessionProperties.LoggerNameOffset), PChar(loggerName), Length(loggerName)+1); //Copy LogFilePath to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+sessionProperties.LogFileNameOffset), PChar(logFilePath), Length(logFilePath)+1); hr := StartTrace({var}th, PChar(loggerName), sessionProperties); if (hr <> ERROR_SUCCESS) then raise EWin32Error.Create(SysErrorMessage(hr));

并且日志成功启动(我可以看到foo.etl开始增长到它的5 MB circuluar限制).
>步骤3:调用ProcessTrace,阻止它将所有挂起事件传递给步骤1中指定的EventCallback处理程序:

var res: LongWord; begin res := EventTrace.ProcessTrace(@currentTrace, 1, nil, nil); if (res <> ERROR_SUCCESS) then raise EWin32Error.Create(SysErrorMessage(res));

除了ProcessTrace立即重复返回,并且没有调用回调 – 即使etl文件存在并且正在增长.

如果我将记录从基于文件更改为实时日志记录:

>第1步 – OpenTrace更改以支持实时:

logFile.ProcessTraceMode := PROCESS_TRACE_MODE_REAL_TIME;

>第2步 – StartTrace更改以支持实时:

sessionProperties.LogFileMode := EVENT_TRACE_REAL_TIME_MODE;

在这种情况下,ProcessTrace永远不会返回,但是从未调用过EventCallback或BufferCallback.

我究竟做错了什么?

更新:我的回调函数:

function BufferCallback(Logfile: PEVENT_TRACE_LOGFILE): LongWord; stdcall; begin ShowMessage('BufferCallback'); Result := 1; //return true to keep processing rows end; procedure RealtimeEventCallback(pEvent: PEVENT_TRACE); stdcall; begin ShowMessage('EventCallback'); nEvents := nEvents+1; end; 我发现了这个问题.

我使用的标题不是四字对齐的.

在Delphi的说法中,正在使用关键字packed.

Delphi Windows ETW中,内核使用者为何长期不接收EventCallback或BufferCallback事件回调?