#pragma option push -b -a8 -pc -A- -w-pun /*P_O_Push*/
/* ++

Copyright (c) Microsoft Corporation.  All rights reserved.

Module Name:

    TraceLoggingActivity.h

Abstract:

    TraceLogging activity logging helper classes and macros for C++ for
    utilizing ETW activity ids.

Environment:

    User mode.

--*/

#pragma once
#ifndef RC_INVOKED

#include "TraceLoggingProvider.h"

/*
Quick start:

#include <windows.h>
#include <TraceLoggingProvider.h>
#include <TraceLoggingActivity.h>
#include <winmeta.h> // optional, used here for WINEVENT_LEVEL_ERROR

TRACELOGGING_DEFINE_PROVIDER(
    g_hProvider,
    "MyProvider",
    (0xb3864c38, 0x4273, 0x58c5, 0x54, 0x5b, 0x8b, 0x36, 0x08, 0x34, 0x34, 0x71));

int main(int argc, char* argv[])
{
    const ULONGLONG MyKeywordValue = 0x10;

    TraceLoggingRegister(g_hProvider);

    // Declare a local activity variable.
    // Use the default (0 = none) for the activity's keyword.
    // Use the default (5 = verbose) for the activity's level.
    TraceLoggingActivity<g_hProvider> parentActivity;

    // Write the activity's START event. Note that you must not specify keyword
    // or level for START and STOP events because they always use the activity's
    // keyword and level.
    TraceLoggingWriteStart(
        parentActivity,
        "ParentActivity", // The name of the start event is used as the activity name.
        TraceLoggingValue(argc, "SampleField1"));

    {
        // Declare a local (nested) activity variable, with explicit keyword and level:
        TraceLoggingActivity<g_hProvider, MyKeywordValue, WINEVENT_LEVEL_ERROR> nestedActivity;

        // Connect the nested activity to the parent:
        nestedActivity.SetRelatedActivity(parentActivity);

        // Write the activity's START event.
        TraceLoggingWriteStart(nestedActivity, "NestedActivity");

        // TraceLoggingWriteTagged writes an event that is tagged with an activity
        // ID. Note that TraceLoggingWriteTagged is just like TraceLoggingWrite
        // except that the first parameter is an activity (not a provider) and the
        // resulting event is explicitly tagged with the activity ID. In particular,
        // TraceLoggingWriteTagged does NOT use the activity's level and keyword --
        // they are specified just as they would be for a TraceLoggingWrite event.
        TraceLoggingWriteTagged(
            nestedActivity,
            "NestedActivityIdTaggedEvent",
            TraceLoggingValue(argc, "SampleField2"),
            TraceLoggingKeyword(MyKeywordValue));

        // Write the activity's STOP event.
        TraceLoggingWriteStop(nestedActivity, "NestedActivity");

        // Note that if the activity is destroyed without being stopped, a default
        // "ActivityStoppedAutomatically" event will be written by the destructor.
    }

    TraceLoggingWriteStop(parentActivity, "ParentActivity");

    TraceLoggingUnregister(g_hProvider);
    return 0;
}
*/

#pragma region Public Interface

/*
Classes:

- TraceLoggingActivity: General purpose activity class.
- TraceLoggingThreadActivity: Automatic activity class. (Desktop apps only.)
- TraceLoggingThreadActivityIdSetter: Helper for controlling the thread-local
  activity ID. (Desktop apps only.)

Macros:

- TraceLoggingWriteStart: Writes an activity START event.
- TraceLoggingWriteStop: Writes an activity STOP event.
- TraceLoggingWriteTagged: Writes an event explicitly tagged with an activity ID.
- TraceLoggingWriteTaggedIfStarted: TraceLoggingWriteTagged if the activity was
  started.
- TraceLoggingFunction: Creates a TraceLoggingThreadActivity and writes a START
  event with the current function's name. (Desktop apps only.)

Basic usage:

1. Create an instance of TraceLoggingActivity or TraceLoggingThreadActivity.
2. Call TraceLoggingWriteStart to write the activity's START event.
3. Call TraceLoggingWriteTagged to write events associated with the activity.
4. Call TraceLoggingWriteStop to write the activity's STOP event.
*/

/*
TraceLoggingActivity implements general-purpose activity support. It supports
nesting via an explicit childActivity.SetRelatedActivity(parentActivity) method.
Events associated with the activity can then be written using
TraceLoggingWriteTagged.

Activities can be nested by calling childActivity.SetRelatedActivity(parentActivity)
before calling TraceLoggingWriteStart(childActivity, ...).

Use TraceLoggingWriteStart to generate a unique activity ID and write the START
event for the activity.

Use TraceLoggingWriteTagged to write events that are associated with the activity.

Use TraceLoggingWriteStop to write the STOP event for the activity.

If the activity is destroyed without being stopped, it will log a default STOP
event.
*/
template<
    TraceLoggingHProvider const& provider,
    UINT64 keyword = 0, // defaults to 0 = none
    UINT8 level = 5, // defaults to 5 = WINEVENT_LEVEL_VERBOSE
    typename TlgReflectorTag = _TlgReflectorTag_Param0IsHProvider> // helps TlgReflector understand that this is a wrapper type
class TraceLoggingActivity;

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

/*
TraceLoggingThreadActivity implements automatic activities using a thread-local
CurrentActivityId variable. Each new activity is automatically nested within the
activity that previously set the CurrentActivityId variable, and all events
written using TraceLoggingWrite are automatically associated with the
CurrentActivityId. This automatic behavior can be convenient in some cases, but it
only works correctly when the activities nest precisely and do not cross thread
boundaries. In addition, TraceLoggingThreadActivity is not available on the
Windows Runtime (i.e. this class cannot be used for Windows Store or Windows Phone
apps).

PLEASE NOTE: use TraceLoggingThreadActivity only when you can guarantee that
lifetimes of all activities of this type on the thread fully nest in all cases, i.e.
a parent activity will not end before a child activity, even in error or exceptional
cases. Activities defined in function-local scopes typically meet this criteria.

Use TraceLoggingWriteStart to generate a unique activity ID and write the START
event for the activity.

Use TraceLoggingWrite to write events that are automatically associated with the
activity.

Use TraceLoggingWriteTagged to write events that are explicitly associated with the
activity.

Use TraceLoggingWriteStop to write the STOP event for the activity.

If the activity is destroyed without being stopped, it will log a default STOP
event.
*/
template<
    TraceLoggingHProvider const& provider,
    UINT64 keyword = 0, // defaults to 0 = none
    UINT8 level = 5, // defaults to 5 = WINEVENT_LEVEL_VERBOSE
    typename TlgReflectorTag = _TlgReflectorTag_Param0IsHProvider> // helps TlgReflector understand that this is a wrapper type
class TraceLoggingThreadActivity;

/*
TraceLoggingThreadActivityIdSetter is a helper class that sets the thread-local
CurrentActivity variable during construction and saves the original value. It then
restores the original value during destruction. This class is not available on the
Windows Runtime (i.e. it cannot be used for Windows Store or Windows Phone apps).

As with thread activities, lifetime of an instance of this class should
be carefully managed to avoid imperfect nesting.
*/
class TraceLoggingThreadActivityIdSetter;

#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

/*
Macro TraceLoggingWriteStart(activity, "EventName", args...):
Invoke this macro to start an activity and log the start event.

The event name must be a string literal (not a variable) and must not contain
any '\0' characters.

Each arg must be a wrapper macro such as TraceLoggingValue, TraceLoggingInt32,
etc.

Do not specify TraceLoggingKeyword or TraceLoggingLevel as args for this macro.
The START and STOP events always use the activity's keyword and level.
*/
#define TraceLoggingWriteStart(activity, name, ...) \
    __pragma(warning(push)) __pragma(warning(disable:4127)) \
    do { \
        _TlgActivityDecl(activity) \
        static const UINT64 _TlgActivity_Keyword = _TlgActivityRef(activity).Keyword;\
        static const UINT8 _TlgActivity_Level = _TlgActivityRef(activity).Level;\
        _TLG_CASSERT( \
            _TlgActivity_Keyword == (_TlgActivity_Keyword _TLG_FOREACH(_TlgKeywordVal, __VA_ARGS__)), \
            "Do not use TraceLoggingKeyword in TraceLoggingWriteStart. Keywords for START events are " \
            "specified in the activity type, e.g. TraceLoggingActivity<Provider,Keyword,Level>."); \
        _TLG_CASSERT( \
            _TlgActivity_Level == (_TlgActivity_Level _TLG_FOREACH(_TlgLevelVal, __VA_ARGS__)), \
            "Do not use TraceLoggingLevel in TraceLoggingWriteStart. The Level for START events is " \
            "specified in the activity type, e.g. TraceLoggingActivity<Provider,Keyword,Level>."); \
        _TlgActivityRef(activity).zInternalStart(); \
        TraceLoggingWriteActivity( \
            _TlgActivityRef(activity).Provider(), \
            (name), \
            _TlgActivityRef(activity).Id(), \
            _TlgActivityRef(activity).zInternalRelatedId(), \
            TraceLoggingOpcode(1 /* WINEVENT_OPCODE_START */), \
            TraceLoggingKeyword(_TlgActivity_Keyword), \
            TraceLoggingLevel(_TlgActivity_Level), \
            TraceLoggingDescription("~^" _TLG_PASTE(L, _TLG_STRINGIZE(activity)) L"^~"), \
            __VA_ARGS__); \
    } while(0) \
    __pragma(warning(pop)) \

/*
Macro TraceLoggingWriteStop(activity, "EventName", args...):
Invoke this macro to stop an activity and log the stop event.

The event name must be a string literal (not a variable) and must not contain
any '\0' characters.

Each arg must be a wrapper macro such as TraceLoggingValue, TraceLoggingInt32,
etc.

Do not specify TraceLoggingKeyword or TraceLoggingLevel as args for this macro.
The START and STOP events always use the activity's keyword and level.

If an activity is started and is destroyed before it is stopped, a default
event will be logged from the destructor.
*/
#define TraceLoggingWriteStop(activity, name, ...) \
    __pragma(warning(push)) __pragma(warning(disable:4127)) \
    do { \
        _TlgActivityDecl(activity) \
        static const UINT64 _TlgActivity_Keyword = _TlgActivityRef(activity).Keyword;\
        static const UINT8 _TlgActivity_Level = _TlgActivityRef(activity).Level;\
        _TLG_CASSERT( \
            _TlgActivity_Keyword == (_TlgActivity_Keyword _TLG_FOREACH(_TlgKeywordVal, __VA_ARGS__)), \
            "Do not use TraceLoggingKeyword in TraceLoggingWriteStop. Keywords for STOP events are " \
            "specified in the activity type, e.g. TraceLoggingActivity<Provider,Keyword,Level>."); \
        _TLG_CASSERT( \
            _TlgActivity_Level == (_TlgActivity_Level _TLG_FOREACH(_TlgLevelVal, __VA_ARGS__)), \
            "Do not use TraceLoggingLevel in TraceLoggingWriteStop. The Level for STOP events is " \
            "specified in the activity type, e.g. TraceLoggingActivity<Provider,Keyword,Level>."); \
        _TlgActivityRef(activity).zInternalStop(); \
        TraceLoggingWriteActivity( \
            _TlgActivityRef(activity).Provider(), \
            (name), \
            _TlgActivityRef(activity).Id(), \
            NULL, \
            TraceLoggingOpcode(2 /* WINEVENT_OPCODE_STOP */),\
            TraceLoggingKeyword(_TlgActivity_Keyword),\
            TraceLoggingLevel(_TlgActivity_Level),\
            TraceLoggingDescription("~^" _TLG_PASTE(L, _TLG_STRINGIZE(activity)) L"^~"),\
            __VA_ARGS__); \
    } while(0) \
    __pragma(warning(pop)) \

/*
Macro TraceLoggingWriteTagged(activity, "EventName", args...):
Invoke this macro to log an event that is explicitly tagged with the activity id
of the specified activity.

The event name must be a string literal (not a variable) and must not contain
any '\0' characters.

Each arg must be a wrapper macro such as TraceLoggingValue, TraceLoggingInt32,
etc.

Note that events written with this macro do NOT use the activity's keyword and
level. If the level is not specified via TraceLoggingLevel, the level will default
to verbose (5). If the keyword is not specified via TraceLoggingKeyword, the keyword
will default to none (0).
*/
#define TraceLoggingWriteTagged(activity, name, ...) \
    __pragma(warning(push)) __pragma(warning(disable:4127)) \
    do { \
        _TlgActivityDecl(activity) \
        TraceLoggingWriteActivity( \
            _TlgActivityRef(activity).Provider(), \
            (name), \
            _TlgActivityRef(activity).Id(), \
            NULL, \
            __VA_ARGS__); \
    } while(0) \
    __pragma(warning(pop)) \

/*
Macro TraceLoggingWriteTaggedIfStarted(activity, "EventName", args...):
Invoke this macro to log an event that is explicitly tagged with the activity id
of the specified activity. This macro logs the event only if the activity is
started.

The event name must be a string literal (not a variable) and must not contain
any '\0' characters.

Each arg must be a wrapper macro such as TraceLoggingValue, TraceLoggingInt32,
etc.

Note that events written with this macro do NOT use the activity's keyword and
level. If the level is not specified via TraceLoggingLevel, the level will default
to verbose (5). If the keyword is not specified via TraceLoggingKeyword, the keyword
will default to none (0).
*/
#define TraceLoggingWriteTaggedIfStarted(activity, name, ...) \
    __pragma(warning(push)) __pragma(warning(disable:4127)) \
    do { \
        _TlgActivityDecl(activity) \
        if (_TlgActivityRef(activity).IsStarted()) { \
        TraceLoggingWriteActivity( \
            _TlgActivityRef(activity).Provider(), \
            (name), \
            _TlgActivityRef(activity).Id(), \
            NULL, \
            __VA_ARGS__); \
        } \
    } while(0) \
    __pragma(warning(pop)) \

/*
Macro TraceLoggingFunction(hProvider, args...):
Invoke this macro at the beginning of a function to define an activity and
start it. This will log a start event with the name of the function. When
the function exits, the activity class will log an automatically-generated
stop event.

Each arg must be a wrapper macro such as TraceLoggingValue, TraceLoggingInt32,
etc.

Since this macro uses a thread activity, please read the description for
TraceLoggingThreadActivity and ensure the function call or other thread
activities started within perfectly nest within each other even in cases of
errors and exceptions.
*/
#define TraceLoggingFunction(providerHandle, ...)\
    TraceLoggingThreadActivity< \
        providerHandle, \
        0 _TLG_FOREACH(_TlgKeywordVal, __VA_ARGS__), \
        5 _TLG_FOREACH(_TlgLevelVal, __VA_ARGS__)> \
        _TlgFnActivity; \
    TraceLoggingWriteStart(_TlgFnActivity, _TlgThisFunctionName, __VA_ARGS__)

#pragma endregion

#pragma region Implementation

/*
Private implementation macros. For internal use only.
Avoid IntelliSense errors about __FUNCTION__ only being valid within a function.
*/
#ifdef __INTELLISENSE__
#define _TlgThisFunctionName "ThisFunctionName"
#else
#define _TlgThisFunctionName __FUNCTION__
#endif

/*
Private implementation macros. For internal use only.
If the auto keyword is available, we can avoid referencing the activity
parameter more than once.
*/
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#define _TlgActivityDecl(activity) auto& _TlgActivity(activity);
#define _TlgActivityRef(activity) _TlgActivity
#else
#define _TlgActivityDecl(activity)
#define _TlgActivityRef(activity) (activity)
#endif

/*
Private implementation function. For internal use only.
Separate function to minimize code bloat by consolidating the auto-stop events.
*/
template<UINT64 keyword, UINT8 level>
void _TlgWriteActivityAutoStop(
    TraceLoggingHProvider provider,
    _In_ GUID const* pActivityId)
{
    TraceLoggingWriteActivity(
        provider,
        "ActivityStoppedAutomatically",
        pActivityId,
        NULL,
        TraceLoggingOpcode(2 /* WINEVENT_OPCODE_STOP */),
        TraceLoggingKeyword(keyword),
        TraceLoggingLevel(level));
}

/*
Private implementation function. For internal use only.
*/
inline bool _TlgGuidIsZero(GUID const& g)
{
    INT32 const* p = reinterpret_cast<INT32 const*>(&g);
    return
        p[0] == 0 &&
        p[1] == 0 &&
        p[2] == 0 &&
        p[3] == 0;
}

/*
Private implementation function. For internal use only.
*/
inline bool _TlgGuidEqual(GUID const& g1, GUID const& g2)
{
    INT32 const* p1 = reinterpret_cast<INT32 const*>(&g1);
    INT32 const* p2 = reinterpret_cast<INT32 const*>(&g2);
    return
        p1[0] == p2[0] &&
        p1[1] == p2[1] &&
        p1[2] == p2[2] &&
        p1[3] == p2[3];
}

/*
Private implementation class. For internal use only.
*/
template<
    typename DerivedTy, // DerivedTy must define Provider(), OnStarted(), OnStopped().
    UINT64 keyword,
    UINT8 level>
class _TlgActivityBase
{
    _TlgActivityBase(const _TlgActivityBase&); // = delete
    _TlgActivityBase& operator=(const _TlgActivityBase&); // = delete

    void Reset()
    {
        m_State = Created;
        m_HasRelatedId = false;
    }

    enum State
    {
        Created,
        Started,
        Stopped,
        Destroyed
    };

    State m_State;
    bool m_HasRelatedId;
    GUID m_Id;
    GUID m_CapturedRelatedId;

protected:

    ~_TlgActivityBase()
    {
        if (m_State == Started)
        {
            zInternalStop();
            _TlgWriteActivityAutoStop<keyword, level>(
                static_cast<DerivedTy*>(this)->Provider(),
                &m_Id);
        }

        m_State = Destroyed;
    }

    _TlgActivityBase()
    {
        Reset();
    }

#if defined(_MSC_VER) && (_MSC_VER >= 1600)

    _TlgActivityBase(_TlgActivityBase&& rhs)
    {
        Reset();
        *this = static_cast<_TlgActivityBase&&>(rhs);
    }

    _TlgActivityBase& operator=(_TlgActivityBase&& rhs)
    {
        _TLG_ASSERT(m_State == Created, "Move-assign to newly created activities only");
        m_State = rhs.m_State;
        m_HasRelatedId = rhs.m_HasRelatedId;
        m_Id = rhs.m_Id;
        m_CapturedRelatedId = rhs.m_CapturedRelatedId;
        rhs.Reset();
        return *this;
    }

#endif // _MSC_VER >= 1600

    /*
    Should be called during activity setup (before activity starts).
    If this is used, do NOT use PushThreadActivityId or PopThreadActivityId.
    */
    void SetRelatedId(const GUID& relatedActivityId)
    {
        _TLG_ASSERT(m_State == Created, "_TlgActivityBase::SetRelatedId called from invalid state.");
        _TLG_ASSERT(!m_HasRelatedId, "_TlgActivityBase::RelatedActivity was already set.");
        m_CapturedRelatedId = relatedActivityId;
        m_HasRelatedId = true;
    }

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

    /*
    Should be called from OnStarted if applicable.
    If this is used, do NOT use SetRelatedId.
    */
    void PushThreadActivityId()
    {
        _TLG_ASSERT(m_State == Created, "_TlgActivityBase::PushThreadActivityId called from invalid state.");
        _TLG_ASSERT(!m_HasRelatedId, "_TlgActivityBase::RelatedActivity was already set.");
        m_CapturedRelatedId = m_Id;
        EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_SET_ID, &m_CapturedRelatedId);
        m_HasRelatedId = true;
    }

    /*
    Should be called from OnStopped if applicable.
    If this is used, do NOT use SetRelatedId.
    */
    void PopThreadActivityId()
    {
        _TLG_ASSERT(m_State == Started, "_TlgActivityBase::PopThreadActivityId called from invalid state.");
        if (m_HasRelatedId)
        {
            EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_SET_ID, &m_CapturedRelatedId);
            _TLG_ASSERT(_TlgGuidEqual(m_Id, m_CapturedRelatedId), "_TlgActivityBase: current id does not match set id!");
        }
    }

#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

public:

    /*
    The activity's Keyword, which is used as the keyword for the START and STOP events.
    */
    static const UINT64 Keyword = keyword;

    /*
    The activity's Level, which is used as the level for the START and STOP events.
    */
    static const UINT8 Level = level;

    /*
    Returns the activity Id.
    */
    _Ret_ const GUID* Id() const
    {
        _TLG_ASSERT(m_State >= Started, "TraceLoggingActivity::Id() called from invalid state");
        _TLG_ASSERT(m_State != Destroyed, "TraceLoggingActivity::Id() called after destruction");
        return &m_Id;
    }

    /*
    Returns true if the activity has been started and has not yet been stopped.
    */
    bool IsStarted() const
    {
        return m_State == Started;
    }

    /*
    Private implementation method. For internal use only.
    Called by TraceLoggingWriteStart. Do not call directly.
    Returns the related activity Id, if there is one.
    Returns NULL if the related activity Id has not been set or if it is GUID_NULL.
    */
    _Ret_opt_ const GUID* zInternalRelatedId() const
    {
        _TLG_ASSERT(m_State == Started, "TraceLoggingWriteStart race condition");
        return m_HasRelatedId && !_TlgGuidIsZero(m_CapturedRelatedId) ? &m_CapturedRelatedId : NULL;
    }

    /*
    Private implementation method. For internal use only.
    Called by TraceLoggingWriteStart. Do not call directly.
    */
    void zInternalStart()
    {
        _TLG_ASSERT(m_State == Created, "TraceLoggingWriteStart called from invalid state.");

        DerivedTy* pDerived = static_cast<DerivedTy*>(this);
        if (TraceLoggingProviderEnabled(pDerived->Provider(), level, keyword))
        {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

            EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, &m_Id);

#else // !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

            // Currently for store applications we cannot call the APIs to have ETW generate
            // activity IDs. So we are implementing a similar time based algorithm here with
            // a little more uniqueness added for the current process / thread that ETW does
            // not have to worry about since it is incremented in a system global way.

            static INT64 s_Seed;
            static INT64 s_Count;

            // One time initialization, we are OK if multiple threads go through this
            // the statics will be initialized just once due to compare exchange.
            if (!s_Seed || !s_Count)
            {
                LARGE_INTEGER currentTime;
                GetSystemTimeAsFileTime(reinterpret_cast<LPFILETIME>(&currentTime));
                currentTime.LowPart ^= GetCurrentThreadId();
                currentTime.HighPart ^= GetCurrentProcessId();
                InterlockedCompareExchange64(&s_Count, currentTime.QuadPart, 0);
                currentTime.QuadPart ^= static_cast<INT64>(GetTickCount64());
                InterlockedCompareExchange64(&s_Seed, currentTime.QuadPart, 0);
            }

            reinterpret_cast<INT64*>(&m_Id)[0] = s_Seed;
            reinterpret_cast<INT64*>(&m_Id)[1] = InterlockedIncrement64(&s_Count);

#endif // !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
            
            pDerived->OnStarted();
        }
        else
        {
            // Zero the activity id in case we end up logging the stop.
            ZeroMemory(&m_Id, sizeof(&m_Id));
        }

        m_State = Started;
    }

    /*
    Private implementation method. For internal use only.
    Called by TraceLoggingWriteStop. Do not call directly.
    */
    void zInternalStop()
    {
        _TLG_ASSERT(m_State == Started, "TraceLoggingWriteStop called from invalid state");

        DerivedTy* pDerived = static_cast<DerivedTy*>(this);
        pDerived->OnStopped();

        m_State = Stopped;
    }
};

template<
    TraceLoggingHProvider const& provider,
    UINT64 keyword,
    UINT8 level,
    typename TlgReflectorTag>
class TraceLoggingActivity
    : public _TlgActivityBase<TraceLoggingActivity<provider, keyword, level, TlgReflectorTag>, keyword, level>
{
    typedef
        _TlgActivityBase<TraceLoggingActivity<provider, keyword, level, TlgReflectorTag>, keyword, level>
        BaseTy;
    friend class BaseTy;

    void OnStarted()
    {
    }

    void OnStopped()
    {
    }

public:

    TraceLoggingActivity()
    {
    }

#if defined(_MSC_VER) && (_MSC_VER >= 1600)

    TraceLoggingActivity(TraceLoggingActivity&& rhs)
        : BaseTy(static_cast<TraceLoggingActivity&&>(rhs))
    {
    }

    TraceLoggingActivity& operator=(TraceLoggingActivity&& rhs)
    {
        BaseTy::operator=(static_cast<TraceLoggingActivity&&>(rhs));
        return *this;
    }

#endif // _MSC_VER >= 1600

    /*
    Returns a handle to the TraceLogging provider associated with this activity.
    */
    TraceLoggingHProvider Provider() const
    {
        return provider;
    }

    /*
    Sets the related (parent) activity.
    May only be called once. Must be called before starting the activity.
    */
    template<typename ActivityTy>
    void SetRelatedActivity(_In_ const ActivityTy& relatedActivity)
    {
        SetRelatedId(*relatedActivity.Id());
    }

    /*
    Sets the related (parent) activity.
    May only be called once. Must be called before starting the activity.
    */
    void SetRelatedActivityId(_In_ const GUID& relatedActivityId)
    {
        SetRelatedId(relatedActivityId);
    }

    /*
    Sets the related (parent) activity.
    May only be called once. Must be called before starting the activity.
    */
    void SetRelatedActivityId(_In_ const GUID* relatedActivityId)
    {
        _TLG_ASSERT(relatedActivityId != NULL, "TraceLoggingActivity SetRelatedActivity called with NULL id.");
        SetRelatedId(*relatedActivityId);
    }
};

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

template<
    TraceLoggingHProvider const& provider,
    UINT64 keyword,
    UINT8 level,
    typename TlgReflectorTag>
class TraceLoggingThreadActivity
    : public _TlgActivityBase<TraceLoggingThreadActivity<provider, keyword, level, TlgReflectorTag>, keyword, level>
{
    typedef
        _TlgActivityBase<TraceLoggingThreadActivity<provider, keyword, level, TlgReflectorTag>, keyword, level>
        BaseTy;
    friend class BaseTy;

    void OnStarted()
    {
        PushThreadActivityId();
    }

    void OnStopped()
    {
        PopThreadActivityId();
    }

public:

    TraceLoggingThreadActivity()
    {
    }

#if defined(_MSC_VER) && (_MSC_VER >= 1600)

    TraceLoggingThreadActivity(TraceLoggingThreadActivity&& rhs)
        : BaseTy(static_cast<TraceLoggingThreadActivity&&>(rhs))
    {
    }

    TraceLoggingThreadActivity& operator=(TraceLoggingThreadActivity&& rhs)
    {
        BaseTy::operator=(static_cast<TraceLoggingThreadActivity&&>(rhs));
        return *this;
    }

#endif // _MSC_VER >= 1600

    /*
    Returns a handle to the TraceLogging provider associated with this activity.
    */
    TraceLoggingHProvider Provider() const
    {
        return provider;
    }
};

class TraceLoggingThreadActivityIdSetter
{
    GUID m_ActivityId;
    GUID m_SavedActivityId;

    TraceLoggingThreadActivityIdSetter(const TraceLoggingThreadActivityIdSetter&); // = delete
    const TraceLoggingThreadActivityIdSetter& operator=(const TraceLoggingThreadActivityIdSetter&); // = delete

public:

    explicit TraceLoggingThreadActivityIdSetter(_In_ const GUID& activityId)
        : m_ActivityId(activityId)
        , m_SavedActivityId(activityId)
    {
        EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_SET_ID, &m_SavedActivityId);
    }

    explicit TraceLoggingThreadActivityIdSetter(_In_ const GUID* activityId)
        : m_ActivityId(*activityId)
        , m_SavedActivityId(*activityId)
    {
        EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_SET_ID, &m_SavedActivityId);
    }

    ~TraceLoggingThreadActivityIdSetter()
    {
        EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_SET_ID, &m_SavedActivityId);
        _TLG_ASSERT(_TlgGuidEqual(m_ActivityId, m_SavedActivityId), "TraceLoggingThreadActivityIdSetter current id does not match set id!");
    }
};

#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

#pragma endregion

#endif // RC_INVOKED
#pragma option pop /*P_O_Pop*/
