Windows Event Trace 编程(TDH.lib)

来源:互联网 发布:离散傅里叶矩阵 编辑:程序博客网 时间:2024/05/01 11:53

简单做个摘录,持续更新。
一. 配置和启动Event tracing Session
要配置一个事件跟踪会话,使用EVENT_TRACE_PROPERTIES结构来指定会话的属性。

//待注释typedef struct _EVENT_TRACE_PROPERTIES {  WNODE_HEADER Wnode;  ULONG        BufferSize;  ULONG        MinimumBuffers;  ULONG        MaximumBuffers;  ULONG        MaximumFileSize;  ULONG        LogFileMode;  ULONG        FlushTimer;  ULONG        EnableFlags;  LONG         AgeLimit;  ULONG        NumberOfBuffers;  ULONG        FreeBuffers;  ULONG        EventsLost;  ULONG        BuffersWritten;  ULONG        LogBuffersLost;  ULONG        RealTimeBuffersLost;  HANDLE       LoggerThreadId;  ULONG        LogFileNameOffset;  ULONG        LoggerNameOffset;} EVENT_TRACE_PROPERTIES, *PEVENT_TRACE_PROPERTIES;

所以所分配的内存必须足够大,包含会话日志的名称(etl文件名称),会话日志的路径,和结构体大小。

BufferSize = sizeof(EVENT_TRACE_PROPERTIES)+sizeof(LOGFILE_PATH)+sizeof(LOGSESSION_NAME);

设置完结构体内容后,调用StartTrace函数启动会话。函数成功,则通过参数返回SessionHandle,并将会话名称的偏移给LoggerNameOffset成员(有一些疑问待解决)。

//待注释ULONG StartTrace(  _Out_   PTRACEHANDLE            SessionHandle,  _In_    LPCTSTR                 SessionName,  _Inout_ PEVENT_TRACE_PROPERTIES Properties);

使用EnableTrace/EX/EX2函数,打开你想要记录事件到Session的providers(事件提供者)。启用或禁用指定的经典事件跟踪提供程序。
在Windows Vista和更高版本,调用EnableTraceEx功能启用或禁用提供商。

//待注释ULONG EnableTrace(  _In_ ULONG       Enable,  _In_ ULONG       EnableFlag,  _In_ ULONG       EnableLevel,  _In_ LPCGUID     ControlGuid,  _In_ TRACEHANDLE SessionHandle);

使用EnableTraceEx函数,启用或禁用指定的事件跟踪提供程序。

//待注释ULONG EnableTraceEx(  _In_     LPCGUID                  ProviderId,  _In_opt_ LPCGUID                  SourceId,  _In_     TRACEHANDLE              TraceHandle,  _In_     ULONG                    IsEnabled,  _In_     UCHAR                    Level,  _In_     ULONGLONG                MatchAnyKeyword,  _In_     ULONGLONG                MatchAllKeyword,  _In_     ULONG                    EnableProperty,  _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc);

EnableTraceEx2功能取代了此函数。

//待注释ULONG EnableTraceEx2(  _In_     TRACEHANDLE              TraceHandle,  _In_     LPCGUID                  ProviderId,  _In_     ULONG                    ControlCode,  _In_     UCHAR                    Level,  _In_     ULONGLONG                MatchAnyKeyword,  _In_     ULONGLONG                MatchAllKeyword,  _In_     ULONG                    Timeout,  _In_opt_ PENABLE_TRACE_PARAMETERS EnableParameters);

对于manifest-based provider可以有最多8个Session进行启用和接收,但是对于classic provider只允许同时存在一个Session进行启用和记录数据,即: SessionA enabled Provider1,then SessionB enabled provider1,only SessionB would recv events from provider1.
____________________________________
在Winodows 8.1之后
可以使用EnableTraceEx2函数和ENABLE_TRACE_PARAMETERS和EVENT_FILTER_DESCRIPTOR结构体在会话中对payload,scope,stack walk进行过滤。

ENABLE_TRACE_PARAMETERS结构定义信息用于启用提供者。

typedef struct _ENABLE_TRACE_PARAMETERS {  ULONG                    Version;  ULONG                    EnableProperty;  ULONG                    ControlFlags;  GUID                     SourceId;  PEVENT_FILTER_DESCRIPTOR EnableFilterDesc;  ULONG                    FilterDescCount;} ENABLE_TRACE_PARAMETERS, *PENABLE_TRACE_PARAMETERS;

该EVENT_FILTER_DESCRIPTOR结构 定义一个过滤数据传递给会话的事件提供者的回调函数。

typedef struct _EVENT_FILTER_DESCRIPTOR {  ULONGLONG Ptr;  ULONG     Size;  ULONG     Type;} EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR;

等等,一些函数 TdhCreatePayloadFilter, and TdhAggregatePayloadFilters functions(不理解)。
____________________________________

可以再事件供应者注册之前或之后启用事件供应者,ETW都会调用提供的回调函数,如果没有注册会自己注册(?)
可以使用EnableTrace或者EnableTraceEx2来关闭或者更新provider相关数据(开关标志)。每次调用这两个函数都会使得会话,ETW都会调用回调函数。provider保持开启状态,直到由会话将其关闭。
在停止跟踪会话的时候,使用ControlTrace函数,使用EVENT_TRACE_CONTROL_STOP。使用StartTrace函数获得的SessionHanle或者先前启动会话的名称。(要先关闭provider在关闭Session)

//待注释ULONG ControlTrace(  _In_    TRACEHANDLE             SessionHandle,  _In_    LPCTSTR                 SessionName,  _Inout_ PEVENT_TRACE_PROPERTIES Properties,  _In_    ULONG                   ControlCode);/*eg:    status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);*/

下面的几个例子进行参考分析和研究代码逻辑。

//待注释 //Example that Creates a Session and Enables a Manifest-based or Classic Provider//The following example shows how to start a trace session, enables a manifest-based or classic provider, disables the provider and then stops the session.#include <windows.h>#include <stdio.h>#include <conio.h>#include <strsafe.h>#include <wmistr.h>#include <evntrace.h>#define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"#define LOGSESSION_NAME L"My Event Trace Session"// GUID that identifies your trace session.// Remember to create your own session GUID.// {AE44CB98-BD11-4069-8093-770EC9258A12}static const GUID SessionGuid = { 0xae44cb98, 0xbd11, 0x4069, { 0x80, 0x93, 0x77, 0xe, 0xc9, 0x25, 0x8a, 0x12 } };// GUID that identifies the provider that you want// to enable to your session.// {D8909C24-5BE9-4502-98CA-AB7BDC24899D}static const GUID ProviderGuid = { 0xd8909c24, 0x5be9, 0x4502, {0x98, 0xca, 0xab, 0x7b, 0xdc, 0x24, 0x89, 0x9d } };void wmain(void){    ULONG status = ERROR_SUCCESS;    TRACEHANDLE SessionHandle = 0;    EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;    ULONG BufferSize = 0;    BOOL TraceOn = TRUE;    // 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.    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);    pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);        if (NULL == pSessionProperties)    {        wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);        goto cleanup;    }    // Set the session properties. You only append the log file name    // to the properties structure; the StartTrace function appends    // the session name for you.    ZeroMemory(pSessionProperties, BufferSize);    pSessionProperties->Wnode.BufferSize = BufferSize;    pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;    pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution    pSessionProperties->Wnode.Guid = SessionGuid;     pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;    pSessionProperties->MaximumFileSize = 1;  // 1 MB    pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);    pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME);     StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);    // Create the trace session.    status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties);    if (ERROR_SUCCESS != status)    {        wprintf(L"StartTrace() failed with %lu\n", status);        goto cleanup;    }    // Enable the providers that you want to log events to your session.    status = EnableTraceEx2(        SessionHandle,        (LPCGUID)&ProviderGuid,        EVENT_CONTROL_CODE_ENABLE_PROVIDER,        TRACE_LEVEL_INFORMATION,        0,        0,        0,        NULL        );    if (ERROR_SUCCESS != status)    {        wprintf(L"EnableTrace() failed with %lu\n", status);        TraceOn = FALSE;        goto cleanup;    }    wprintf(L"Run the provider application. Then hit any key to stop the session.\n");    _getch();cleanup:    if (SessionHandle)    {        if (TraceOn)        {            status = EnableTraceEx2(                SessionHandle,                (LPCGUID)&ProviderGuid,                EVENT_CONTROL_CODE_DISABLE_PROVIDER,                TRACE_LEVEL_INFORMATION,                0,                0,                0,                NULL                );        }        status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);        if (ERROR_SUCCESS != status)        {            wprintf(L"ControlTrace(stop) failed with %lu\n", status);        }    }    if (pSessionProperties)    {        free(pSessionProperties);        pSessionProperties = NULL;    }}

下面的例子演示了如何配置和启动NT内核记录会议,收集网络中的TCP/ IP内核事件,并将其写入到一个5MB的循环文件。

//Configuring and Starting the NT Kernel Logger Session//There is only one NT Kernel Logger session. If the session is already in use, the StartTrace function returns ERROR_ALREADY_EXISTS.#define INITGUID  // Include this #define to use SystemTraceControlGuid in Evntrace.h.#include <windows.h>#include <stdio.h>#include <conio.h>#include <strsafe.h>#include <wmistr.h>#include <evntrace.h>#define LOGFILE_PATH L"<FULLPATHTOTHELOGFILE.etl>"void wmain(void){    ULONG status = ERROR_SUCCESS;    TRACEHANDLE SessionHandle = 0;    EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;    ULONG BufferSize = 0;    // 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.    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(KERNEL_LOGGER_NAME);    pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);        if (NULL == pSessionProperties)    {        wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);        goto cleanup;    }    // Set the session properties. You only append the log file name    // to the properties structure; the StartTrace function appends    // the session name for you.    ZeroMemory(pSessionProperties, BufferSize);    pSessionProperties->Wnode.BufferSize = BufferSize;    pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;    pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution    pSessionProperties->Wnode.Guid = SystemTraceControlGuid;     pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_NETWORK_TCPIP;    pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;    pSessionProperties->MaximumFileSize = 5;  // 5 MB    pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);    pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME);     StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);    // Create the trace session.    status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);    if (ERROR_SUCCESS != status)    {        if (ERROR_ALREADY_EXISTS == status)        {            wprintf(L"The NT Kernel Logger session is already in use.\n");        }        else        {            wprintf(L"EnableTrace() failed with %lu\n", status);        }        goto cleanup;    }    wprintf(L"Press any key to end trace session ");    _getch();cleanup:    if (SessionHandle)    {        status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);        if (ERROR_SUCCESS != status)        {            wprintf(L"ControlTrace(stop) failed with %lu\n", status);        }    }    if (pSessionProperties)        free(pSessionProperties);}

用于分析etl文件的代码,参考和研究。

//Turns the DEFINE_GUID for EventTraceGuid into a const.#define INITGUID#include <windows.h>#include <stdio.h>#include <wbemidl.h>#include <wmistr.h>#include <evntrace.h>#include <tdh.h>#include <in6addr.h>#pragma comment(lib, "tdh.lib")#define LOGFILE_PATH L"C:\\Code\\etw\\V2EventTraceController\\mylogfile.etl"// Used to calculate CPU usageULONG g_TimerResolution = 0;// Used to determine if the session is a private session or kernel session.// You need to know this when accessing some members of the EVENT_TRACE.Header// member (for example, KernelTime or UserTime).BOOL g_bUserMode = FALSE;// Handle to the trace file that you opened.TRACEHANDLE g_hTrace = 0;  // Prototypesvoid WINAPI ProcessEvent(PEVENT_RECORD pEvent);DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);PBYTE PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData);DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength);DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize);DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo);void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo);void wmain(void){    TDHSTATUS status = ERROR_SUCCESS;    EVENT_TRACE_LOGFILE trace;    TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;    // Identify the log file from which you want to consume events    // and the callbacks used to process the events and buffers.    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));    trace.LogFileName = (LPWSTR) LOGFILE_PATH;    trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);    trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;    g_hTrace = OpenTrace(&trace);    if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)    {        wprintf(L"OpenTrace failed with %lu\n", GetLastError());        goto cleanup;    }    g_bUserMode = pHeader->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE;    if (pHeader->TimerResolution > 0)    {        g_TimerResolution = pHeader->TimerResolution / 10000;    }    wprintf(L"Number of events lost:  %lu\n", pHeader->EventsLost);    // Use pHeader to access all fields prior to LoggerName.    // Adjust pHeader based on the pointer size to access    // all fields after LogFileName. This is required only if    // you are consuming events on an architecture that is     // different from architecture used to write the events.    if (pHeader->PointerSize != sizeof(PVOID))    {        pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader +            2 * (pHeader->PointerSize - sizeof(PVOID)));    }    wprintf(L"Number of buffers lost: %lu\n\n", pHeader->BuffersLost);    status = ProcessTrace(&g_hTrace, 1, 0, 0);    if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)    {        wprintf(L"ProcessTrace failed with %lu\n", status);        goto cleanup;    }cleanup:    if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)    {        status = CloseTrace(g_hTrace);    }}// Callback that receives the events. VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent){    DWORD status = ERROR_SUCCESS;    PTRACE_EVENT_INFO pInfo = NULL;    LPWSTR pwsEventGuid = NULL;    PBYTE pUserData = NULL;    PBYTE pEndOfUserData = NULL;    DWORD PointerSize = 0;    ULONGLONG TimeStamp = 0;    ULONGLONG Nanoseconds = 0;    SYSTEMTIME st;    SYSTEMTIME stLocal;    FILETIME ft;    // Skips the event if it is the event trace header. Log files contain this event    // but real-time sessions do not. The event contains the same information as     // the EVENT_TRACE_LOGFILE.LogfileHeader member that you can access when you open     // the trace.     if (IsEqualGUID(pEvent->EventHeader.ProviderId, EventTraceGuid) &&        pEvent->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO)    {        ; // Skip this event.    }    else    {        // Process the event. The pEvent->UserData member is a pointer to         // the event specific data, if it exists.        status = GetEventInformation(pEvent, pInfo);        if (ERROR_SUCCESS != status)        {            wprintf(L"GetEventInformation failed with %lu\n", status);            goto cleanup;        }        // Determine whether the event is defined by a MOF class, in an        // instrumentation manifest, or a WPP template; to use TDH to decode        // the event, it must be defined by one of these three sources.        if (DecodingSourceWbem == pInfo->DecodingSource)  // MOF class        {            HRESULT hr = StringFromCLSID(pInfo->EventGuid, &pwsEventGuid);            if (FAILED(hr))            {                wprintf(L"StringFromCLSID failed with 0x%x\n", hr);                status = hr;                goto cleanup;            }            wprintf(L"\nEvent GUID: %s\n", pwsEventGuid);            CoTaskMemFree(pwsEventGuid);            pwsEventGuid = NULL;            wprintf(L"Event version: %d\n", pEvent->EventHeader.EventDescriptor.Version);            wprintf(L"Event type: %d\n", pEvent->EventHeader.EventDescriptor.Opcode);        }        else if (DecodingSourceXMLFile == pInfo->DecodingSource) // Instrumentation manifest        {            wprintf(L"Event ID: %d\n", pInfo->EventDescriptor.Id);        }        else // Not handling the WPP case        {            goto cleanup;        }        // Print the time stamp for when the event occurred.        ft.dwHighDateTime = pEvent->EventHeader.TimeStamp.HighPart;        ft.dwLowDateTime = pEvent->EventHeader.TimeStamp.LowPart;        FileTimeToSystemTime(&ft, &st);        SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal);        TimeStamp = pEvent->EventHeader.TimeStamp.QuadPart;        Nanoseconds = (TimeStamp % 10000000) * 100;        wprintf(L"%02d/%02d/%02d %02d:%02d:%02d.%I64u\n",             stLocal.wMonth, stLocal.wDay, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, Nanoseconds);        // If the event contains event-specific data use TDH to extract        // the event data. For this example, to extract the data, the event         // must be defined by a MOF class or an instrumentation manifest.        // Need to get the PointerSize for each event to cover the case where you are        // consuming events from multiple log files that could have been generated on         // different architectures. Otherwise, you could have accessed the pointer        // size when you opened the trace above (see pHeader->PointerSize).        if (EVENT_HEADER_FLAG_32_BIT_HEADER == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))        {            PointerSize = 4;        }        else        {            PointerSize = 8;        }        pUserData = (PBYTE)pEvent->UserData;        pEndOfUserData = (PBYTE)pEvent->UserData + pEvent->UserDataLength;        // Print the event data for all the top-level properties. Metadata for all the         // top-level properties come before structure member properties in the         // property information array.        for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)        {            pUserData = PrintProperties(pEvent, pInfo, PointerSize, i, pUserData, pEndOfUserData);            if (NULL == pUserData)            {                wprintf(L"Printing top level properties failed.\n");                goto cleanup;            }        }    }cleanup:    if (pInfo)    {        free(pInfo);    }    if (ERROR_SUCCESS != status || NULL == pUserData)    {        CloseTrace(g_hTrace);    }}// Print the property.PBYTE PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData){    TDHSTATUS status = ERROR_SUCCESS;    USHORT PropertyLength = 0;    DWORD FormattedDataSize = 0;    USHORT UserDataConsumed = 0;    USHORT UserDataLength = 0;    LPWSTR pFormattedData = NULL;    DWORD LastMember = 0;  // Last member of a structure    USHORT ArraySize = 0;    PEVENT_MAP_INFO pMapInfo = NULL;    // Get the length of the property.    status = GetPropertyLength(pEvent, pInfo, i, &PropertyLength);    if (ERROR_SUCCESS != status)    {        wprintf(L"GetPropertyLength failed.\n");        pUserData = NULL;        goto cleanup;    }    // Get the size of the array if the property is an array.    status = GetArraySize(pEvent, pInfo, i, &ArraySize);    for (USHORT k = 0; k < ArraySize; k++)    {        // If the property is a structure, print the members of the structure.        if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)        {            LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex +                 pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;            for (USHORT j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++)            {                pUserData = PrintProperties(pEvent, pInfo, PointerSize, j, pUserData, pEndOfUserData);                if (NULL == pUserData)                {                    wprintf(L"Printing the members of the structure failed.\n");                    pUserData = NULL;                    goto cleanup;                }            }        }        else        {            // Get the name/value mapping if the property specifies a value map.            status = GetMapInfo(pEvent,                 (PWCHAR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset),                pInfo->DecodingSource,                pMapInfo);            if (ERROR_SUCCESS != status)            {                wprintf(L"GetMapInfo failed\n");                pUserData = NULL;                goto cleanup;            }            // Get the size of the buffer required for the formatted data.            status = TdhFormatProperty(                pInfo,                 pMapInfo,                 PointerSize,                 pInfo->EventPropertyInfoArray[i].nonStructType.InType,                pInfo->EventPropertyInfoArray[i].nonStructType.OutType,                PropertyLength,                (USHORT)(pEndOfUserData - pUserData),                pUserData,                &FormattedDataSize,                pFormattedData,                &UserDataConsumed);            if (ERROR_INSUFFICIENT_BUFFER == status)            {                if (pFormattedData)                {                    free(pFormattedData);                    pFormattedData = NULL;                }                pFormattedData = (LPWSTR) malloc(FormattedDataSize);                if (pFormattedData == NULL)                {                    wprintf(L"Failed to allocate memory for formatted data (size=%lu).\n", FormattedDataSize);                    status = ERROR_OUTOFMEMORY;                    pUserData = NULL;                    goto cleanup;                }                // Retrieve the formatted data.                status = TdhFormatProperty(                    pInfo,                     pMapInfo,                     PointerSize,                     pInfo->EventPropertyInfoArray[i].nonStructType.InType,                    pInfo->EventPropertyInfoArray[i].nonStructType.OutType,                    PropertyLength,                    (USHORT)(pEndOfUserData - pUserData),                    pUserData,                    &FormattedDataSize,                    pFormattedData,                    &UserDataConsumed);            }            if (ERROR_SUCCESS == status)            {                wprintf(L"%s: %s\n",                     (PWCHAR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset),                    pFormattedData);                pUserData += UserDataConsumed;            }            else            {                wprintf(L"TdhFormatProperty failed with %lu.\n", status);                pUserData = NULL;                goto cleanup;            }        }    }cleanup:    if (pFormattedData)    {        free(pFormattedData);        pFormattedData = NULL;    }    if (pMapInfo)    {        free(pMapInfo);        pMapInfo = NULL;    }    return pUserData;}// Get the length of the property data. For MOF-based events, the size is inferred from the data type// of the property. For manifest-based events, the property can specify the size of the property value// using the length attribute. The length attribue can specify the size directly or specify the name // of another property in the event data that contains the size. If the property does not include the // length attribute, the size is inferred from the data type. The length will be zero for variable// length, null-terminated strings and structures.DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength){    DWORD status = ERROR_SUCCESS;    PROPERTY_DATA_DESCRIPTOR DataDescriptor;    DWORD PropertySize = 0;    // If the property is a binary blob and is defined in a manifest, the property can     // specify the blob's size or it can point to another property that defines the     // blob's size. The PropertyParamLength flag tells you where the blob's size is defined.    if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamLength) == PropertyParamLength)    {        DWORD Length = 0;  // Expects the length to be defined by a UINT16 or UINT32        DWORD j = pInfo->EventPropertyInfoArray[i].lengthPropertyIndex;        ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR));        DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset);        DataDescriptor.ArrayIndex = ULONG_MAX;        status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);        status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Length);        *PropertyLength = (USHORT)Length;    }    else    {        if (pInfo->EventPropertyInfoArray[i].length > 0)        {            *PropertyLength = pInfo->EventPropertyInfoArray[i].length;        }        else        {            // If the property is a binary blob and is defined in a MOF class, the extension            // qualifier is used to determine the size of the blob. However, if the extension             // is IPAddrV6, you must set the PropertyLength variable yourself because the             // EVENT_PROPERTY_INFO.length field will be zero.            if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType &&                TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType)            {                *PropertyLength = (USHORT)sizeof(IN6_ADDR);            }            else if (TDH_INTYPE_UNICODESTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType ||                     TDH_INTYPE_ANSISTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType ||                     (pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)            {                *PropertyLength = pInfo->EventPropertyInfoArray[i].length;            }            else            {                wprintf(L"Unexpected length of 0 for intype %d and outtype %d\n",                     pInfo->EventPropertyInfoArray[i].nonStructType.InType,                    pInfo->EventPropertyInfoArray[i].nonStructType.OutType);                status = ERROR_EVT_INVALID_EVENT_DATA;                goto cleanup;            }        }    }cleanup:    return status;}// Get the size of the array. For MOF-based events, the size is specified in the declaration or using // the MAX qualifier. For manifest-based events, the property can specify the size of the array// using the count attribute. The count attribue can specify the size directly or specify the name // of another property in the event data that contains the size.DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize){    DWORD status = ERROR_SUCCESS;    PROPERTY_DATA_DESCRIPTOR DataDescriptor;    DWORD PropertySize = 0;    if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)    {        DWORD Count = 0;  // Expects the count to be defined by a UINT16 or UINT32        DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex;        ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR));        DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset);        DataDescriptor.ArrayIndex = ULONG_MAX;        status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);        status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Count);        *ArraySize = (USHORT)Count;    }    else    {        *ArraySize = pInfo->EventPropertyInfoArray[i].count;    }    return status;}// Both MOF-based events and manifest-based events can specify name/value maps. The// map values can be integer values or bit values. If the property specifies a value// map, get the map.DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo){    DWORD status = ERROR_SUCCESS;    DWORD MapSize = 0;    // Retrieve the required buffer size for the map info.    status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);    if (ERROR_INSUFFICIENT_BUFFER == status)    {        pMapInfo = (PEVENT_MAP_INFO) malloc(MapSize);        if (pMapInfo == NULL)        {            wprintf(L"Failed to allocate memory for map info (size=%lu).\n", MapSize);            status = ERROR_OUTOFMEMORY;            goto cleanup;        }        // Retrieve the map info.        status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);    }    if (ERROR_SUCCESS == status)    {        if (DecodingSourceXMLFile == DecodingSource)        {            RemoveTrailingSpace(pMapInfo);        }    }    else    {        if  (ERROR_NOT_FOUND == status)        {            status = ERROR_SUCCESS; // This case is okay.        }        else        {            wprintf(L"TdhGetEventMapInformation failed with 0x%x.\n", status);        }    }cleanup:    return status;}// The mapped string values defined in a manifest will contain a trailing space// in the EVENT_MAP_ENTRY structure. Replace the trailing space with a null-// terminating character, so that the bit mapped strings are correctly formatted.void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo){    DWORD ByteLength = 0;    for (DWORD i = 0; i < pMapInfo->EntryCount; i++)    {        ByteLength = (wcslen((LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)) - 1) * 2;        *((LPWSTR)((PBYTE)pMapInfo + (pMapInfo->MapEntryArray[i].OutputOffset + ByteLength))) = L'\0';    }}// Get the metadata for the event.DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo){    DWORD status = ERROR_SUCCESS;    DWORD BufferSize = 0;    // Retrieve the required buffer size for the event metadata.    status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);    if (ERROR_INSUFFICIENT_BUFFER == status)    {        pInfo = (TRACE_EVENT_INFO*) malloc(BufferSize);        if (pInfo == NULL)        {            wprintf(L"Failed to allocate memory for event info (size=%lu).\n", BufferSize);            status = ERROR_OUTOFMEMORY;            goto cleanup;        }        // Retrieve the event metadata.        status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);    }    if (ERROR_SUCCESS != status)    {        wprintf(L"TdhGetEventInformation failed with 0x%x.\n", status);    }cleanup:    return status;}

同上,分析etl文件的,这两个文件,感觉都是转化为xml对etl进行分析的。

//Turns the DEFINE_GUID for EventTraceGuid into a const.#define INITGUID#include <windows.h>#include <stdio.h>#include <strsafe.h>#include <wbemidl.h>#include <wmistr.h>#include <evntrace.h>#include <tdh.h>#include <in6addr.h>#pragma comment(lib, "tdh.lib")#pragma comment(lib, "ws2_32.lib")  // For ntohs function#define LOGFILE_PATH L"C:\\Code\\etw\\V2EventTraceController\\mylogfile.etl"#define MAX_NAME 256// Used to determine the data size of property values that contain a// Pointer value. The value will be 4 or 8.USHORT g_PointerSize = 0;// Used to calculate CPU usageULONG g_TimerResolution = 0;// Used to determine if the session is a private session or kernel session.// You need to know this when accessing some members of the EVENT_TRACE.Header// member (for example, KernelTime or UserTime).BOOL g_bUserMode = FALSE;// Handle to the trace file that you opened.TRACEHANDLE g_hTrace = 0;  // Prototypesvoid WINAPI ProcessEvent(PEVENT_RECORD pEvent);DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);DWORD PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, LPWSTR pStructureName, USHORT StructIndex);DWORD FormatAndPrintData(PEVENT_RECORD pEvent, USHORT InType, USHORT OutType, PBYTE pData, DWORD DataSize, PEVENT_MAP_INFO pMapInfo); void PrintMapString(PEVENT_MAP_INFO pMapInfo, PBYTE pData);DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize);DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo);void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo);typedef LPTSTR (NTAPI *PIPV6ADDRTOSTRING)(  const IN6_ADDR *Addr,  LPTSTR S);void wmain(void){    ULONG status = ERROR_SUCCESS;    EVENT_TRACE_LOGFILE trace;    TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;    // Identify the log file from which you want to consume events    // and the callbacks used to process the events and buffers.    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));    trace.LogFileName = (LPWSTR) LOGFILE_PATH;    trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);    trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;    g_hTrace = OpenTrace(&trace);    if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)    {        wprintf(L"OpenTrace failed with %lu\n", GetLastError());        goto cleanup;    }    g_bUserMode = pHeader->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE;    if (pHeader->TimerResolution > 0)    {        g_TimerResolution = pHeader->TimerResolution / 10000;    }    wprintf(L"Number of events lost:  %lu\n", pHeader->EventsLost);    // Use pHeader to access all fields prior to LoggerName.    // Adjust pHeader based on the pointer size to access    // all fields after LogFileName. This is required only if    // you are consuming events on an architecture that is     // different from architecture used to write the events.    if (pHeader->PointerSize != sizeof(PVOID))    {        pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader +            2 * (pHeader->PointerSize - sizeof(PVOID)));    }    wprintf(L"Number of buffers lost: %lu\n\n", pHeader->BuffersLost);    status = ProcessTrace(&g_hTrace, 1, 0, 0);    if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)    {        wprintf(L"ProcessTrace failed with %lu\n", status);        goto cleanup;    }cleanup:    if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)    {        status = CloseTrace(g_hTrace);    }}// Callback that receives the events. VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent){    DWORD status = ERROR_SUCCESS;    PTRACE_EVENT_INFO pInfo = NULL;    LPWSTR pwsEventGuid = NULL;    ULONGLONG TimeStamp = 0;    ULONGLONG Nanoseconds = 0;    SYSTEMTIME st;    SYSTEMTIME stLocal;    FILETIME ft;    // Skips the event if it is the event trace header. Log files contain this event    // but real-time sessions do not. The event contains the same information as     // the EVENT_TRACE_LOGFILE.LogfileHeader member that you can access when you open     // the trace.     if (IsEqualGUID(pEvent->EventHeader.ProviderId, EventTraceGuid) &&        pEvent->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO)    {        ; // Skip this event.    }    else    {        // Process the event. The pEvent->UserData member is a pointer to         // the event specific data, if it exists.        status = GetEventInformation(pEvent, pInfo);        if (ERROR_SUCCESS != status)        {            wprintf(L"GetEventInformation failed with %lu\n", status);            goto cleanup;        }        // Determine whether the event is defined by a MOF class, in an        // instrumentation manifest, or a WPP template; to use TDH to decode        // the event, it must be defined by one of these three sources.        if (DecodingSourceWbem == pInfo->DecodingSource)  // MOF class        {            HRESULT hr = StringFromCLSID(pInfo->EventGuid, &pwsEventGuid);            if (FAILED(hr))            {                wprintf(L"StringFromCLSID failed with 0x%x\n", hr);                status = hr;                goto cleanup;            }            wprintf(L"\nEvent GUID: %s\n", pwsEventGuid);            CoTaskMemFree(pwsEventGuid);            pwsEventGuid = NULL;            wprintf(L"Event version: %d\n", pEvent->EventHeader.EventDescriptor.Version);            wprintf(L"Event type: %d\n", pEvent->EventHeader.EventDescriptor.Opcode);        }        else if (DecodingSourceXMLFile == pInfo->DecodingSource) // Instrumentation manifest        {            wprintf(L"Event ID: %d\n", pInfo->EventDescriptor.Id);        }        else // Not handling the WPP case        {            goto cleanup;        }        // Print the time stamp for when the event occurred.        ft.dwHighDateTime = pEvent->EventHeader.TimeStamp.HighPart;        ft.dwLowDateTime = pEvent->EventHeader.TimeStamp.LowPart;        FileTimeToSystemTime(&ft, &st);        SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal);        TimeStamp = pEvent->EventHeader.TimeStamp.QuadPart;        Nanoseconds = (TimeStamp % 10000000) * 100;        wprintf(L"%02d/%02d/%02d %02d:%02d:%02d.%I64u\n",             stLocal.wMonth, stLocal.wDay, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, Nanoseconds);        // If the event contains event-specific data use TDH to extract        // the event data. For this example, to extract the data, the event         // must be defined by a MOF class or an instrumentation manifest.        // Need to get the PointerSize for each event to cover the case where you are        // consuming events from multiple log files that could have been generated on         // different architectures. Otherwise, you could have accessed the pointer        // size when you opened the trace above (see pHeader->PointerSize).        if (EVENT_HEADER_FLAG_32_BIT_HEADER == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))        {            g_PointerSize = 4;        }        else        {            g_PointerSize = 8;        }        // Print the event data for all the top-level properties. Metadata for all the         // top-level properties come before structure member properties in the         // property information array. If the EVENT_HEADER_FLAG_STRING_ONLY flag is set,        // the event data is a null-terminated string, so just print it.        if (EVENT_HEADER_FLAG_STRING_ONLY == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_STRING_ONLY))        {            wprintf(L"%s\n", (LPWSTR)pEvent->UserData);        }        else        {            for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)            {                status = PrintProperties(pEvent, pInfo, i, NULL, 0);                if (ERROR_SUCCESS != status)                {                    wprintf(L"Printing top level properties failed.\n");                    goto cleanup;                }            }        }    }cleanup:    if (pInfo)    {        free(pInfo);    }    if (ERROR_SUCCESS != status)    {        CloseTrace(g_hTrace);    }}// Print the property.DWORD PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, LPWSTR pStructureName, USHORT StructIndex){    DWORD status = ERROR_SUCCESS;    DWORD LastMember = 0;  // Last member of a structure    USHORT ArraySize = 0;    PEVENT_MAP_INFO pMapInfo = NULL;    PROPERTY_DATA_DESCRIPTOR DataDescriptors[2];    ULONG DescriptorsCount = 0;    DWORD PropertySize = 0;    PBYTE pData = NULL;    // Get the size of the array if the property is an array.    status = GetArraySize(pEvent, pInfo, i, &ArraySize);    for (USHORT k = 0; k < ArraySize; k++)    {        wprintf(L"%*s%s: ", (pStructureName) ? 4 : 0, L"", (LPWSTR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset));        // If the property is a structure, print the members of the structure.        if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)        {            wprintf(L"\n");            LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex +                 pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;            for (USHORT j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++)            {                status = PrintProperties(pEvent, pInfo, j, (LPWSTR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset), k);                if (ERROR_SUCCESS != status)                {                    wprintf(L"Printing the members of the structure failed.\n");                    goto cleanup;                }            }        }        else        {            ZeroMemory(&DataDescriptors, sizeof(DataDescriptors));            // To retrieve a member of a structure, you need to specify an array of descriptors.             // The first descriptor in the array identifies the name of the structure and the second             // descriptor defines the member of the structure whose data you want to retrieve.             if (pStructureName)            {                DataDescriptors[0].PropertyName = (ULONGLONG)pStructureName;                DataDescriptors[0].ArrayIndex = StructIndex;                DataDescriptors[1].PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset);                DataDescriptors[1].ArrayIndex = k;                DescriptorsCount = 2;            }            else            {                DataDescriptors[0].PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset);                DataDescriptors[0].ArrayIndex = k;                DescriptorsCount = 1;            }            // The TDH API does not support IPv6 addresses. If the output type is TDH_OUTTYPE_IPV6,            // you will not be able to consume the rest of the event. If you try to consume the            // remainder of the event, you will get ERROR_EVT_INVALID_EVENT_DATA.            if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType &&                TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType)            {                wprintf(L"The event contains an IPv6 address. Skipping event.\n");                status = ERROR_EVT_INVALID_EVENT_DATA;                break;            }            else            {                status = TdhGetPropertySize(pEvent, 0, NULL, DescriptorsCount, &DataDescriptors[0], &PropertySize);                if (ERROR_SUCCESS != status)                {                    wprintf(L"TdhGetPropertySize failed with %lu\n", status);                    goto cleanup;                }                pData = (PBYTE)malloc(PropertySize);                if (NULL == pData)                {                    wprintf(L"Failed to allocate memory for property data\n");                    status = ERROR_OUTOFMEMORY;                    goto cleanup;                }                status = TdhGetProperty(pEvent, 0, NULL, DescriptorsCount, &DataDescriptors[0], PropertySize, pData);                // Get the name/value mapping if the property specifies a value map.                status = GetMapInfo(pEvent,                     (PWCHAR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset),                    pInfo->DecodingSource,                    pMapInfo);                if (ERROR_SUCCESS != status)                {                    wprintf(L"GetMapInfo failed\n");                    goto cleanup;                }                status = FormatAndPrintData(pEvent,                     pInfo->EventPropertyInfoArray[i].nonStructType.InType,                    pInfo->EventPropertyInfoArray[i].nonStructType.OutType,                    pData,                     PropertySize,                    pMapInfo                     );                if (ERROR_SUCCESS != status)                {                    wprintf(L"GetMapInfo failed\n");                    goto cleanup;                }                if (pData)                {                    free(pData);                    pData = NULL;                }                if (pMapInfo)                {                    free(pMapInfo);                    pMapInfo = NULL;                }            }        }    }cleanup:    if (pData)    {        free(pData);        pData = NULL;    }    if (pMapInfo)    {        free(pMapInfo);        pMapInfo = NULL;    }    return status;}DWORD FormatAndPrintData(PEVENT_RECORD pEvent, USHORT InType, USHORT OutType, PBYTE pData, DWORD DataSize, PEVENT_MAP_INFO pMapInfo){    UNREFERENCED_PARAMETER(pEvent);    DWORD status = ERROR_SUCCESS;    switch (InType)    {        case TDH_INTYPE_UNICODESTRING:        case TDH_INTYPE_COUNTEDSTRING:        case TDH_INTYPE_REVERSEDCOUNTEDSTRING:        case TDH_INTYPE_NONNULLTERMINATEDSTRING:        {            size_t StringLength = 0;            if (TDH_INTYPE_COUNTEDSTRING == InType)            {                StringLength = *(PUSHORT)pData;            }            else if (TDH_INTYPE_REVERSEDCOUNTEDSTRING == InType)            {                StringLength = MAKEWORD(HIBYTE((PUSHORT)pData), LOBYTE((PUSHORT)pData));            }            else if (TDH_INTYPE_NONNULLTERMINATEDSTRING == InType)            {                StringLength = DataSize;            }            else            {                StringLength = wcslen((LPWSTR)pData);            }            wprintf(L"%.*s\n", StringLength, (LPWSTR)pData);            break;        }        case TDH_INTYPE_ANSISTRING:        case TDH_INTYPE_COUNTEDANSISTRING:        case TDH_INTYPE_REVERSEDCOUNTEDANSISTRING:        case TDH_INTYPE_NONNULLTERMINATEDANSISTRING:        {            size_t StringLength = 0;            if (TDH_INTYPE_COUNTEDANSISTRING == InType)            {                StringLength = *(PUSHORT)pData;            }            else if (TDH_INTYPE_REVERSEDCOUNTEDANSISTRING == InType)            {                StringLength = MAKEWORD(HIBYTE((PUSHORT)pData), LOBYTE((PUSHORT)pData));            }            else if (TDH_INTYPE_NONNULLTERMINATEDANSISTRING == InType)            {                StringLength = DataSize;            }            else            {                StringLength = strlen((LPSTR)pData);            }            wprintf(L"%.*S\n", StringLength, (LPSTR)pData);            break;        }        case TDH_INTYPE_INT8:        {            wprintf(L"%hd\n", *(PCHAR)pData);            break;        }        case TDH_INTYPE_UINT8:        {            if (TDH_OUTTYPE_HEXINT8 == OutType)            {                wprintf(L"0x%x\n", *(PBYTE)pData);            }            else            {                wprintf(L"%hu\n", *(PBYTE)pData);            }            break;        }        case TDH_INTYPE_INT16:        {            wprintf(L"%hd\n", *(PSHORT)pData);            break;        }        case TDH_INTYPE_UINT16:        {            if (TDH_OUTTYPE_HEXINT16 == OutType)            {                wprintf(L"0x%x\n", *(PUSHORT)pData);            }            else if (TDH_OUTTYPE_PORT == OutType)            {                wprintf(L"%hu\n", ntohs(*(PUSHORT)pData));            }            else            {                wprintf(L"%hu\n", *(PUSHORT)pData);            }            break;        }        case TDH_INTYPE_INT32:        {            if (TDH_OUTTYPE_HRESULT == OutType)            {                wprintf(L"0x%x\n", *(PLONG)pData);            }            else            {                wprintf(L"%d\n", *(PLONG)pData);            }            break;        }        case TDH_INTYPE_UINT32:        {            if (TDH_OUTTYPE_HRESULT == OutType ||                TDH_OUTTYPE_WIN32ERROR == OutType ||                TDH_OUTTYPE_NTSTATUS == OutType ||                TDH_OUTTYPE_HEXINT32 == OutType)            {                wprintf(L"0x%x\n", *(PULONG)pData);            }            else if (TDH_OUTTYPE_IPV4 == OutType)            {                wprintf(L"%d.%d.%d.%d\n", (*(PLONG)pData >>  0) & 0xff,                                          (*(PLONG)pData >>  8) & 0xff,                                          (*(PLONG)pData >>  16) & 0xff,                                          (*(PLONG)pData >>  24) & 0xff);            }            else            {                if (pMapInfo)                {                    PrintMapString(pMapInfo, pData);                }                else                {                    wprintf(L"%lu\n", *(PULONG)pData);                }            }            break;        }        case TDH_INTYPE_INT64:        {            wprintf(L"%I64d\n", *(PLONGLONG)pData);            break;        }        case TDH_INTYPE_UINT64:        {            if (TDH_OUTTYPE_HEXINT64 == OutType)            {                wprintf(L"0x%x\n", *(PULONGLONG)pData);            }            else            {                wprintf(L"%I64u\n", *(PULONGLONG)pData);            }            break;        }        case TDH_INTYPE_FLOAT:        {            wprintf(L"%f\n", *(PFLOAT)pData);            break;        }        case TDH_INTYPE_DOUBLE:        {            wprintf(L"%I64f\n", *(DOUBLE*)pData);            break;        }        case TDH_INTYPE_BOOLEAN:        {            wprintf(L"%s\n", (0 == (PBOOL)pData) ? L"false" : L"true");            break;        }        case TDH_INTYPE_BINARY:        {            if (TDH_OUTTYPE_IPV6 == OutType)            {                WCHAR IPv6AddressAsString[46];                PIPV6ADDRTOSTRING fnRtlIpv6AddressToString;                fnRtlIpv6AddressToString = (PIPV6ADDRTOSTRING)GetProcAddress(                    GetModuleHandle(L"ntdll"), "RtlIpv6AddressToStringW");                if (NULL == fnRtlIpv6AddressToString)                {                    wprintf(L"GetProcAddress failed with %lu.\n", status = GetLastError());                    goto cleanup;                }                fnRtlIpv6AddressToString((IN6_ADDR*)pData, IPv6AddressAsString);                wprintf(L"%s\n", IPv6AddressAsString);            }            else            {                for (DWORD i = 0; i < DataSize; i++)                {                    wprintf(L"%.2x", pData[i]);                }                wprintf(L"\n");            }            break;        }        case TDH_INTYPE_GUID:        {            WCHAR szGuid[50];            StringFromGUID2(*(GUID*)pData, szGuid, sizeof(szGuid)-1);            wprintf(L"%s\n", szGuid);            break;        }        case TDH_INTYPE_POINTER:        case TDH_INTYPE_SIZET:        {            if (4 == g_PointerSize)            {                wprintf(L"0x%x\n", *(PULONG)pData);            }            else            {                wprintf(L"0x%x\n", *(PULONGLONG)pData);            }            break;        }        case TDH_INTYPE_FILETIME:        {            break;        }        case TDH_INTYPE_SYSTEMTIME:        {            break;        }        case TDH_INTYPE_SID:        {            WCHAR UserName[MAX_NAME];            WCHAR DomainName[MAX_NAME];            DWORD cchUserSize = MAX_NAME;            DWORD cchDomainSize = MAX_NAME;            SID_NAME_USE eNameUse;            if (!LookupAccountSid(NULL, (PSID)pData, UserName, &cchUserSize, DomainName, &cchDomainSize, &eNameUse))            {                if (ERROR_NONE_MAPPED == status)                {                    wprintf(L"Unable to locate account for the specified SID\n");                    status = ERROR_SUCCESS;                }                else                {                    wprintf(L"LookupAccountSid failed with %lu\n", status = GetLastError());                }                goto cleanup;            }            else            {                wprintf(L"%s\\%s\n", DomainName, UserName);            }            break;        }        case TDH_INTYPE_HEXINT32:        {            wprintf(L"0x%x\n", (PULONG)pData);            break;        }        case TDH_INTYPE_HEXINT64:        {            wprintf(L"0x%x\n", (PULONGLONG)pData);            break;        }        case TDH_INTYPE_UNICODECHAR:        {            wprintf(L"%c\n", *(PWCHAR)pData);            break;        }        case TDH_INTYPE_ANSICHAR:        {            wprintf(L"%C\n", *(PCHAR)pData);            break;        }        case TDH_INTYPE_WBEMSID:        {            WCHAR UserName[MAX_NAME];            WCHAR DomainName[MAX_NAME];            DWORD cchUserSize = MAX_NAME;            DWORD cchDomainSize = MAX_NAME;            SID_NAME_USE eNameUse;            if ((PULONG)pData > 0)            {                // A WBEM SID is actually a TOKEN_USER structure followed                 // by the SID. The size of the TOKEN_USER structure differs                 // depending on whether the events were generated on a 32-bit                 // or 64-bit architecture. Also the structure is aligned                // on an 8-byte boundary, so its size is 8 bytes on a                // 32-bit computer and 16 bytes on a 64-bit computer.                // Doubling the pointer size handles both cases.                pData += g_PointerSize * 2;                if (!LookupAccountSid(NULL, (PSID)pData, UserName, &cchUserSize, DomainName, &cchDomainSize, &eNameUse))                {                    if (ERROR_NONE_MAPPED == status)                    {                        wprintf(L"Unable to locate account for the specified SID\n");                        status = ERROR_SUCCESS;                    }                    else                    {                        wprintf(L"LookupAccountSid failed with %lu\n", status = GetLastError());                    }                    goto cleanup;                }                else                {                    wprintf(L"%s\\%s\n", DomainName, UserName);                }            }            break;        }    default:        status = ERROR_NOT_FOUND;    }cleanup:    return status;}void PrintMapString(PEVENT_MAP_INFO pMapInfo, PBYTE pData){    BOOL MatchFound = FALSE;    if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP) == EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP ||        ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_VALUEMAP) == EVENTMAP_INFO_FLAG_WBEM_VALUEMAP &&        (pMapInfo->Flag & (~EVENTMAP_INFO_FLAG_WBEM_VALUEMAP)) != EVENTMAP_INFO_FLAG_WBEM_FLAG))    {        if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_NO_MAP) == EVENTMAP_INFO_FLAG_WBEM_NO_MAP)        {            wprintf(L"%s\n", (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[*(PULONG)pData].OutputOffset));        }        else        {            for (DWORD i = 0; i < pMapInfo->EntryCount; i++)            {                if (pMapInfo->MapEntryArray[i].Value == *(PULONG)pData)                {                    wprintf(L"%s\n", (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));                    MatchFound = TRUE;                    break;                }            }            if (FALSE == MatchFound)            {                wprintf(L"%lu\n", *(PULONG)pData);            }        }    }    else if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_MANIFEST_BITMAP) == EVENTMAP_INFO_FLAG_MANIFEST_BITMAP ||        (pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_BITMAP) == EVENTMAP_INFO_FLAG_WBEM_BITMAP ||        ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_VALUEMAP) == EVENTMAP_INFO_FLAG_WBEM_VALUEMAP &&        (pMapInfo->Flag & (~EVENTMAP_INFO_FLAG_WBEM_VALUEMAP)) == EVENTMAP_INFO_FLAG_WBEM_FLAG))    {        if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_NO_MAP) == EVENTMAP_INFO_FLAG_WBEM_NO_MAP)        {            DWORD BitPosition = 0;            for (DWORD i = 0; i < pMapInfo->EntryCount; i++)            {                if ((*(PULONG)pData & (BitPosition = (1 << i))) == BitPosition)                {                    wprintf(L"%s%s",                         (MatchFound) ? L" | " : L"",                         (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));                    MatchFound = TRUE;                }            }        }        else        {            for (DWORD i = 0; i < pMapInfo->EntryCount; i++)            {                if ((pMapInfo->MapEntryArray[i].Value & *(PULONG)pData) == pMapInfo->MapEntryArray[i].Value)                {                    wprintf(L"%s%s",                         (MatchFound) ? L" | " : L"",                         (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));                    MatchFound = TRUE;                }            }        }        if (MatchFound)        {            wprintf(L"\n");        }        else        {            wprintf(L"%lu\n", *(PULONG)pData);        }    }}// Get the size of the array. For MOF-based events, the size is specified in the declaration or using // the MAX qualifier. For manifest-based events, the property can specify the size of the array// using the count attribute. The count attribue can specify the size directly or specify the name // of another property in the event data that contains the size.DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize){    DWORD status = ERROR_SUCCESS;    PROPERTY_DATA_DESCRIPTOR DataDescriptor;    DWORD PropertySize = 0;    if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)    {        DWORD Count = 0;  // Expects the count to be defined by a UINT16 or UINT32        DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex;        ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR));        DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset);        DataDescriptor.ArrayIndex = ULONG_MAX;        status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);        status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Count);        *ArraySize = (USHORT)Count;    }    else    {        *ArraySize = pInfo->EventPropertyInfoArray[i].count;    }    return status;}// Both MOF-based events and manifest-based events can specify name/value maps. The// map values can be integer values or bit values. If the property specifies a value// map, get the map.DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo){    DWORD status = ERROR_SUCCESS;    DWORD MapSize = 0;    // Retrieve the required buffer size for the map info.    status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);    if (ERROR_INSUFFICIENT_BUFFER == status)    {        pMapInfo = (PEVENT_MAP_INFO) malloc(MapSize);        if (pMapInfo == NULL)        {            wprintf(L"Failed to allocate memory for map info (size=%lu).\n", MapSize);            status = ERROR_OUTOFMEMORY;            goto cleanup;        }        // Retrieve the map info.        status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);    }    if (ERROR_SUCCESS == status)    {        if (DecodingSourceXMLFile == DecodingSource)        {            RemoveTrailingSpace(pMapInfo);        }    }    else    {        if  (ERROR_NOT_FOUND == status)        {            status = ERROR_SUCCESS; // This case is okay.        }        else        {            wprintf(L"TdhGetEventMapInformation failed with 0x%x.\n", status);        }    }cleanup:    return status;}// The mapped string values defined in a manifest will contain a trailing space// in the EVENT_MAP_ENTRY structure. Replace the trailing space with a null-// terminating character, so that the bit mapped strings are correctly formatted.void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo){    SIZE_T ByteLength = 0;    for (DWORD i = 0; i < pMapInfo->EntryCount; i++)    {        ByteLength = (wcslen((LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)) - 1) * 2;        *((LPWSTR)((PBYTE)pMapInfo + (pMapInfo->MapEntryArray[i].OutputOffset + ByteLength))) = L'\0';    }}// Get the metadata for the event.DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo){    DWORD status = ERROR_SUCCESS;    DWORD BufferSize = 0;    // Retrieve the required buffer size for the event metadata.    status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);    if (ERROR_INSUFFICIENT_BUFFER == status)    {        pInfo = (TRACE_EVENT_INFO*) malloc(BufferSize);        if (pInfo == NULL)        {            wprintf(L"Failed to allocate memory for event info (size=%lu).\n", BufferSize);            status = ERROR_OUTOFMEMORY;            goto cleanup;        }        // Retrieve the event metadata.        status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);    }    if (ERROR_SUCCESS != status)    {        wprintf(L"TdhGetEventInformation failed with 0x%x.\n", status);    }cleanup:    return status;}

下面的代码是将etl中分析出的数据结构的属性列举并描述。(不清楚)

//Turns the DEFINE_GUID for EventTraceGuid into a const.#define INITGUID#include <windows.h>#include <stdio.h>#include <comdef.h>#include <guiddef.h>#include <wbemidl.h>#include <wmistr.h>#include <evntrace.h>#include <tdh.h>#pragma comment(lib, "tdh.lib")#define LOGFILE_PATH L"<FULLPATHTOTHELOGFILE.etl>"static const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };// Strings that represent the source of the event metadata.WCHAR* pSource[] = {L"XML instrumentation manifest", L"WMI MOF class", L"WPP TMF file"};// Handle to the trace file that you opened.TRACEHANDLE g_hTrace = 0;  // Prototypesvoid WINAPI ProcessEvent(PEVENT_RECORD pEvent);DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);DWORD PrintPropertyMetadata(TRACE_EVENT_INFO* pInfo, DWORD i, USHORT indent);void wmain(void){    ULONG status = ERROR_SUCCESS;    EVENT_TRACE_LOGFILE trace;    TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;    // Identify the log file from which you want to consume events    // and the callbacks used to process the events and buffers.    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));    trace.LogFileName = (LPWSTR) LOGFILE_PATH;    trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);    trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;    g_hTrace = OpenTrace(&trace);    if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)    {        wprintf(L"OpenTrace failed with %lu\n", GetLastError());        goto cleanup;    }    status = ProcessTrace(&g_hTrace, 1, 0, 0);    if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)    {        wprintf(L"ProcessTrace failed with %lu\n", status);        goto cleanup;    }cleanup:    if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)    {        status = CloseTrace(g_hTrace);    }}VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent){    DWORD status = ERROR_SUCCESS;    HRESULT hr = S_OK;    PTRACE_EVENT_INFO pInfo = NULL;    LPWSTR pStringGuid = NULL;    // Skips the event if it is the event trace header. Log files contain this event    // but real-time sessions do not. The event contains the same information as     // the EVENT_TRACE_LOGFILE.LogfileHeader member that you can access when you open     // the trace.     if (IsEqualGUID(pEvent->EventHeader.ProviderId, EventTraceGuid) &&        pEvent->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO)    {        ; // Skip this event.    }    else    {        // Process the event. This example does not process the event data but        // instead prints the metadata that describes each event.        status = GetEventInformation(pEvent, pInfo);        if (ERROR_SUCCESS != status)        {            wprintf(L"GetEventInformation failed with %lu\n", status);            goto cleanup;        }        wprintf(L"Decoding source: %s\n", pSource[pInfo->DecodingSource]);        if (DecodingSourceWPP == pInfo->DecodingSource)        {            // This example is not rendering WPP metadata.            goto cleanup;        }        if (pInfo->ProviderNameOffset > 0)        {            wprintf(L"Provider name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ProviderNameOffset));        }        hr = StringFromCLSID(pInfo->ProviderGuid, &pStringGuid);        if (FAILED(hr))        {            wprintf(L"StringFromCLSID(ProviderGuid) failed with 0x%x\n", hr);            status = hr;            goto cleanup;        }        wprintf(L"\nProvider GUID: %s\n", pStringGuid);        CoTaskMemFree(pStringGuid);        pStringGuid = NULL;        if (!IsEqualGUID(pInfo->EventGuid, GUID_NULL))        {            hr = StringFromCLSID(pInfo->EventGuid, &pStringGuid);            if (FAILED(hr))            {                wprintf(L"StringFromCLSID(EventGuid) failed with 0x%x\n", hr);                status = hr;                goto cleanup;            }            wprintf(L"\nEvent GUID: %s\n", pStringGuid);            CoTaskMemFree(pStringGuid);            pStringGuid = NULL;        }        if (DecodingSourceXMLFile == pInfo->DecodingSource)        {            wprintf(L"Event ID: %hu\n", pInfo->EventDescriptor.Id);        }        wprintf(L"Version: %d\n", pInfo->EventDescriptor.Version);        if (pInfo->ChannelNameOffset > 0)        {            wprintf(L"Channel name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ChannelNameOffset));        }        if (pInfo->LevelNameOffset > 0)        {            wprintf(L"Level name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->LevelNameOffset));        }        else        {            wprintf(L"Level: %hu\n", pInfo->EventDescriptor.Level);        }        if (DecodingSourceXMLFile == pInfo->DecodingSource)        {            if (pInfo->OpcodeNameOffset > 0)            {                wprintf(L"Opcode name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->OpcodeNameOffset));            }        }        else        {            wprintf(L"Type: %hu\n", pInfo->EventDescriptor.Opcode);        }        if (DecodingSourceXMLFile == pInfo->DecodingSource)        {            if (pInfo->TaskNameOffset > 0)            {                wprintf(L"Task name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->TaskNameOffset));            }        }        else        {            wprintf(L"Task: %hu\n", pInfo->EventDescriptor.Task);        }        wprintf(L"Keyword mask: 0x%x\n", pInfo->EventDescriptor.Keyword);        if (pInfo->KeywordsNameOffset)        {            LPWSTR pKeyword = (LPWSTR)((PBYTE)(pInfo) + pInfo->KeywordsNameOffset);            for (; *pKeyword != 0; pKeyword += (wcslen(pKeyword) + 1))                wprintf(L"  Keyword name: %s\n", pKeyword);        }        if (pInfo->EventMessageOffset > 0)        {            wprintf(L"Event message: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->EventMessageOffset));        }        if (pInfo->ActivityIDNameOffset > 0)        {            wprintf(L"Activity ID name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ActivityIDNameOffset));        }        if (pInfo->RelatedActivityIDNameOffset > 0)        {            wprintf(L"Related activity ID name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->RelatedActivityIDNameOffset));        }        wprintf(L"Number of top-level properties: %lu\n", pInfo->TopLevelPropertyCount);        wprintf(L"Total number of properties: %lu\n", pInfo->PropertyCount);        // Print the metadata for all the top-level properties. Metadata for all the         // top-level properties come before structure member properties in the         // property information array.        if (pInfo->TopLevelPropertyCount > 0)        {            wprintf(L"\nThe following are the user data properties defined for this event:\n");            for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)            {                status = PrintPropertyMetadata(pInfo, i, 0);                if (ERROR_SUCCESS != status)                {                    wprintf(L"Printing metadata for top-level properties failed.\n");                    goto cleanup;                }            }        }        else        {            wprintf(L"\nThe event does not define any user data properties.\n");        }        wprintf(L"\n");    }cleanup:    if (pInfo)    {        free(pInfo);    }    if (ERROR_SUCCESS != status)    {        CloseTrace(g_hTrace);    }}DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo){    DWORD status = ERROR_SUCCESS;    DWORD BufferSize = 0;    // Retrieve the required buffer size for the event metadata.    status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);    if (ERROR_INSUFFICIENT_BUFFER == status)    {        pInfo = (TRACE_EVENT_INFO*) malloc(BufferSize);        if (pInfo == NULL)        {            wprintf(L"Failed to allocate memory for event info (size=%lu).\n", BufferSize);            status = ERROR_OUTOFMEMORY;            goto cleanup;        }        // Retrieve the event metadata.        status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);    }    if (ERROR_SUCCESS != status)    {        wprintf(L"TdhGetEventInformation failed with 0x%x.\n", status);    }cleanup:    return status;}// Print the metadata for each property.DWORD PrintPropertyMetadata(TRACE_EVENT_INFO* pinfo, DWORD i, USHORT indent){    DWORD status = ERROR_SUCCESS;    DWORD j = 0;    DWORD lastMember = 0;  // Last member of a structure    // Print property name.    wprintf(L"%*s%s", indent, L"", (LPWSTR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[i].NameOffset));    // If the property is an array, the property can define the array size or it can    // point to another property whose value defines the array size. The PropertyParamCount    // flag tells you where the array size is defined.    if ((pinfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)    {        j = pinfo->EventPropertyInfoArray[i].countPropertyIndex;        wprintf(L" (array size is defined by %s)", (LPWSTR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[j].NameOffset));    }    else    {        if (pinfo->EventPropertyInfoArray[i].count > 1)            wprintf(L" (array size is %lu)", pinfo->EventPropertyInfoArray[i].count);    }    // If the property is a buffer, the property can define the buffer size or it can    // point to another property whose value defines the buffer size. The PropertyParamLength    // flag tells you where the buffer size is defined.    if ((pinfo->EventPropertyInfoArray[i].Flags & PropertyParamLength) == PropertyParamLength)    {        j = pinfo->EventPropertyInfoArray[i].lengthPropertyIndex;        wprintf(L" (size is defined by %s)", (LPWSTR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[j].NameOffset));    }    else    {        // Variable length properties such as structures and some strings do not have        // length definitions.        if (pinfo->EventPropertyInfoArray[i].length > 0)            wprintf(L" (size is %lu bytes)", pinfo->EventPropertyInfoArray[i].length);        else            wprintf(L" (size  is unknown)");    }    wprintf(L"\n");    // If the property is a structure, print the members of the structure.    if ((pinfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)    {        wprintf(L"%*s(The property is a structure and has the following %hu members:)\n", 4, L"",            pinfo->EventPropertyInfoArray[i].structType.NumOfStructMembers);        lastMember = pinfo->EventPropertyInfoArray[i].structType.StructStartIndex +             pinfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;        for (j = pinfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < lastMember; j++)        {            PrintPropertyMetadata(pinfo, j, 4);        }    }    else    {        // You can use InType to determine the data type of the member and OutType        // to determine the output format of the data.        if (pinfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset)        {            // You can pass the name to the TdhGetEventMapInformation function to             // retrieve metadata about the value map.            wprintf(L"%*s(Map attribute name is %s)\n", indent, L"",                 (PWCHAR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset));        }    }    return status;}

参考:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363688(v=vs.85).aspx

0 0
原创粉丝点击