0

I have written a programme that reads Windows ETW data from an ETL file produced by the netsh trace utility. I'm using standard Windows Event Tracing libraries to do this which require that I do some initial setup work, register a callback function (using PEVENT_RECORD_CALLBACK) and then call a function called ProcessTrace(...).

This worked fine as static functions but, for a few reasons, I needed to move the code into a netsh reader class (NetshReader). I'm having problems defining the callback function. If I run the example code below I get an Access Violation as soon as the ProcessTrace(...) function is called.

I suspect the problem is that the callback function must be static, but I thought I would check with wiser heads.

Can I define the ProcessTrace(...) callback as a member function?

Thanks in advance...Paul

#pragma once

#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <evntrace.h>
#include <tdh.h>

#pragma comment(lib, "tdh.lib")

using namespace std;

class NetshReader
{
public:
    void processNetshTrace();
    void WINAPI processFirstPass(PEVENT_RECORD pEvent);
};

void WINAPI NetshReader::processFirstPass(PEVENT_RECORD pEvent)
{
    std::wcout << "In callback function" << std::endl;
}

void NetshReader::processNetshTrace()
{
    std::wstring stemp = L"C:\\traces\\a7-netsh.etl";

    EVENT_TRACE_LOGFILE trace;
    TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;
    TRACEHANDLE g_hTrace = 0;  // Handle to the trace file that you opened.

    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));

    trace.LogFileName = &stemp[0];

    trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK)(&NetshReader::processFirstPass, this);

    trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;

    g_hTrace = OpenTrace(&trace);

    if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)
        std::wcout << "OpenTrace failed" << std::endl;

    ProcessTrace(&g_hTrace, 1, 0, 0); // <<=== Access violation here because tries to
                                      //       callback to NetshReader object address
                                      //       (i.e. "this")
}

int wmain(int argc, wchar_t** argv)
{
    NetshReader* rdr = new NetshReader();
    rdr->processNetshTrace();

    return(0);
}

The ETL file I have been using for testing is here: https://a7pub.s3-eu-west-1.amazonaws.com/a7-netsh.etl

Paul Offord
  • 127
  • 12
  • Hi 1201ProgramAlarm, I'm disappointed that you've closed this as a duplicate. I've read the post you have referred to numerous times but there are two crucial differences with my question: a) The caller is Windows library code over which I have no control, and b) I believe that the WINAPI specification means that the function must be exposed as a linkable entry point. Neither of these aspects are dealt with in the post. If they are, I don't have the knowledge to understand how the post relates to my question. – Paul Offord Feb 01 '20 at 17:08
  • Just to answer my own question, I'm fairly convinced that there isn't a way to specify member functions for the ```PEVENT_RECORD_CALLBACK``` call. I solved the problem by making ```rdr``` and global variable and introducing a static callback wrapper function like this: ```void cbFirstPass(PEVENT_RECORD pEvent) { rdr->processFirstPass(pEvent); }``` I then changed the callback specification to this: ```trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) cbFirstPass``` – Paul Offord Feb 02 '20 at 14:31

0 Answers0