EnableTraceEx2 函数 (evntrace.h)

跟踪会话控制器调用 EnableTraceEx2 来配置 ETW 事件提供程序如何将事件记录到跟踪会话。

此函数取代了 EnableTraceEnableTraceEx 函数。

语法

ULONG WMIAPI EnableTraceEx2(
                 CONTROLTRACE_ID          TraceId,
  [in]           LPCGUID                  ProviderId,
  [in]           ULONG                    ControlCode,
  [in]           UCHAR                    Level,
  [in]           ULONGLONG                MatchAnyKeyword,
  [in]           ULONGLONG                MatchAllKeyword,
  [in]           ULONG                    Timeout,
  [in, optional] PENABLE_TRACE_PARAMETERS EnableParameters
);

参数

TraceId

[in] ProviderId

要配置的事件提供程序的提供程序 ID(控制 GUID)。

[in] ControlCode

可以指定以下控制代码之一:

价值 意义
EVENT_CONTROL_CODE_DISABLE_PROVIDER 更新会话配置,以便会话不会从提供程序接收事件。
EVENT_CONTROL_CODE_ENABLE_PROVIDER 更新会话配置,以便会话从提供程序接收请求的事件。
EVENT_CONTROL_CODE_CAPTURE_STATE 请求提供程序记录其状态信息。

[in] Level

一个值,该值指示希望提供程序写入的最大事件级别。 除了满足 matchAnyKeywordMatchAllKeyword 条件之外,提供程序通常还写入事件(如果事件的级别小于或等于此值)。

Microsoft定义级别 1-5 的语义,如下所示。 较低的值表示更严重的事件。 级别 的每个值都支持指定的级别和更严重的级别。 例如,如果指定 TRACE_LEVEL_WARNING,使用者将收到警告、错误和关键事件。

价值 意义
TRACE_LEVEL_CRITICAL (1) 异常退出或终止事件
TRACE_LEVEL_ERROR (2) 严重错误事件
TRACE_LEVEL_WARNING (3) 警告事件,例如分配失败
TRACE_LEVEL_INFORMATION (4) 非错误信息性事件
TRACE_LEVEL_VERBOSE (5) 详细的诊断事件

TRACE_LEVEL 常量在 evntrace.h中定义。 winmeta.h中定义了等效的 WINMETA_LEVEL 常量。

[in] MatchAnyKeyword

用于确定要提供程序写入的事件类别的关键字的 64 位掩码。 如果事件的关键字位匹配 此值中设置的任何位,或者事件没有设置关键字位,除了满足 LevelMatchAllKeyword 条件之外,提供程序通常会写入事件。

[in] MatchAllKeyword

限制提供程序写入的事件的关键字的 64 位掩码。 提供程序通常写入事件(如果事件的关键字位匹配 此值中设置的所有位,或者事件没有设置关键字位,除了满足 LevelMatchAnyKeyword 条件。

此值通常设置为 0。

[in] Timeout

如果 超时 为 0,则此函数将开始异步配置提供程序,并立即返回(即它将返回而不等待提供程序回调完成)。

否则,此函数将开始配置提供程序,然后开始等待配置完成,包括等待所有提供程序回调完成。 如果配置在指定超时之前完成,此函数将返回 ERROR_SUCCESS。 否则,此函数将返回 ERROR_TIMEOUT

要永远等待,请设置为 INFINITE

[in, optional] EnableParameters

用于启用提供程序的跟踪参数。 有关详细信息,请参阅 ENABLE_TRACE_PARAMETERS

返回值

如果函数成功,则返回值 ERROR_SUCCESS

如果函数失败,则返回值是系统错误代码之一。 下面是一些常见的错误及其原因。

  • ERROR_INVALID_PARAMETER

    参数不正确。

    如果以下任一项为 true,可能会发生这种情况:

    • ProviderIdNULL
    • TraceHandle0
  • ERROR_TIMEOUT

    在启用回调完成之前过期的超时值。 有关详细信息,请参阅 超时 参数。

  • ERROR_INVALID_FUNCTION

    如果未注册提供程序,则无法更新级别。

  • ERROR_NO_SYSTEM_RESOURCES

    超出了可以启用提供程序的跟踪会话数。

  • ERROR_ACCESS_DENIED

    只有具有管理权限、Performance Log Users 组中的用户以及作为 LocalSystemLocalServiceNetworkService 运行的服务才能将事件提供程序启用跨进程会话。 若要授予受限用户启用事件提供程序的功能,请将其添加到 Performance Log Users 组,或查看 EventAccessControl

    Windows XP 和 Windows 2000: 任何人都可以启用事件提供程序。

言论

事件跟踪控制器调用此函数以配置将事件写入会话的事件提供程序。 例如,控制器可以调用此函数开始从提供程序收集事件、调整从提供程序收集的事件的级别或关键字,或停止从提供程序收集事件。

提供程序的启用行为取决于提供程序使用的 API。

  • 使用 RegisterTraceGuids(例如使用基于 TMF 的 WPP 或 MOF 的提供程序)的提供程序使用旧启用系统(有时称为“经典 ETW”)。 为会话启用或重新配置旧提供程序时,ETW 运行时会通知提供程序并提供对级别的访问权限、MatchAnyKeyword 掩码的低 32 位和会话 ID。 然后,提供程序使用自己的逻辑来确定应启用哪些事件,并将这些事件直接发送到指定的会话。 在运行时发送到 ETW 的事件数据包括事件的解码 GUID 和消息 ID,但不包括事件的控制 GUID、级别或关键字。 ETW 验证提供程序是否具有必要的权限,然后将事件数据添加到指定的会话。
    • 由于事件直接发送到没有控制 GUID、级别或关键字信息的特定会话,因此 ETW 无法对使用旧启用系统的提供程序执行任何其他筛选或路由。 可将每个事件路由到不超过一个会话。
  • 使用 EventRegister(例如基于清单的提供程序或 TraceLogging 提供程序)的提供程序使用新式启用系统(有时称为“深红色 ETW”)。 为会话启用或重新配置新式提供程序时,ETW 运行时会向提供程序发出级别、64 位 MatchAnyKeyword 掩码、64 位 MatchAllKeyword 掩码和跟踪控制器指定的任何自定义提供程序端筛选数据通知提供程序。 然后,提供程序使用自己的逻辑来确定应启用哪些事件,但大多数提供程序只是复制 EventProviderEnabled的逻辑。 提供程序将启用的事件发送到 ETW 进行路由。 发送到 ETW 的事件数据包括事件的控制 GUID、消息 ID、级别和关键字。 然后,ETW 会根据需要执行其他筛选,将事件路由到相应的会话(s)。
    • 由于事件通过描述性信息发送到 ETW,因此 ETW 可以在将事件添加到会话之前执行其他筛选和路由。 事件可以路由到多个会话(如果适用)。

对于使用新式启用系统的提供程序(即使用 EventRegister的提供程序),ETW 支持跟踪会话控制器可通过 EnableTraceEx2EnableParameters请求的多项功能。 (有关详细信息,请参阅 EVENT_FILTER_DESCRIPTOR

  • 架构化筛选 - 这是传统的筛选设置,也称为提供程序端筛选。 控制器将一组自定义筛选器定义为一个二进制对象,该对象在 EnableCallbackFilterData传递给提供程序。 控制器和提供程序有责任定义和解释这些筛选器。 然后,提供程序可以使用 EventWriteExFilter 参数来指示由于提供程序端筛选而不应向其发送事件的会话。 这需要控制器和提供程序的紧密耦合,因为无法定义可筛选的二进制对象的类型和格式。 TdhEnumerateProviderFilters 函数可用于检索清单中定义的筛选器。
  • 范围筛选 - 根据某些提供程序是否满足范围筛选器指定的条件启用或未启用会话。 有多种类型的范围筛选器允许基于进程 ID(PID)、可执行文件文件名、应用 ID 和应用包名称进行筛选。 Windows 8.1、Windows Server 2012 R2 及更高版本支持此功能。
  • Stackwalk 筛选 - 这通知 ETW 仅对给定的事件 ID 集或(对于 TraceLogging 事件)事件名称执行堆栈演练。 Windows 8.1、Windows Server 2012 R2 及更高版本支持此功能。
  • 属性筛选 - 对于清单提供程序,可以根据级别、关键字、事件 ID 或事件名称等事件属性筛选事件。
  • 事件有效负载筛选 - 对于清单提供程序,可以根据事件是否满足基于一个或多个谓词的逻辑表达式进行实时筛选。

注意

尽管 ETW 支持强大的有效负载和属性筛选,但事件主要应基于范围筛选器进行筛选,或通过控制 GUID、级别和关键字进行筛选。 提供程序通常在生成或发送到 ETW 之前直接在提供程序的代码中执行控制 GUID、级别和关键字筛选。 在大多数提供程序中,由级别或关键字禁用的事件几乎不会影响系统性能。 同样,范围筛选器禁用的提供程序几乎不会影响系统性能。 其他类型的筛选(基于级别和关键字以外的有效负载或属性)通常在提供程序生成事件并将其发送到 ETW 运行时后执行,这意味着该事件会影响系统性能(准备事件并将事件发送到 ETW 的 CPU 时间),即使 ETW 筛选确定事件不应由任何会话记录。 此类筛选仅在减少跟踪数据量方面有效,并且对于减少跟踪 CPU 开销并不那么有效。

每次调用 enableTraceEx2 时,该会话中的提供程序的筛选器将替换为传递给 EnableTraceEx2 函数的参数定义的新参数。 在单个 EnableTraceEx2 调用中传递的多个筛选器可以与累加效果结合使用,但后续调用中传递的筛选器将替换以前的筛选器集。

若要禁用筛选,从而在日志记录会话中启用所有提供程序/事件,请使用 EnableParameters 参数调用 enableTraceEx2 参数,该参数指向 FilterDescCount 成员设置为 0 ENABLE_TRACE_PARAMETERS 结构。

传递给 EnableTraceEx2 函数的每个筛选器由 EVENT_FILTER_DESCRIPTOR中的 类型 成员指定。 将 EVENT_FILTER_DESCRIPTOR 结构的数组传递到 EnableParameters 参数中传递给 EnableTraceEx2 函数的 ENABLE_TRACE_PARAMETERS 结构中。

每种类型的筛选器(特定的 类型 成员)只能在对 EnableTraceEx2 函数的调用中出现一次。 某些筛选器类型允许将多个条件包含在单个筛选器中。 MAX_EVENT_FILTERS_COUNT(在 Evntprov.h 头文件中定义)设置对 enableTraceEx2 调用中包含的筛选器的最大数目;在 Windows SDK 的未来版本中可能会更改值)。

每个筛选器类型都有自己的大小或实体限制,具体取决于 EVENT_FILTER_DESCRIPTOR 结构中特定 类型 成员。 以下列表指示这些限制。

  • EVENT_FILTER_TYPE_SCHEMATIZED

    • 筛选器大小限制:MAX_EVENT_FILTER_DATA_SIZE(1024)
    • 允许的元素数:由提供程序和控制器定义
  • EVENT_FILTER_TYPE_PID

    • 筛选器大小限制:MAX_EVENT_FILTER_DATA_SIZE(1024)
    • 允许的元素数:MAX_EVENT_FILTER_PID_COUNT (8)
  • EVENT_FILTER_TYPE_EXECUTABLE_NAME

    • 筛选器大小限制:MAX_EVENT_FILTER_DATA_SIZE(1024)
    • 允许的元素数:可以包含多个可执行文件名称的单个字符串,用分号分隔。
  • EVENT_FILTER_TYPE_PACKAGE_ID

    • 筛选器大小限制:MAX_EVENT_FILTER_DATA_SIZE(1024)
    • 允许的元素数:一个字符串,可以包含以分号分隔的多个包 ID。
  • EVENT_FILTER_TYPE_PACKAGE_APP_ID

    • 筛选器大小限制:MAX_EVENT_FILTER_DATA_SIZE(1024)
    • 允许的元素数:可以包含多个包相对应用 ID(PRAID)的单个字符串,用分号分隔。
  • EVENT_FILTER_TYPE_PAYLOAD

    • 筛选器大小限制:MAX_EVENT_FILTER_PAYLOAD_SIZE(4096)
    • 允许的元素数:1
  • EVENT_FILTER_TYPE_EVENT_ID

    • 筛选器大小限制:未定义
    • 允许的元素数:MAX_EVENT_FILTER_EVENT_ID_COUNT(64)
  • EVENT_FILTER_TYPE_STACKWALK

    • 筛选器大小限制:未定义
    • 允许的元素数:MAX_EVENT_FILTER_EVENT_ID_COUNT(64)

关键字定义事件类别。 例如,如果提供程序定义 InitializationKeyword = 0x1 (关键字位 0),FileOperationKeyword = 0x2 (关键字位 1),并且 CalculationKeyword = 0x4 (关键字位 2),则可以将 matchAnyKeyword 设置为 (InitializationKeyword |CalculationKeyword) = 5,用于接收初始化和计算事件,但不接收文件事件。

与新式(基于清单的TraceLogging)提供程序一起使用时,MatchAnyKeyword0 值与 0xFFFFFFFFFFFFFFFFMatchAnyKeyword 值相同,即启用所有事件关键字。 但是,此行为不适用于旧版 (MOF 或基于 TMF 的 WPP) 提供程序。 若要从旧提供程序启用所有事件关键字,请将 MatchAnyKeyword 设置为 0xFFFFFFFF。 若要启用旧式和新式提供程序中的所有事件关键字,请将 MatchAnyKeyword 设置为 0xFFFFFFFFFFFFFFFF

如果事件的关键字为零,提供程序会将事件写入会话,而不考虑 matchAnyKeyword MatchAllKeyword 掩码。 (可以使用 EVENT_ENABLE_PROPERTY_IGNORE_KEYWORD_0 标志禁用此行为。

若要指示要启用提供程序组,请使用 EnablePropertyEnableParameters成员上的 EVENT_ENABLE_PROPERTY_PROVIDER_GROUP 标志。

调用 EnableTraceEx2时,提供程序可能或可能尚未注册。 如果提供程序已注册,ETW 将调用提供程序的回调函数(如果有),并且会话开始接收事件。 如果提供程序尚未注册,ETW 将在提供程序注册后立即调用提供程序的回调函数(如果有),然后会话将开始接收事件。 如果提供程序尚未注册,提供程序的回调函数将不会接收源 ID。

如果提供程序已注册且已启用到会话, 可以再次调用 EnableTraceEx2,以更新 级别MatchAnyKeywordMatchAllKeyword 参数 以及 enablePropertyEnableFilterDescEnableParameters的成员。

在 Windows 8.1 上,Windows Server 2012 R2 及更高版本、事件有效负载、范围和堆栈演练筛选器可由 EnableTraceEx2 函数和 ENABLE_TRACE_PARAMETERSEVENT_FILTER_DESCRIPTOR 结构用于筛选记录器会话中的特定条件。 有关事件有效负载筛选器的详细信息,请参阅 TdhCreatePayloadFilter,以及 TdhAggregatePayloadFilters 函数以及 ENABLE_TRACE_PARAMETERSEVENT_FILTER_DESCRIPTORPAYLOAD_FILTER_PREDICATE 结构。

EnableTraceEx2无法启用或禁用特殊系统跟踪提供程序事件。 仅当 StartTrace首次启动跟踪时,只能通过 EVENT_TRACE_PROPERTIESEnableFlags 字段启用它们。

从 Windows 11 开始,可以使用 EnableTraceEx2启用 系统跟踪提供程序事件。

最多八个跟踪会话可以启用和接收来自同一新式(基于清单的TraceLogging)提供程序的事件。 但是,只有一个跟踪会话可以启用旧版(MOF、基于 TMF 的 WPP)提供程序。 如果多个会话尝试启用旧提供程序,则当第二个会话启用同一提供程序时,第一个会话将停止接收事件。 例如,如果会话 A 已启用旧提供程序,然后会话 B 启用同一提供程序,则只有会话 B 会从该提供程序接收事件。

在会话禁用提供程序之前,提供程序将保持为会话启用状态。 如果启动会话的应用程序在未禁用提供程序的情况下结束,则提供程序将保持启用状态。

若要确定用于启用基于清单的提供程序的级别和关键字,请使用以下命令之一:

  • logman 查询提供程序 提供程序名称
  • wevtutil gp provider-name

对于经典提供程序,由提供程序来记录并提供给潜在控制器的严重性级别或启用它支持的标志。 如果提供程序希望由任何控制器启用,则提供程序应接受 0 作为严重级别,并启用标志并将 0 解释为执行默认日志记录的请求(无论可能是什么)。

如果使用 EnableTraceEx2 启用经典提供程序,则会发生以下转换:

例子

以下示例演示如何使用 TdhCreatePayloadFilterTdhAggregatePayloadFilters 函数通过有效负载筛选器 EnableTraceEx2 函数来筛选记录器会话中的特定条件。

#define INITGUID
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <strsafe.h>
#include <evntrace.h>
#include <tdh.h>

#define MAXIMUM_SESSION_NAME 1024

#define PATH_TO_MANIFEST_FILE L"c:\\ExampleManifest.man"

//
// The following definitions would be found in the include file generated by
// message compiler from the manifest file.
//

// Provider Example-Provider Event Count 2
EXTERN_C __declspec(selectany) const GUID EXAMPLE_PROVIDER = {0x37a59b93, 0xbb25, 0x4cee, {0x97, 0xaa, 0x8b, 0x6a, 0xcd, 0xc, 0x4d, 0xf8}};

//
// Event Descriptors
//
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Example_Event_1 = { 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 };
#define Example_Event_1_value 0x1
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Example_Event_2 = { 0x2, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 };
#define Example_Event_2_value 0x2

//
// (End of snippet from include file)
//

// Allocate an EVENT_TRACE_PROPERTIES structure and set the needed logging session properties
PEVENT_TRACE_PROPERTIES AllocateTraceProperties(
    _In_opt_ PCWSTR LoggerName,
    _In_opt_ PCWSTR LogFileName
)
{
    PEVENT_TRACE_PROPERTIES TraceProperties = NULL;
    ULONG BufferSize;

    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) +
        (MAXIMUM_SESSION_NAME + MAX_PATH) * sizeof(WCHAR);

    TraceProperties = (PEVENT_TRACE_PROPERTIES)malloc(BufferSize);
    if (TraceProperties == NULL) {
        printf("Unable to allocate %d bytes for properties structure.\n", BufferSize);
        goto Exit;
    }

    //
    // Set the session properties.
    //
    ZeroMemory(TraceProperties, BufferSize);
    TraceProperties->Wnode.BufferSize = BufferSize;
    TraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    TraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
    TraceProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) +
        (MAXIMUM_SESSION_NAME * sizeof(WCHAR));

    if (LoggerName != NULL) {
        StringCchCopyW((LPWSTR)((PCHAR)TraceProperties + TraceProperties->LoggerNameOffset),
            MAXIMUM_SESSION_NAME,
            LoggerName);
    }

    if (LogFileName != NULL) {
        StringCchCopyW((LPWSTR)((PCHAR)TraceProperties + TraceProperties->LogFileNameOffset),
            MAX_PATH,
            LogFileName);
    }

Exit:
    return TraceProperties;
}

// Free the EVENT_TRACE_PROPERTIES structure previously allocated
VOID FreeTraceProperties(
    _In_ PEVENT_TRACE_PROPERTIES TraceProperties
)
{
    free(TraceProperties);
    return;
}

// Set the values needed in a PAYLOAD_FILTER_PREDICATE for a single payload filter
FORCEINLINE VOID PayloadPredicateCreate(
    _Out_ PAYLOAD_FILTER_PREDICATE* Predicate,
    _In_ PCWSTR FieldName,
    USHORT CompareOp,
    PCWSTR Value
)
{
    Predicate->FieldName = (PWSTR)FieldName;
    Predicate->CompareOp = CompareOp;
    Predicate->Value = (PWSTR)Value;
    return;
}

int __cdecl wmain()
{
    UINT i;
    PVOID EventFilters[2];
    EVENT_FILTER_DESCRIPTOR FilterDescriptor;
    UINT PredicateCount;
    PAYLOAD_FILTER_PREDICATE Predicates[3];
    ULONG FilterCount;
    ULONG Status = ERROR_SUCCESS;
    TRACEHANDLE SessionHandle = 0;
    PEVENT_TRACE_PROPERTIES TraceProperties;
    BOOLEAN TraceStarted = FALSE;
    PCWSTR LoggerName = L"MyTrace";
    ENABLE_TRACE_PARAMETERS EnableParameters;

    ZeroMemory(EventFilters, sizeof(EventFilters));
    ZeroMemory(Predicates, sizeof(Predicates));
    TraceProperties = NULL;
    FilterCount = 0;

    //
    // Load the manifest for the provider
    //
    Status = TdhLoadManifest((PWSTR)PATH_TO_MANIFEST_FILE);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCreatePayloadFilter() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Create predicates that match the following high-level expression:
    //
    // INCLUDE Example_Event_1 IF
    //     Example_Event_1.Initiator == "User" AND
    //     7 <= Example_Event_1.Level <= 16
    //
    PredicateCount = 0;

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        (PWSTR)L"Initiator",
        PAYLOADFIELD_IS,
        (PWSTR)L"User");

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"Level",
        PAYLOADFIELD_BETWEEN,
        L"7,16");

    Status = TdhCreatePayloadFilter(
        &EXAMPLE_PROVIDER,
        &Example_Event_1,
        FALSE,      // Match all predicates (AND)
        PredicateCount,
        Predicates,
        &EventFilters[FilterCount++]);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCreatePayloadFilter() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Create predicates that match the following high-level expression:
    // INCLUDE Example_Event_2 IF
    //      Example_Event_2.Title CONTAINS "UNI" OR
    //      Example_Event_2.InstanceId == {0E95CFBC-58D4-44BA-BE40-E63A853536DF} OR
    //      Example_Event_2.ErrorCode != 0      //
    PredicateCount = 0;

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"Title",
        PAYLOADFIELD_CONTAINS,
        L"UNI");

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"InstanceId",
        PAYLOADFIELD_IS,
        L" {0E95CFBC-58D4-44BA-BE40-E63A853536DF}");

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"ErrorCode",
        PAYLOADFIELD_NE,
        L"0");

    Status = TdhCreatePayloadFilter(
        &EXAMPLE_PROVIDER,
        &Example_Event_2,
        FALSE,      // Match any predicates (OR)
        PredicateCount,
        Predicates,
        &EventFilters[FilterCount++]);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCreatePayloadFilter() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Combine the interim filters into a final filter descriptor.
    //
    Status = TdhAggregatePayloadFilters(
        FilterCount,
        EventFilters,
        NULL,
        &FilterDescriptor);
    if (Status != ERROR_SUCCESS) {
        printf("TdhAggregatePayloadFilters() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Clean up the interim filters
    //
    for (i = 0; i < FilterCount; i++) {

        Status = TdhDeletePayloadFilter(&EventFilters[i]);
        if (Status != ERROR_SUCCESS) {
            printf("TdhDeletePayloadFilter() failed with %lu\n", Status);
            goto Exit;
        }
    }

    //
    // Create a new trace session
    //
    //
    // Allocate EVENT_TRACE_PROPERTIES structure and perform some
    // basic initialization.
    //
    // N.B. LoggerName will be populated during StartTrace call.
    //
    TraceProperties = AllocateTraceProperties(NULL, L"SystemTrace.etl");
    if (TraceProperties == NULL) {
        Status = ERROR_OUTOFMEMORY;
        goto Exit;
    }

    TraceProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_SYSTEM_LOGGER_MODE;
    TraceProperties->MaximumFileSize = 100; // Limit file size to 100MB max
    TraceProperties->BufferSize = 512; // Use 512KB trace buffers
    TraceProperties->MinimumBuffers = 8;
    TraceProperties->MaximumBuffers = 64;

    Status = StartTraceW(&SessionHandle, LoggerName, TraceProperties);
    if (Status != ERROR_SUCCESS) {
        printf("StartTrace() failed with %lu\n", Status);
        goto Exit;
    }

    TraceStarted = TRUE;

    //
    // Enable the provider to a trace session with filtering enabled on the
    // provider
    //
    ZeroMemory(&EnableParameters, sizeof(EnableParameters));
    EnableParameters.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
    EnableParameters.EnableFilterDesc = &FilterDescriptor;
    EnableParameters.FilterDescCount = 1;

    Status = EnableTraceEx2(
        SessionHandle,
        &EXAMPLE_PROVIDER,
        EVENT_CONTROL_CODE_ENABLE_PROVIDER,
        TRACE_LEVEL_VERBOSE,
        0,
        0,
        0,
        &EnableParameters);
    if (Status != ERROR_SUCCESS) {
        printf("EnableTraceEx2() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Clean up the payload descriptor
    //
    Status = TdhCleanupPayloadEventFilterDescriptor(&FilterDescriptor);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCleanupPayloadEventFilterDescriptor() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Collect trace for 30 seconds
    //
    Sleep(30 * 1000);

Exit:

    //
    // Stop tracing.
    //
    if (TraceStarted != FALSE) {
        Status = ControlTraceW(SessionHandle, NULL, TraceProperties, EVENT_TRACE_CONTROL_STOP);
        if (Status != ERROR_SUCCESS) {
            printf("StopTrace() failed with %lu\n", Status);
        }
    }

    if (TraceProperties != NULL) {
        FreeTraceProperties(TraceProperties);
    }

    TdhUnloadManifest((PWSTR)PATH_TO_MANIFEST_FILE);

    return Status;
}

要求

要求 价值
最低支持的客户端 Windows 7 [桌面应用 |UWP 应用]
支持的最低服务器 Windows Server 2008 R2 [桌面应用 |UWP 应用]
目标平台 窗户
标头 evntrace.h
Windows 8.1 和 Windows Server 2012 R2 上的 Sechost.lib;Windows 8、Windows Server 2012、Windows 7 和 Windows Server 2008 R2 上的 Advapi32.lib
DLL Windows 8.1 和 Windows Server 2012 R2 上的 Sechost.dll;Windows 8、Windows Server 2012、Windows 7 和 Windows Server 2008 R2 上的 Advapi32.dll

另请参阅

StartTrace

ControlTrace

EnableCallback

ENABLE_TRACE_PARAMETERS

EVENT_FILTER_DESCRIPTOR