0

I am trying to use the EvtSubscribe function in the winevt.h header provided in the Windows C++ API.

Currently, my call to EvtSubscibe looks like this:

EvtSubscribeData data;
hResults = EvtSubscribe(
   NULL, NULL, L"Security", L"Event/System[EventID=4624]", NULL, reinterpret_cast<void *>(&data), (EVT_SUBSCRIBE_CALLBACK)callback, EvtSubscribeStartAtOldestRecord
);

EvtSubscribeData is a class that has a function called subscribe and my callback function looks like this:

DWORD callback(EVT_SUBSCRIBE_NOTIFY_ACTION Action, PVOID UserContext,EVT_HANDLE Event) {
  return reinterpret_cast<EvtSubscribeData *>(UserContext)->subscribe(Action, Event);
}

As you can tell, I am using the Context parameter which allows me to use the data returned in the callback to populate the EvtSubscribeData class member variables.

The only problem is that one data point is returned, then the program stops. The EVT_SUBSCRIBE_CALLBACK function says that the subscribe function is blocking, so my first thought was that callback was never returning, but after debugging, callback is returning 0, which is correctly being returned from EvtSubscribeData::subscribe.

When I remove the Context argument and use EvtSubscribeData::subscribe as a function instead of a member function (like in the examples shown here) everything works as it should with hundreds of events being printed.

A barebones EvtSubscribeData function:

class EvtSubscribeData {
 public:
  EvtSubscribeData() {}
  DWORD WINAPI subscribe(EVT_SUBSCRIBE_NOTIFY_ACTION action, EVT_HANDLE event) {
    auto status = ERROR_SUCCESS;
    switch (action) {
      case EvtSubscribeActionError:
        if (ERROR_EVT_QUERY_RESULT_STALE == (DWORD)event) {
          std::cout << "event records are missing" << std::endl;
        } else {
          std::cout << "win32 Error" << (DWORD)event << std::endl;
        }
        break;
      case EvtSubscribeActionDeliver:
        status = PrintEvent(event);
        break;
    }
    return status;
  }
};
  • 1
    use exactly how you begin use it. you can pass pointer to instance of self class here – RbMm Jan 07 '19 at 17:37
  • @RbMm I know that, I'm having a problem with how to use the Context argument in relation to how it affects the EvtSubscribe EvtNext, since I'm only getting one event before the program stops. – Maxwell Harley Jan 07 '19 at 18:14
  • the value of `UserContext` not affect system call. system not interpret it, simply pass you back. your problem not in this – RbMm Jan 07 '19 at 20:36
  • @MaxwellHarley you misunderstand how things work. Your `callback()` does not block `EvtSubscribe()`, it returns as soon as your subscription is active, and then `callback()` will be called in the background for all current *and future* events that match your criteria. So make sure that your `data` object stays alive for the lifetime of the subscription (until you call `EvtClose()`). What the documentation is referring to when it takes about blocking is that when your `callback()` receives an event, you will not receive another event until `callback()` exits, not that it blocks `EvtSubscribe()` – Remy Lebeau Jan 07 '19 at 22:05
  • @MaxwellHarley you should not be calling `EvtNext()` at all when using `callback()`. You only need to use `EvtNext()` when you poll events manually instead of using a callback. – Remy Lebeau Jan 07 '19 at 22:07

1 Answers1

0

The only problem is that one data point is returned, then the program stops.

Add WINAPI to your callback function to see if it works. Without WINAPI keyword it results in an "Access violation reading" exception (not "that the subscribe function is blocking" of yours.)

The callback will like this:

DWORD WINAPI callback(EVT_SUBSCRIBE_NOTIFY_ACTION Action, PVOID UserContext, EVT_HANDLE Event) {
    return reinterpret_cast<EvtSubscribeData *>(UserContext)->subscribe(Action, Event);
}

It works for me.

More reference: "What does “WINAPI” in main function mean?"

Rita Han
  • 9,574
  • 1
  • 11
  • 24