//---------------------------------------------------------------------------------------------------------------------- /// \file /// Waiter classes for Etw events. // Copyright (c) Microsoft Corporation. All Rights Reserved. //---------------------------------------------------------------------------------------------------------------------- #pragma once #include "EtwProcessor.h" #include // Forward define VARIANT struct typedef struct tagVARIANT VARIANT; typedef struct _EVENT_RECORD EVENT_RECORD; /// \namespace Etw::Processor /// /// The Etw::Processor namespace contains Etw waiter class declarations. /// namespace Etw { namespace Processor { /// /// Base class for all Waiter classes. /// class Waiter { friend class CachingWaiter; friend class EtwWaiter; friend class MultiplicityWaiter; friend class WaiterCollection; public: ETWPROCESSOR_API virtual ~Waiter(); Waiter(Waiter&& other) noexcept : m_pImpl{other.m_pImpl} , m_status{other.m_status} { other.m_pImpl = nullptr; } Waiter(const Waiter& other) { CopyFrom(other); } ETWPROCESSOR_API Waiter& operator=(Waiter other); /// Method that blocks the current thread until the required event is received /// Time in milliseconds to wait for /// S_OK if received the event. HRESULT_FROM_WIN32(WAIT_TIMEOUT) on timeout. ETWPROCESSOR_API virtual HRESULT Wait(unsigned int timeout); virtual HRESULT Wait() { // We would use a default argument for this, but Wait with no parameters exists as a virtual method; // so removing this overload could break users that override this method. return Wait(c_defaultTimeout); } /// Method to reset the current waiter ETWPROCESSOR_API virtual void Reset(); HRESULT GetStatus() const { return m_status; } /// Method to retrieve the message associated with the last error that modified the error code returned /// from GetStatus. ETWPROCESSOR_API const unsigned short* GetLastErrorMessage() const; protected: Waiter() = default; void CommonInitialize(const Waiter& waiter); struct Impl; Impl* m_pImpl = nullptr; HRESULT m_status = S_OK; // hr stored if any exception encountered static const unsigned int c_defaultTimeout = 5000; // 5 seconds private: ETWPROCESSOR_API void CopyFrom(const Waiter& other); }; /// /// Struct to encapsulate options for customizing how to set up an EtwWaiter /// struct EtwWaiterOptions { static const unsigned long c_currentVersion = 1; /// Version number of the struct unsigned long Version = c_currentVersion; /// How long to wait before flushing ETW events unsigned long FlushTimerInMs = 500; explicit EtwWaiterOptions(unsigned long flushTimerInMs = 500) : FlushTimerInMs(flushTimerInMs) { } }; /// /// Light weight waiter to wait for an Etw event /// class EtwWaiter : public Waiter { public: /// Construct an EtwWaiter /// Guid of the provider that raises events /// Event Identifier EtwWaiter(GUID providerGuid, unsigned long eventId) { Initialize(providerGuid, eventId, L"", EtwWaiterOptions()); } /// Construct an EtwWaiter /// Guid of the provider that raises events /// Event Identifier /// String representing payload to filter the event EtwWaiter(GUID providerGuid, unsigned long eventId, const wchar_t* pszPayloadCriteria) { Initialize(providerGuid, eventId, pszPayloadCriteria, EtwWaiterOptions()); } /// Construct an EtwWaiter /// Guid of the provider that raises events /// Event Identifier /// Options on ETW trace session EtwWaiter(GUID providerGuid, unsigned long eventId, const EtwWaiterOptions& options) { Initialize(providerGuid, eventId, L"", options); } /// Construct an EtwWaiter /// Guid of the provider that raises events /// Event Identifier /// String representing payload to filter the event /// Options on ETW trace session EtwWaiter(GUID providerGuid, unsigned long eventId, const wchar_t* pszPayloadCriteria, const EtwWaiterOptions& options) { Initialize(providerGuid, eventId, pszPayloadCriteria, options); } /// Construct an EtwWaiter for a TraceLogging event /// Guid of the provider that raises events /// Task Name EtwWaiter(GUID providerGuid, const wchar_t* pszTaskName) { Initialize(providerGuid, pszTaskName, L"", EtwWaiterOptions()); } /// Construct an EtwWaiter for a TraceLogging event /// Guid of the provider that raises events /// Task Name /// String representing payload to filter the event EtwWaiter(GUID providerGuid, const wchar_t* pszTaskName, const wchar_t* pszPayloadCriteria) { Initialize(providerGuid, pszTaskName, pszPayloadCriteria, EtwWaiterOptions()); } /// Construct an EtwWaiter for a TraceLogging event /// Guid of the provider that raises events /// Task Name /// Options on ETW trace session EtwWaiter(GUID providerGuid, const wchar_t* pszTaskName, const EtwWaiterOptions& options) { Initialize(providerGuid, pszTaskName, L"", options); } /// Construct an EtwWaiter for a TraceLogging event /// Guid of the provider that raises events /// Task Name /// String representing payload to filter the event /// Options on ETW trace session EtwWaiter(GUID providerGuid, const wchar_t* pszTaskName, const wchar_t* pszPayloadCriteria, const EtwWaiterOptions& options) { Initialize(providerGuid, pszTaskName, pszPayloadCriteria, options); } ETWPROCESSOR_API ~EtwWaiter(); private: ETWPROCESSOR_API void Initialize(const GUID& providerGuid, unsigned long eventId, const wchar_t* pszPayloadCriteria, const EtwWaiterOptions& options); ETWPROCESSOR_API void Initialize(const GUID& providerGuid, const wchar_t* pszTaskName, const wchar_t* pszPayloadCriteria, const EtwWaiterOptions& options); #if defined(ETWPROCESSOR_FULL_BUILD) ETWPROCESSOR_API void Initialize(const GUID& providerGuid, unsigned long eventId, const unsigned short* pszPayloadCriteria, const EtwWaiterOptions& options); ETWPROCESSOR_API void Initialize(const GUID& providerGuid, const unsigned short* pszTaskName, const unsigned short* pszPayloadCriteria, const EtwWaiterOptions& options); #endif }; struct PayloadProperty; /// /// Class that represents an etw event /// class EtwEvent { friend class CachingWaiter; public: ETWPROCESSOR_API static EtwEvent __stdcall FromEventRecord(EVENT_RECORD* pEventRecord); ETWPROCESSOR_API ~EtwEvent(); ETWPROCESSOR_API EtwEvent(const EtwEvent& other); ETWPROCESSOR_API EtwEvent& operator=(EtwEvent other); HRESULT GetStatus() const { return m_status; } /// Method to retrieve the message associated with the last error that modified the error code returned /// from GetStatus. ETWPROCESSOR_API const unsigned short* GetLastErrorMessage() const; /// Method to get the event identifier ETWPROCESSOR_API unsigned long GetEventId() const; /// Method to get the event version ETWPROCESSOR_API unsigned char GetVersion() const; /// Method to get the event Channel ETWPROCESSOR_API unsigned char GetChannel() const; /// Method to get the event Level ETWPROCESSOR_API unsigned char GetLevel() const; /// Method to get the event OpCode ETWPROCESSOR_API unsigned char GetOpCode() const; /// Method to get the event thred Identifier ETWPROCESSOR_API unsigned long GetThreadId() const; /// Method to get the event Process Identifier ETWPROCESSOR_API unsigned long GetProcessId() const; /// Method to get the event provider Guid ETWPROCESSOR_API GUID GetProviderGuid() const; /// Method to get the event activity ID ETWPROCESSOR_API GUID GetActivityId() const; /// /// Method to get the event timestamp. Beware that the timestamp is calculated using the current machine's /// performance frequency. If this event is being read from a file, the timestamp may be inaccurate if the /// frequency was different when the trace was recorded. /// ETWPROCESSOR_API LARGE_INTEGER GetTimeStamp() const; /// Method to get the whether the event has a related (parent) activity ETWPROCESSOR_API bool HasRelatedActivity() const; /// Method to get the event related (parent) activity ID ETWPROCESSOR_API GUID GetRelatedActivityId() const; ETWPROCESSOR_API const unsigned short* GetProviderName() const; ETWPROCESSOR_API const unsigned short* GetLevelName() const; ETWPROCESSOR_API const unsigned short* GetChannelName() const; ETWPROCESSOR_API const unsigned short* GetKeywordsName() const; ETWPROCESSOR_API const unsigned short* GetTaskName() const; ETWPROCESSOR_API const unsigned short* GetOpCodeName() const; ETWPROCESSOR_API const unsigned short* GetEventMessage() const; ETWPROCESSOR_API const unsigned short* GetProviderMessage() const; /// Method that prints the event properties to the console ETWPROCESSOR_API void PrintProperties(); /// Method to retrieve payload property value of the event /// Name of the property to retrieve /// VARIANT structure that holds the value of the property ETWPROCESSOR_API HRESULT GetPayloadProperty(const wchar_t* pszPropertyName, VARIANT& variant) const; /// Method to retrieve the list of Payload Property names available into a buffer and count of avaialble properties; /// this function does not allocate memory. It is valid to call this with a null buffer with 0 length /// if you only want the property count. If buffer is provided but length is less than property count then /// ERROR_INSUFFICIENT_BUFFER will be returned /// The array buffer that will be filled with available payload property names /// The array buffer length that indicates max size of the buffer that will be filled to size of buffer /// or total of properties available (whichever is greater) /// Pointer that will be given the total count of properties this payload has available ETWPROCESSOR_API HRESULT GetPayloadPropertyNames(_Out_writes_to_opt_(length, *pLengthNeeded) LPCWSTR* ppszEventPropertyNames, const unsigned long length, _Out_ unsigned long* pLengthNeeded) const; #if defined(ETWPROCESSOR_FULL_BUILD) ETWPROCESSOR_API HRESULT GetPayloadProperty(const unsigned short* pszPropertyName, VARIANT& variant) const; ETWPROCESSOR_API HRESULT GetPayloadPropertyNames(_Out_writes_to_opt_(length, *pLengthNeeded) const unsigned short** ppEventPropertyList, const unsigned long length, _Out_ unsigned long* pLengthNeeded) const; #endif private: static HRESULT __stdcall EtwEvent_GetPayloadProperty(EtwEvent* pEtwEvent, const wchar_t* pszPropertyName, const PayloadProperty** ppValue); static HRESULT __stdcall EtwEvent_GetPayloadPropertyLegacy(EtwEvent* pEtwEvent, const wchar_t* pszPropertyName, VARIANT& variant); static HRESULT __stdcall EtwEvent_GetPayloadPropertyNames(EtwEvent *pEtwEvent, _Out_writes_to_opt_(length, *pLengthNeeded) LPCWSTR* ppszEventPropertyNames, const unsigned long length, _Out_ unsigned long* pLengthNeeded); EtwEvent(); struct Impl; Impl* m_pImpl = nullptr; HRESULT m_status = S_OK; }; /// /// Waiter that also caches the event that is waiting for /// class CachingWaiter : public Waiter { public: /// Constructor for CachingWaiter /// Waiter object CachingWaiter(const Waiter& waiter) { Initialize(waiter); } /// Constructor for CachingWaiter /// Waiter object /// String representing payload to filter the event CachingWaiter(const Waiter& waiter, const wchar_t* pszPayloadCriteria) { Initialize(waiter, pszPayloadCriteria); } ~CachingWaiter() {} /// Method to get the Cached event ETWPROCESSOR_API EtwEvent GetCachedEvent(); private: ETWPROCESSOR_API void Initialize(const Waiter& waiter); ETWPROCESSOR_API void Initialize(const Waiter& waiter, const wchar_t* pszPayloadCriteria); #if defined(ETWPROCESSOR_FULL_BUILD) ETWPROCESSOR_API void Initialize(const Waiter& waiter, const unsigned short* pszPayloadCriteria); #endif }; /// /// Class that represents a collection of Etw waiter classes /// class WaiterCollection { friend class CompositeWaiter; public: ETWPROCESSOR_API WaiterCollection(); ETWPROCESSOR_API ~WaiterCollection(); ETWPROCESSOR_API WaiterCollection(const WaiterCollection& other); ETWPROCESSOR_API WaiterCollection& operator=(WaiterCollection other); HRESULT GetStatus() const { return m_status; } /// Method to retrieve the message associated with the last error that modified the error code returned /// from GetStatus. ETWPROCESSOR_API const unsigned short* GetLastErrorMessage() const; /// Method to add a waiter to the collection /// Waiter object ETWPROCESSOR_API void Add(const Waiter& waiter); protected: struct Impl; Impl* m_pImpl = nullptr; HRESULT m_status = S_OK; }; /// /// Waiter to wait for multiple instances of a same event /// class MultiplicityWaiter : public Waiter { public: /// Constructor for MultiplicityWaiter /// Waiter object /// Number of instances of the Event MultiplicityWaiter(const Waiter& waiter, unsigned int instances) { Initialize(waiter, instances); } ~MultiplicityWaiter() {} private: ETWPROCESSOR_API void Initialize(const Waiter& waiter, unsigned int instances); }; enum class DefaultWaitBehavior { Any = 0, All }; /// /// Waiter to WaitForAny or WaitForAll events from multiple providers at the same time /// class CompositeWaiter : public Waiter { public: CompositeWaiter(const WaiterCollection& waiterCollection) { Initialize(waiterCollection, DefaultWaitBehavior::Any); } CompositeWaiter(const WaiterCollection& waiterCollection, DefaultWaitBehavior defaultWaitBehavior) { Initialize(waiterCollection, defaultWaitBehavior); } ~CompositeWaiter() {} ETWPROCESSOR_API HRESULT WaitAny(unsigned int timeout = c_defaultTimeout); ETWPROCESSOR_API HRESULT WaitAll(unsigned int timeout = c_defaultTimeout); private: ETWPROCESSOR_API void Initialize(const WaiterCollection& waiterCollection, DefaultWaitBehavior defaultWaitBehavior); }; }/* namespace Processor */}/* namespace Etw */