You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中ETW跟踪会话启动失败(错误码87)及事件打印求助

错误:无法在C++中启动ETW跟踪会话(错误码87)

开发C++应用时,使用Event Tracing for Windows (ETW)实时消费并打印事件,启动跟踪和注册提供程序时遇到以下错误:

unable to start trace 87
unable to register provider 87

错误码87对应ERROR_INVALID_PARAMETER,以下是问题代码片段:

#pragma once
#include <windows.h>
#include <evntrace.h>
#include <evntcons.h>
#include <iostream>
#include <thread>



class EventProvider
{
private:
    TRACEHANDLE sessionhandle;
    TRACEHANDLE consumertrace;
    GUID eventprovider;
    LPCWSTR sessionname;
    PEVENT_TRACE_PROPERTIES properties;
    bool running;
public:
    EventProvider(LPCWSTR, GUID);
    void initProperty();
    void startTrace();
    void consumer();
    static void run(PTRACEHANDLE);
    static VOID WINAPI eventcallback(PEVENT_RECORD);
    ~EventProvider();
};

EventProvider::EventProvider(LPCWSTR sessionname, GUID provider)
    : sessionhandle(0), consumertrace(0), eventprovider(provider), sessionname(sessionname), properties(nullptr), running(false)
{
    this->initProperty();
    this->startTrace();
    this->consumer();
}

void EventProvider::initProperty() {
    ULONG buffsize = sizeof(EVENT_TRACE_PROPERTIES) + 2 * sizeof(WCHAR) * 1024;
    this->properties = (EVENT_TRACE_PROPERTIES*)malloc(buffsize);
    if (this->properties == NULL) {
        std::cout << "Unable to allocate bytes for properties" << std::endl;
    }
    ZeroMemory(this->properties, buffsize);
    this->properties->Wnode.BufferSize = buffsize;
    this->properties->Wnode.Guid = this->eventprovider;
    this->properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    this->properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
    this->properties->Wnode.ClientContext = 1;
    this->properties->LogFileNameOffset = 0;
    this->properties->EnableFlags = EVENT_TRACE_FLAG_PROCESS;
    this->properties->BufferSize = 64;        // Size of each tracing buffer in KB
    this->properties->MinimumBuffers = 1;
    this->properties->MaximumBuffers = 5;
    this->properties->MaximumFileSize = 0;

}
VOID WINAPI EventProvider::eventcallback(PEVENT_RECORD pevent) {
    std::cout << "i have bbencalled" << std::endl;
}
void EventProvider::startTrace() {
    DWORD status = StartTraceW((PTRACEHANDLE)sessionhandle, sessionname, properties);
    if (status != ERROR_SUCCESS) {
        std::cout << "unable to start trace " << GetLastError() << std::endl;
    }

    DWORD status2 = EnableTraceEx2(this->sessionhandle, &this->eventprovider, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, 0, 0, 0, NULL);
    if (status != ERROR_SUCCESS) {
        std::cout << "unable to register provider " << GetLastError() << std::endl;
    }
}
void EventProvider::run(PTRACEHANDLE handel) {
    if (ProcessTrace(handel, 1, 0, 0) != ERROR_SUCCESS) {
        exit(0);
    }
}
void EventProvider::consumer() {
    EVENT_TRACE_LOGFILEW trace;
    TRACE_LOGFILE_HEADER* pheader = &trace.LogfileHeader;
    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILEW));
    trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
    trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK)(EventProvider::eventcallback);
    trace.LoggerName = (LPWSTR)R"(ANTI TRACER)";
    TRACEHANDLE handle = OpenTraceW((PEVENT_TRACE_LOGFILEW)&trace);
    if (handle == INVALID_PROCESSTRACE_HANDLE) {
        std::cout << "Unable start trace session : " << GetLastError() << std::endl;
    }
    consumertrace = (TRACEHANDLE)handle;
    std::thread thread(run, (PTRACEHANDLE)consumertrace);

}

问题定位与修复方案

以下是导致错误码87的核心问题及修复:

  • StartTraceW参数错误:第一个参数需要传入TRACEHANDLE*类型(用于接收会话句柄),原代码直接将初始值为0的sessionhandle强制转换为指针,参数无效。应改为传入&sessionhandle。
  • EVENT_TRACE_PROPERTIES的GUID设置错误:跟踪会话的Wnode.Guid必须设置为SystemTraceControlGuid,目标提供程序的GUID仅在EnableTraceEx2中指定,原代码错误将提供程序GUID赋值给会话。
  • EnableTraceEx2错误判断逻辑错误:原代码用StartTraceW的返回值status判断EnableTraceEx2的结果,应改为判断status2。
  • 消费端会话名不匹配:启动会话时使用构造函数传入的sessionname,但消费时硬编码了R"(ANTI TRACER)",需保持名称一致。
  • ProcessTrace参数错误:第一个参数是TRACEHANDLE数组的指针,原代码传入单个句柄指针,需改为传入包含句柄的数组地址。
  • 线程生命周期问题:消费线程是局部变量,会立即销毁,需用成员变量保存线程对象,并在析构时正确回收。

修复后的完整代码:

#pragma once
#include <windows.h>
#include <evntrace.h>
#include <evntcons.h>
#include <iostream>
#include <thread>

class EventProvider
{
private:
    TRACEHANDLE sessionhandle;
    TRACEHANDLE consumertrace;
    GUID eventprovider;
    LPCWSTR sessionname;
    PEVENT_TRACE_PROPERTIES properties;
    bool running;
    std::thread consumerThread; // 保存消费线程
public:
    EventProvider(LPCWSTR, GUID);
    void initProperty();
    void startTrace();
    void consumer();
    static void run(TRACEHANDLE*);
    static VOID WINAPI eventcallback(PEVENT_RECORD);
    ~EventProvider();
};

EventProvider::EventProvider(LPCWSTR sessionname, GUID provider)
    : sessionhandle(0), consumertrace(INVALID_PROCESSTRACE_HANDLE), eventprovider(provider), sessionname(sessionname), properties(nullptr), running(false)
{
    this->initProperty();
    this->startTrace();
    this->consumer();
}

void EventProvider::initProperty() {
    ULONG buffsize = sizeof(EVENT_TRACE_PROPERTIES) + 2 * sizeof(WCHAR) * 1024;
    this->properties = (EVENT_TRACE_PROPERTIES*)malloc(buffsize);
    if (this->properties == NULL) {
        std::cout << "Unable to allocate bytes for properties" << std::endl;
        return;
    }
    ZeroMemory(this->properties, buffsize);
    this->properties->Wnode.BufferSize = buffsize;
    this->properties->Wnode.Guid = SystemTraceControlGuid; // 修正会话GUID
    this->properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    this->properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
    this->properties->Wnode.ClientContext = 1;
    this->properties->LogFileNameOffset = 0;
    this->properties->EnableFlags = EVENT_TRACE_FLAG_PROCESS;
    this->properties->BufferSize = 64;
    this->properties->MinimumBuffers = 1;
    this->properties->MaximumBuffers = 5;
    this->properties->MaximumFileSize = 0;
}

VOID WINAPI EventProvider::eventcallback(PEVENT_RECORD pevent) {
    std::cout << "事件已触发" << std::endl;
}

void EventProvider::startTrace() {
    DWORD status = StartTraceW(&sessionhandle, sessionname, properties); // 传入句柄指针
    if (status != ERROR_SUCCESS) {
        std::cout << "unable to start trace " << status << std::endl;
        return;
    }

    DWORD status2 = EnableTraceEx2(this->sessionhandle, &this->eventprovider, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, 0, 0, 0, NULL);
    if (status2 != ERROR_SUCCESS) { // 修正判断条件
        std::cout << "unable to register provider " << status2 << std::endl;
    }
}

void EventProvider::run(TRACEHANDLE* handles) {
    if (ProcessTrace(handles, 1, NULL, NULL) != ERROR_SUCCESS) {
        std::cout << "ProcessTrace failed: " << GetLastError() << std::endl;
    }
}

void EventProvider::consumer() {
    EVENT_TRACE_LOGFILEW trace;
    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILEW));
    trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
    trace.EventRecordCallback = EventProvider::eventcallback;
    trace.LoggerName = const_cast<LPWSTR>(sessionname); // 使用一致的会话名
    
    TRACEHANDLE handle = OpenTraceW(&trace);
    if (handle == INVALID_PROCESSTRACE_HANDLE) {
        std::cout << "Unable start trace session : " << GetLastError() << std::endl;
        return;
    }
    consumertrace = handle;
    TRACEHANDLE handles[] = {consumertrace};
    consumerThread = std::thread(run, handles); // 保存线程对象
}

EventProvider::~EventProvider() {
    // 清理资源
    if (consumertrace != INVALID_PROCESSTRACE_HANDLE) {
        CloseTrace(consumertrace);
    }
    if (sessionhandle != 0) {
        ControlTraceW(sessionhandle, sessionname, properties, EVENT_TRACE_CONTROL_STOP);
    }
    if (properties != nullptr) {
        free(properties);
    }
    if (consumerThread.joinable()) {
        consumerThread.join();
    }
}

内容的提问来源于stack exchange,提问作者90_Priyanshu kumar Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:25:53