DOTA 2 gifts
I have 2 DOTA 2 gifts. Probably you can ask me by email, probably someone will definitely get it. Go, gentlemen.
I have 2 DOTA 2 gifts. Probably you can ask me by email, probably someone will definitely get it. Go, gentlemen.
Short howto for real time Event Tracing for Windows.
#pragma once struct ITraceConsumer; class TraceSession { public: TraceSession(LPCTSTR szSessionName); ~TraceSession(); public: bool Start(); bool EnableProvider(const GUID& providerId, UCHAR level, ULONGLONG anyKeyword = 0, ULONGLONG allKeyword = 0); bool OpenTrace(ITraceConsumer *pConsumer); bool Process(); bool CloseTrace(); bool DisableProvider(const GUID& providerId); bool Stop(); ULONG Status() const; LONGLONG PerfFreq() const; private: LPTSTR _szSessionName; ULONG _status; EVENT_TRACE_PROPERTIES* _pSessionProperties; TRACEHANDLE hSession; EVENT_TRACE_LOGFILE _logFile; TRACEHANDLE _hTrace; };
Initialization and cleanup:
TraceSession::TraceSession(LPCTSTR szSessionName) : _szSessionName(_tcsdup(szSessionName)) { } TraceSession::~TraceSession(void) { delete []_szSessionName; delete _pSessionProperties; }
First step - lets start trace session:
bool TraceSession::Start() { if (!_pSessionProperties) { const size_t buffSize = sizeof(EVENT_TRACE_PROPERTIES) + (_tcslen(_szSessionName) + 1) * sizeof(TCHAR); _pSessionProperties = reinterpret_cast<EVENT_TRACE_PROPERTIES *>(malloc(buffSize)); ZeroMemory(_pSessionProperties, buffSize); _pSessionProperties->Wnode.BufferSize = buffSize; _pSessionProperties->Wnode.ClientContext = 1; _pSessionProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; _pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); } // Create the trace session. _status = StartTrace(&hSession, _szSessionName, _pSessionProperties); return (_status == ERROR_SUCCESS); }
Then lets enable a provider with some filters:
bool TraceSession::EnableProvider(const GUID& providerId, UCHAR level, ULONGLONG anyKeyword, ULONGLONG allKeyword) { _status = EnableTraceEx2(hSession, &providerId, EVENT_CONTROL_CODE_ENABLE_PROVIDER, level, anyKeyword, allKeyword, 0, NULL); return (_status == ERROR_SUCCESS); }
BTW, you can have useful ETW metadata generated by mc.exe
utility,
just find your specific man
manifest file for your ETW provider.
Now we open the trace:
bool TraceSession::OpenTrace(ITraceConsumer *pConsumer) { if (!pConsumer) return false; ZeroMemory(&_logFile, sizeof(EVENT_TRACE_LOGFILE)); _logFile.LoggerName = _szSessionName; _logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; _logFile.EventRecordCallback = &EventRecordCallback; _logFile.Context = pConsumer; _hTrace = ::OpenTrace(&_logFile); return (_hTrace != 0); }
EventRecordCallback
looks like this:
namespace { VOID WINAPI EventRecordCallback(_In_ PEVENT_RECORD pEventRecord) { reinterpret_cast<ITraceConsumer *>(pEventRecord->UserContext)->OnEventRecord(pEventRecord); } }
But this is just for convenience and OOP, you can have just static function. Up to you.
Finally, call the following method:
bool TraceSession::Process() { _status = ProcessTrace(&_hTrace, 1, NULL, NULL); return (_status == ERROR_SUCCESS); }
Ensure you are running under elevated privileges.
When you decide its over - close the trace, disable any providers and stop the session:
bool TraceSession::CloseTrace() { _status = ::CloseTrace(_hTrace); return (_status == ERROR_SUCCESS); } bool TraceSession::DisableProvider(const GUID& providerId) { _status = EnableTraceEx2(hSession, &providerId, EVENT_CONTROL_CODE_DISABLE_PROVIDER, 0, 0, 0, 0, NULL); return (_status == ERROR_SUCCESS); } bool TraceSession::Stop() { _status = ControlTrace(hSession, _szSessionName, _pSessionProperties, EVENT_TRACE_CONTROL_STOP); delete _pSessionProperties; _pSessionProperties = NULL; return (_status == ERROR_SUCCESS); }
Some useful stuff:
ULONG TraceSession::Status() const { return _status; } LONGLONG TraceSession::PerfFreq() const { return _logFile.LogfileHeader.PerfFreq.QuadPart; }
Remember: sessions are global, not tied to your executable. So be sure to write something like this:
if (!traceSession.Start()) { if (traceSession.Status() == ERROR_ALREADY_EXISTS) { if (!traceSession.Stop() || !traceSession.Start()) { // Handle an error } } }
Well, thats it.