我正在调用Windows StartTrace
函数的事件跟踪:
StartTrace(sessionHandle, KERNEL_LOGGER_NAME, sessionProperties);
失败,错误代码为87(ERROR_INVALID_PARAMETER
)。 MSDN给出了此错误的一些常见原因:
我正在调用的代码是:
procedure StartKernelLogging;
var
sessionProperties: PEVENT_TRACE_PROPERTIES;
bufferSize: Int64;
loggerName: AnsiString;
logFilePath: AnsiString;
th: TRACEHANDLE;
hr: Cardinal;
begin
{
Allocate memory for the session properties. The memory must
be large enough to include the log file name and session name,
which get appended to the end of the session properties structure.
}
loggerName := KERNEL_LOGGER_NAME;
logFilePath := 'C:\Users\Ian\foo.etl';
bufferSize := sizeof(EVENT_TRACE_PROPERTIES)
+ Length(loggerName)+1
+ Length(logFilePath)+1;
sessionProperties := AllocMem(bufferSize);
ZeroMemory(sessionProperties, bufferSize);
sessionProperties.Wnode.BufferSize := bufferSize;
sessionProperties.Wnode.Flags := WNODE_FLAG_TRACED_GUID;
sessionProperties.Wnode.ClientContext := 1; //QPC clock resolution
sessionProperties.Wnode.Guid := SystemTraceControlGuid;
sessionProperties.EnableFlags := EVENT_TRACE_FLAG_NETWORK_TCPIP;
sessionProperties.LogFileMode := EVENT_TRACE_FILE_MODE_CIRCULAR;
sessionProperties.MaximumFileSize := 5; // 5 MB
sessionProperties.LoggerNameOffset := sizeof(EVENT_TRACE_PROPERTIES);
sessionProperties.LogFileNameOffset := sizeof(EVENT_TRACE_PROPERTIES) + Length(loggerName)+1;
//Copy LoggerName to the offset address
MoveMemory(Pointer(Cardinal(sessionProperties)+Cardinal(sessionProperties.LoggerNameOffset)), PAnsiChar(loggerName), Length(loggerName)+1);
//Copy LogFilePath to the offset address
MoveMemory(Pointer(Cardinal(sessionProperties)+Cardinal(sessionProperties.LogFileNameOffset)), PAnsiChar(logFilePath), Length(logFilePath)+1);
th := 0;
hr := EventTrace.StartTrace({var}th, PChar(loggerName), sessionProperties);
if (hr <> ERROR_SUCCESS) then
begin
raise EWin32Error.Create(SysErrorMessage(hr));
end;
end;
我的电话语言无关的版本:
ADVAPI32.StartTraceA(
TraceHandle: 0x18F56C
InstanceName: 0x44E840
Properties: 0x243BD8);
其中TraceHandle
指向64位整数:
0018F56C: 00 00 00 00 00 00 00 00
和InstanceName
是指向以null结尾的ansi字符串的指针:
0044E840: 4E 54 20 4B 65 72 6E 65 NT Kerne
0044E848: 6C 20 4C 6F 67 67 65 72 l Logger
0044E850: 00
和Properties
是指向EVENT_TRACE_PROPERTIES
结构的指针,我将避免重现完整的十六进制转储
002A3BD8: 0000009A (154 bytes)
重要的值是两个偏移量:
properties.LoggerNameOffset = 116 (i.e. $243BB8 + 116 = $243C4C)
properties.LogFileNameOffset = 133 (i.e. $243BD8 + 133 = $243C5D)
还包含有效的以null结尾的ansi字符串:
“NT内核记录器”:
$243C4C 4B20544E 656E7265 NT Kerne
$243C54 6F4C206C 72656767 l Logger
$243C5C xxxxxx00 .
“C:\用户\伊恩\ foo.etl”:
$243C5C 5C3A43xx 72657355 .C:\User
$243C64 61495C73 6F665C6E s\Ian\fo
$243C6C 74652E6F xxxx006C o.etc.
为什么我的参数不正确?
更新
会话参数:
9A 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
AD 4A 81 9E 04 32 D2 11
9A 82 00 60 08 A8 69 39
01 00 00 00 00 00 02 00
00 00 00 00 00 00 00 00
00 00 00 00 05 00 00 00
02 00 00 00 00 00 00 00
00 00 01 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 85 00 00 00
74 00 00 00
分解为:
000| Wnode.BufferSize: 9A 00 00 00 (154)
004| Wnode.ProviderID: 00 00 00 00
008| Wnode.Version: 00 00 00 00
012| Wnode.Linkage: 00 00 00 00
016| Wnode.Timestamp: 00 00 00 00 00 00 00 00
024| Wnode.Guid: AD 4A 81 9E 04 32 D2 11 9A 82 00 60 08 A8 69 39 (SystemTraceControlGuid)
040| Wnode.ClientContext: 01 00 00 00 (1)
044| Wnode.Flags: 00 00 02 00 (WNODE_FLAG_TRACED_GUID)
048| BufferSize: 00 00 00 00
052| MinimumBuffers: 00 00 00 00
056| MaximumBuffers: 00 00 00 00
060| MaximumFileSize: 05 00 00 00 (5 MB)
064| LogFileMode: 02 00 00 00 (EVENT_TRACE_FILE_MODE_CIRCULAR)
068| FlushTimer: 00 00 00 00
072| EnableFlags: 00 00 01 00 (EVENT_TRACE_FLAG_NETWORK_TCPIP)
076| AgeLimit: 00 00 00 00
080| NumberOfBuffers: 00 00 00 00
084| FreeBuffers: 00 00 00 00
088| EventsLost: 00 00 00 00
092| BuffersWritten: 00 00 00 00
096| LogBuffersLost: 00 00 00 00
100| RealTimeBuffersLost: 00 00 00 00
104| LoggerThreadId: 00 00 00 00
108| LogFileNameOffset: 85 00 00 00 (133)
112| LoggerNameOffset: 74 00 00 00 (116)
116| NT Kernel Logger\0
133| C:\Users\Ian\foo.etl\0
154|
如果存在对齐问题,我将无法单独发现它。
结构:
EVENT_TRACE_PROPERTIES = packed record
Wnode : WNODE_HEADER;
// data provided by caller
BufferSize : Longword; // buffer size for logging (kbytes)
MinimumBuffers : Longword; // minimum to preallocate
MaximumBuffers : Longword; // maximum buffers allowed
MaximumFileSize : Longword; // maximum logfile size (in MBytes)
LogFileMode : Longword; // sequential, circular
FlushTimer : Longword; // buffer flush timer, in seconds
EnableFlags :Longword; // trace enable flags
AgeLimit : Longint; // age decay time, in minutes
// data returned to caller
NumberOfBuffers : Longword; // no of buffers in use
FreeBuffers : Longword; // no of buffers free
EventsLost : Longword; // event records lost
BuffersWritten : Longword; // no of buffers written to file
LogBuffersLost : Longword; // no of logfile write failures
RealTimeBuffersLost : Longword; // no of rt delivery failures
LoggerThreadId : HANDLE; // thread id of Logger
LogFileNameOffset : Longword; // Offset to LogFileName
LoggerNameOffset : Longword; // Offset to LoggerName
end;
以及:
WNODE_HEADER = packed record
BufferSize : Longword;
ProviderId : Longword;
Version : Longword;
Linkage : Longword;
TimeStamp : Int64;
Guid : TGUID;
ClientContext : Longword;
Flags : Longword;
end;
答案 0 :(得分:2)
哦,我看到卢克评论的评论是什么。
这不是结构错位的方式。 >>结构后的内容必须8-byte
对齐。换句话说:
000| Wnode.BufferSize: 9A 00 00 00 (154)
004| Wnode.ProviderID: 00 00 00 00
...snip...
108| LogFileNameOffset: 85 00 00 00 (133)
112| LoggerNameOffset: 74 00 00 00 (116)
116| 00 00 00 00 (4 bytes padding)
120| NT Kernel Logger\0
136| 00 00 00 00 00 00 00 (7 bytes padding)
144| C:\Users\Ian\foo.etl\0
看起来数据需要在Windows 8-byte
边界上对齐(7(专业版(64位)))
为了帮助填充,我编写了一个Pad
函数,该函数将数字四舍五入到最接近的8的倍数:
function Pad(length: Cardinal): Cardinal;
var
m: Integer;
const
DataAlignment = 8; //align data on 8-byte boundaries
begin
Result := length;
m := length mod DataAlignment;
if (m > 0) then
Result := result + DataAlignment-m;
end;
然后我改变了原始问题中的一些代码来使用它。
计算所需的总buffserSize
:
loggerName := KERNEL_LOGGER_NAME;
logFilePath := 'C:\Users\Ian\foo.etl';
bufferSize := sizeof(EVENT_TRACE_PROPERTIES)
+ Pad(Length(loggerName)+1)
+ Pad(Length(logFilePath)+1);
然后我需要在8字节边界上推动偏移:
sessionProperties.LoggerNameOffset := Pad(sizeof(EVENT_TRACE_PROPERTIES));
sessionProperties.LogFileNameOffset := Pad(sizeof(EVENT_TRACE_PROPERTIES)) + Pad(Length(loggerName)+1);
只要我将字符串复制到结构中声明的偏移量就可以了:
//Copy LoggerName to the offset address
MoveMemory(
Pointer(Cardinal(sessionProperties)+sessionProperties.LoggerNameOffset),
PAnsiChar(loggerName), Length(loggerName)+1);
//Copy LogFilePath to the offset address
MoveMemory(
Pointer(Cardinal(sessionProperties)+sessionProperties.LogFileNameOffset),
PAnsiChar(logFilePath), Length(logFilePath)+1);
和blingo-blango一起工作。
注意:任何代码都会发布到公共域中。无需归属。
答案 1 :(得分:1)
不是答案,但我找到了一些有趣的事情:如果你更换了这行:
hr := EventTrace.StartTrace({var}th, PChar(loggerName), sessionProperties);
带
hr := EventTrace.StartTrace({var}th, KERNEL_LOGGER_NAME, sessionProperties);
然后错误代码变为ERROR_BAD_LENGTH(24)。我想我正在为跟踪API使用一组不同的单元,在我的例子中,StartTrace需要一个PWideChar,但是loggerName是一个AnsiString。由于我不知道你的EventTrace单元是什么样的,所以很难说你是否也是这样。无论如何,它都不会使StartTrace()调用成功。