HRESULT CProfilerManager::AddRawProfilerHook()

in src/InstrumentationEngine/ProfilerManager.cpp [182:318]


HRESULT CProfilerManager::AddRawProfilerHook(
    _In_ IUnknown *pUnkProfilerCallback
    )
{
    HRESULT hr = S_OK;
    IfNullRetPointer(pUnkProfilerCallback);

    CProfilerCallbackHolder* profilerCallbackHolder = static_cast<CProfilerCallbackHolder*>(InterlockedCompareExchangePointer(
        (volatile PVOID*)&m_profilerCallbackHolder,
        nullptr,
        nullptr));

    if (profilerCallbackHolder != nullptr)
    {
        CLogging::LogError(_T("CAppDomainInfo::AddRawProfilerHook - Raw profiler hook is already initialized"));
        return E_FAIL;
    }

    if (!GetIsInInitialize())
    {
        CLogging::LogError(_T("Begin CAppDomainInfo::AddRawProfilerHook - Cannot add a raw profiler hook after initialize"));
        return E_FAIL;
    }

    CCriticalSectionHolder lock(&m_cs);

    profilerCallbackHolder = new CProfilerCallbackHolder;

    // Rather than following COM-rules and QI-ing for each specific ICorProfilerCallback version, we instead follow the implementation set by the CLR
    // where to interface inheritance, higher versioned ICorProfilerCallback## can be statically-casted to lower versioned ICorProfilerCallback##,
    // and raw profilers QI can just return the highest supported version (they must still provide implementation for all lower versioned callbacks).
    //
    // See https://github.com/dotnet/runtime/blob/cf6b06b1d36d545e37b00bf1a6311b7fff33ff4e/src/coreclr/src/vm/eetoprofinterfaceimpl.cpp#L613

    // ICorProfilerCallback7
    CComPtr<ICorProfilerCallback7> pCorProfilerCallback7;
    hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback7), (LPVOID*)&pCorProfilerCallback7);
    if (SUCCEEDED(hr))
    {
        profilerCallbackHolder->m_CorProfilerCallback7 = pCorProfilerCallback7;
    }

    // ICorProfilerCallback6
    if (profilerCallbackHolder->m_CorProfilerCallback7)
    {
        profilerCallbackHolder->m_CorProfilerCallback6 = static_cast<ICorProfilerCallback6*>(profilerCallbackHolder->m_CorProfilerCallback7);
    }
    else
    {
        CComPtr<ICorProfilerCallback6> pCorProfilerCallback6;
        hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback6), (LPVOID*)&pCorProfilerCallback6);
        if (SUCCEEDED(hr))
        {
            profilerCallbackHolder->m_CorProfilerCallback6 = pCorProfilerCallback6;
        }
    }

    // ICorProfilerCallback5
    if (profilerCallbackHolder->m_CorProfilerCallback6)
    {
        profilerCallbackHolder->m_CorProfilerCallback5 = static_cast<ICorProfilerCallback5*>(profilerCallbackHolder->m_CorProfilerCallback6);
    }
    else
    {
        CComPtr<ICorProfilerCallback5> pCorProfilerCallback5;
        hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback5), (LPVOID*)&pCorProfilerCallback5);
        if (SUCCEEDED(hr))
        {
            profilerCallbackHolder->m_CorProfilerCallback5 = pCorProfilerCallback5;
        }
    }

    // ICorProfilerCallback4
    if (profilerCallbackHolder->m_CorProfilerCallback5)
    {
        profilerCallbackHolder->m_CorProfilerCallback4 = static_cast<ICorProfilerCallback4*>(profilerCallbackHolder->m_CorProfilerCallback5);
    }
    else
    {
        CComPtr<ICorProfilerCallback4> pCorProfilerCallback4;
        hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback4), (LPVOID*)&pCorProfilerCallback4);
        if (SUCCEEDED(hr))
        {
            profilerCallbackHolder->m_CorProfilerCallback4 = pCorProfilerCallback4;
        }
    }

    // ICorProfilerCallback3
    if (profilerCallbackHolder->m_CorProfilerCallback4)
    {
        profilerCallbackHolder->m_CorProfilerCallback3 = static_cast<ICorProfilerCallback3*>(profilerCallbackHolder->m_CorProfilerCallback4);
    }
    else
    {
        CComPtr<ICorProfilerCallback3> pCorProfilerCallback3;
        hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback3), (LPVOID*)&pCorProfilerCallback3);
        if (SUCCEEDED(hr))
        {
            profilerCallbackHolder->m_CorProfilerCallback3 = pCorProfilerCallback3;
        }
    }

    // ICorProfilerCallback2
    if (profilerCallbackHolder->m_CorProfilerCallback3)
    {
        profilerCallbackHolder->m_CorProfilerCallback2 = static_cast<ICorProfilerCallback2*>(profilerCallbackHolder->m_CorProfilerCallback3);
    }
    else
    {
        CComPtr<ICorProfilerCallback2> pCorProfilerCallback2;
        hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback2), (LPVOID*)&pCorProfilerCallback2);
        if (SUCCEEDED(hr))
        {
            profilerCallbackHolder->m_CorProfilerCallback2 = pCorProfilerCallback2;
        }
    }

    // ICorProfilerCallback
    if (profilerCallbackHolder->m_CorProfilerCallback2)
    {
        profilerCallbackHolder->m_CorProfilerCallback = static_cast<ICorProfilerCallback*>(profilerCallbackHolder->m_CorProfilerCallback2);
    }
    else
    {
        CComPtr<ICorProfilerCallback> pCorProfilerCallback;
        hr = pUnkProfilerCallback->QueryInterface(__uuidof(ICorProfilerCallback), (LPVOID*)&pCorProfilerCallback);
        if (SUCCEEDED(hr))
        {
            profilerCallbackHolder->m_CorProfilerCallback = pCorProfilerCallback;
        }
    }

    // ICorProfiler::Initialize happens before any other callbacks so this shouldn't have any race conditions
    InterlockedExchangePointer((void**)&m_profilerCallbackHolder, profilerCallbackHolder);

    return S_OK;
}