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.