diff --git a/include/WinStd/Common.h b/include/WinStd/Common.h index eb3b28cb..b718e47e 100644 --- a/include/WinStd/Common.h +++ b/include/WinStd/Common.h @@ -368,7 +368,7 @@ namespace winstd /// handle& operator=(_Inout_ handle &&h) { - if (this != &h) { + if (this != std::addressof(h)) { // Transfer handle. if (m_h) free_internal(); diff --git a/include/WinStd/ETW.h b/include/WinStd/ETW.h index d050d660..d286a228 100644 --- a/include/WinStd/ETW.h +++ b/include/WinStd/ETW.h @@ -20,10 +20,12 @@ #include "Common.h" +#include #include #include #include +#include #include #include @@ -31,6 +33,8 @@ namespace winstd { class WINSTD_API event_data; class WINSTD_API event_provider; + class WINSTD_API event_session; + class WINSTD_API event_trace; class event_fn_auto; template class event_fn_auto_ret; @@ -38,8 +42,6 @@ namespace winstd #pragma once -#include - namespace winstd { @@ -292,6 +294,209 @@ namespace winstd }; + /// + /// ETW session + /// + class WINSTD_API event_session : public handle + { + public: + /// + /// Initializes a new empty session. + /// + inline event_session() + { + } + + /// + /// Initializes a new session with an already available object handle. + /// + /// \param[in] h Initial session handle value + /// \param[in] prop Session properties + /// + inline event_session(_In_opt_ handle_type h, _In_ const EVENT_TRACE_PROPERTIES *prop) : + m_prop((EVENT_TRACE_PROPERTIES*)new char[prop->Wnode.BufferSize]), + handle(h) + { + memcpy(m_prop.get(), prop, prop->Wnode.BufferSize); + } + + /// + /// Move constructor + /// + /// \param[inout] other A rvalue reference of another session + /// + inline event_session(_Inout_ event_session &&other) : + m_prop(std::move(other.m_prop)), + handle(std::move(other)) + { + } + + + /// + /// Closes the session. + /// + /// \sa [ControlTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696.aspx) + /// + virtual ~event_session(); + + + /// + /// Move assignment + /// + /// \param[inout] other A rvalue reference of another session + /// + inline event_session& operator=(_Inout_ event_session &&other) + { + if (this != std::addressof(other)) { + (handle&&)*this = std::move(other); + m_prop = std::move(other.m_prop); + } + return *this; + } + + + /// + /// Sets a new session handle for the class + /// + /// When the current session handle of the class is non-NULL, the session is destroyed first. + /// + /// \param[in] h New session handle + /// \param[in] prop Session properties + /// + inline void attach(_In_opt_ handle_type h, _In_ EVENT_TRACE_PROPERTIES *prop) + { + handle::attach(h); + m_prop.reset(prop); + } + + + /// + /// Registers and starts an event tracing session. + /// + /// \return + /// - `ERROR_SUCCESS` when creation succeeds; + /// - error code otherwise. + /// + /// \sa [StartTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364117.aspx) + /// + inline ULONG create(_In_ LPCTSTR SessionName, _In_ const EVENT_TRACE_PROPERTIES *Properties) + { + handle_type h; + std::unique_ptr prop((EVENT_TRACE_PROPERTIES*)new char[Properties->Wnode.BufferSize]); + memcpy(prop.get(), Properties, Properties->Wnode.BufferSize); + ULONG ulRes = StartTrace(&h, SessionName, prop.get()); + if (ulRes == ERROR_SUCCESS) + attach(h, prop.release()); + return ulRes; + } + + + /// + /// Enables the specified event trace provider. + /// + /// \return + /// - `ERROR_SUCCESS` when succeeds; + /// - error code otherwise. + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline ULONG enable_trace(_In_ LPCGUID ProviderId, _In_ UCHAR Level, _In_opt_ ULONGLONG MatchAnyKeyword = 0, _In_opt_ ULONGLONG MatchAllKeyword = 0, _In_opt_ ULONG EnableProperty = 0, _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) + { + assert(m_h); + return EnableTraceEx( + ProviderId, + &m_prop->Wnode.Guid, + m_h, + EVENT_CONTROL_CODE_ENABLE_PROVIDER, + Level, + MatchAnyKeyword, + MatchAllKeyword, + EnableProperty, + EnableFilterDesc); + } + + + /// + /// Disables the specified event trace provider. + /// + /// \return + /// - `ERROR_SUCCESS` when succeeds; + /// - error code otherwise. + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline ULONG disable_trace(_In_ LPCGUID ProviderId, _In_ UCHAR Level, _In_opt_ ULONGLONG MatchAnyKeyword = 0, _In_opt_ ULONGLONG MatchAllKeyword = 0, _In_opt_ ULONG EnableProperty = 0, _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) + { + assert(m_h); + return EnableTraceEx( + ProviderId, + &m_prop->Wnode.Guid, + m_h, + EVENT_CONTROL_CODE_DISABLE_PROVIDER, + Level, + MatchAnyKeyword, + MatchAllKeyword, + EnableProperty, + EnableFilterDesc); + } + + + protected: + /// + /// Releases the session. + /// + /// \sa [ControlTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696.aspx) + /// + virtual void free_internal(); + + protected: + std::unique_ptr m_prop; ///< Session properties + }; + + + /// + /// ETW trace + /// + class WINSTD_API event_trace : public handle + { + public: + /// + /// Closes the trace. + /// + /// \sa [CloseTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363686.aspx) + /// + virtual ~event_trace(); + + + /// + /// Opens a real-time trace session or log file for consuming. + /// + /// \return + /// - `ERROR_SUCCESS` when creation succeeds; + /// - error code otherwise. + /// + /// \sa [OpenTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364089.aspx) + /// + inline bool create(_Inout_ PEVENT_TRACE_LOGFILE Logfile) + { + handle_type h = OpenTrace(Logfile); + if (h != (TRACEHANDLE)INVALID_HANDLE_VALUE) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Closes the trace. + /// + /// \sa [CloseTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363686.aspx) + /// + virtual void free_internal(); + }; + + /// /// Helper class to write an event on entry/exit of scope. /// diff --git a/src/ETW.cpp b/src/ETW.cpp index 120b0541..00a34147 100644 --- a/src/ETW.cpp +++ b/src/ETW.cpp @@ -66,4 +66,41 @@ VOID NTAPI winstd::event_provider::enable_callback(_In_ LPCGUID SourceId, _In_ U assert(0); // Where did the "this" pointer get lost? } + +////////////////////////////////////////////////////////////////////// +// winstd::event_session +////////////////////////////////////////////////////////////////////// + +winstd::event_session::~event_session() +{ + if (m_h) { + EVENT_TRACE_PROPERTIES *prop = m_prop.get(); + ControlTrace(m_h, (LPCTSTR)((const char*)prop + prop->LoggerNameOffset), prop, EVENT_TRACE_CONTROL_STOP); + } +} + + +void winstd::event_session::free_internal() +{ + EVENT_TRACE_PROPERTIES *prop = m_prop.get(); + ControlTrace(m_h, (LPCTSTR)((const char*)prop + prop->LoggerNameOffset), prop, EVENT_TRACE_CONTROL_STOP); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::event_trace +////////////////////////////////////////////////////////////////////// + +winstd::event_trace::~event_trace() +{ + if (m_h) + CloseTrace(m_h); +} + + +void winstd::event_trace::free_internal() +{ + CloseTrace(m_h); +} + #endif