// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//*****************************************************************************
// File: ShimCallback.cpp
//

//
// The V3 ICD debugging APIs have a lower abstraction level than V2.
// This provides V2 ICD debugging functionality on top of the V3 debugger object.
//*****************************************************************************

#include "stdafx.h"

#include "safewrap.h"
#include "check.h"

#include <limits.h>
#include "shimpriv.h"


//
// Callback that shim provides, which then queues up the events.
//
ShimProxyCallback::ShimProxyCallback(ShimProcess * pShim)
    : m_cRef(0)
{
    m_pShim = pShim;
}

// Implement IUnknown
ULONG ShimProxyCallback::AddRef()
{
    return InterlockedIncrement(&m_cRef);
}
ULONG ShimProxyCallback::Release()
{
    LONG ref = InterlockedDecrement(&m_cRef);
    if (ref == 0)
    {
        delete this;
        return 0;
    }
    return ref;

}
HRESULT ShimProxyCallback::QueryInterface(REFIID riid, void **ppInterface)
{
    if (riid == IID_ICorDebugManagedCallback)
    {
        *ppInterface = static_cast<ICorDebugManagedCallback*>(this);
    }
    else if (riid == IID_ICorDebugManagedCallback2)
    {
        *ppInterface = static_cast<ICorDebugManagedCallback2*>(this);
    }
    else if (riid == IID_ICorDebugManagedCallback3)
    {
        *ppInterface = static_cast<ICorDebugManagedCallback3*>(this);
    }
    else if (riid == IID_ICorDebugManagedCallback4)
    {
        *ppInterface = static_cast<ICorDebugManagedCallback4*>(this);
    }
    else if (riid == IID_IUnknown)
    {
        *ppInterface = static_cast<IUnknown*>(static_cast<ICorDebugManagedCallback*>(this));
    }
    else
    {
        *ppInterface = NULL;
        return E_NOINTERFACE;
    }

    this->AddRef();
    return S_OK;
}

//
// Map from an old frame to a new one.
//
// Arguments:
//   pThread - thread that frame is on
//   pOldFrame - old frame before the continue, may have gotten neutered.
//
// Returns:
//   a new, non-neutered frame that matches the old frame.
//
// Notes:
//   Called by event handlers below (which are considered Outside the RS).
//   No adjust of reference, Thread already has reference.
//   @dbgtodo shim-stackwalks: this is used for exception callbacks, which may change for V3.
ICorDebugFrame * UpdateFrame(ICorDebugThread * pThread, ICorDebugFrame * pOldFrame)
{
    PUBLIC_API_ENTRY_FOR_SHIM(NULL);

    RSExtSmartPtr<ICorDebugFrame> pNewFrame;

    EX_TRY
    {
        CordbFrame * pFrame = static_cast<CordbFrame *> (pOldFrame);
        if (pFrame != NULL)
        {
            FramePointer fp = pFrame->GetFramePointer();

            CordbThread * pThread2 = static_cast<CordbThread *> (pThread);
            pThread2->FindFrame(&pNewFrame, fp);

            //
        }
    }
    EX_CATCH
    {
        // Do not throw out of this function.  Doing so means that the debugger never gets a chance to
        // continue the debuggee process.  This will lead to a hang.  Instead, try to make a best effort to
        // continue with a NULL ICDFrame.  VS is able to handle this gracefully.
        pNewFrame.Assign(NULL);
    }
    EX_END_CATCH(SwallowAllExceptions);

    return pNewFrame;
}



//
// Below this was autogenerated
//

// Implementation of ICorDebugManagedCallback::Breakpoint
HRESULT ShimProxyCallback::Breakpoint(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugBreakpoint * pBreakpoint)
{
    m_pShim->PreDispatchEvent();
    class BreakpointEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugBreakpoint > m_pBreakpoint;

    public:
        // Ctor
        BreakpointEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugBreakpoint * pBreakpoint) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pBreakpoint.Assign(pBreakpoint);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->Breakpoint(m_pAppDomain, m_pThread, m_pBreakpoint);
        }
    }; // end class BreakpointEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new BreakpointEvent(pAppDomain, pThread, pBreakpoint));
    return S_OK;
} // end of methodICorDebugManagedCallback::Breakpoint


// Implementation of ICorDebugManagedCallback::StepComplete
HRESULT ShimProxyCallback::StepComplete(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugStepper * pStepper, CorDebugStepReason reason)
{
    m_pShim->PreDispatchEvent();
    class StepCompleteEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugStepper > m_pStepper;
        CorDebugStepReason m_reason;

    public:
        // Ctor
        StepCompleteEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugStepper * pStepper, CorDebugStepReason reason) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pStepper.Assign(pStepper);
            this->m_reason = reason;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->StepComplete(m_pAppDomain, m_pThread, m_pStepper, m_reason);
        }
    }; // end class StepCompleteEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new StepCompleteEvent(pAppDomain, pThread, pStepper, reason));
    return S_OK;
} // end of methodICorDebugManagedCallback::StepComplete


// Implementation of ICorDebugManagedCallback::Break
HRESULT ShimProxyCallback::Break(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread)
{
    m_pShim->PreDispatchEvent();
    class BreakEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;

    public:
        // Ctor
        BreakEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->Break(m_pAppDomain, m_pThread);
        }
    }; // end class BreakEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new BreakEvent(pAppDomain, pThread));
    return S_OK;
} // end of methodICorDebugManagedCallback::Break


// Implementation of ICorDebugManagedCallback::Exception
HRESULT ShimProxyCallback::Exception(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, BOOL fUnhandled)
{
    m_pShim->PreDispatchEvent();
    class ExceptionEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        BOOL m_fUnhandled;

    public:
        // Ctor
        ExceptionEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, BOOL fUnhandled) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_fUnhandled = fUnhandled;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->Exception(m_pAppDomain, m_pThread, m_fUnhandled);
        }
    }; // end class ExceptionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new ExceptionEvent(pAppDomain, pThread, fUnhandled));
    return S_OK;
} // end of methodICorDebugManagedCallback::Exception


// Implementation of ICorDebugManagedCallback::EvalComplete
HRESULT ShimProxyCallback::EvalComplete(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugEval * pEval)
{
    m_pShim->PreDispatchEvent();
    class EvalCompleteEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugEval > m_pEval;

    public:
        // Ctor
        EvalCompleteEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugEval * pEval) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pEval.Assign(pEval);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->EvalComplete(m_pAppDomain, m_pThread, m_pEval);
        }
    }; // end class EvalCompleteEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new EvalCompleteEvent(pAppDomain, pThread, pEval));
    return S_OK;
} // end of methodICorDebugManagedCallback::EvalComplete


// Implementation of ICorDebugManagedCallback::EvalException
HRESULT ShimProxyCallback::EvalException(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugEval * pEval)
{
    m_pShim->PreDispatchEvent();
    class EvalExceptionEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugEval > m_pEval;

    public:
        // Ctor
        EvalExceptionEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugEval * pEval) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pEval.Assign(pEval);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->EvalException(m_pAppDomain, m_pThread, m_pEval);
        }
    }; // end class EvalExceptionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new EvalExceptionEvent(pAppDomain, pThread, pEval));
    return S_OK;
} // end of methodICorDebugManagedCallback::EvalException


// Implementation of ICorDebugManagedCallback::CreateProcess
// This will only be called for a Real create-process event.
HRESULT ShimProxyCallback::CreateProcess(ICorDebugProcess * pProcess)
{
    m_pShim->PreDispatchEvent(true);
    QueueCreateProcess(pProcess);
    return S_OK;
}

void ShimProxyCallback::QueueCreateProcess(ICorDebugProcess * pProcess)
{
    class CreateProcessEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;

    public:
        // Ctor
        CreateProcessEvent(ICorDebugProcess * pProcess, ShimProcess * pShim) :
             ManagedEvent(),
             m_pShim(pShim)
        {
            this->m_pProcess.Assign(pProcess);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            // signal that we are in the callback--this will be cleared in code:CordbProcess::ContinueInternal
            m_pShim->SetInCreateProcess(true);
            return args.GetCallback1()->CreateProcess(m_pProcess);
        }

        // we need access to the shim in Dispatch so we can set the InCreateProcess flag to keep track of
        // when we are actually in the callback. We need this information to be able to emulate
        // the hresult logic in v2.0.
        ShimProcess * m_pShim;
    }; // end class CreateProcessEvent

    if (!m_pShim->RemoveDuplicateCreationEventIfPresent(pProcess))
    {
        m_pShim->GetManagedEventQueue()->QueueEvent(new CreateProcessEvent(pProcess, m_pShim));
    }
} // end of methodICorDebugManagedCallback::CreateProcess


// Implementation of ICorDebugManagedCallback::ExitProcess
HRESULT ShimProxyCallback::ExitProcess(ICorDebugProcess * pProcess)
{
    m_pShim->PreDispatchEvent();
    class ExitProcessEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;

    public:
        // Ctor
        ExitProcessEvent(ICorDebugProcess * pProcess) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->ExitProcess(m_pProcess);
        }
    }; // end class ExitProcessEvent

    m_pShim->RemoveDuplicateCreationEventIfPresent(pProcess);
    m_pShim->GetManagedEventQueue()->QueueEvent(new ExitProcessEvent(pProcess));
    return S_OK;
} // end of methodICorDebugManagedCallback::ExitProcess


// Implementation of ICorDebugManagedCallback::CreateThread
HRESULT ShimProxyCallback::CreateThread(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread)
{
    m_pShim->PreDispatchEvent();
    class CreateThreadEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;

    public:
        // Ctor
        CreateThreadEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->CreateThread(m_pAppDomain, m_pThread);
        }
    }; // end class CreateThreadEvent

    if (!m_pShim->RemoveDuplicateCreationEventIfPresent(pThread))
    {
        m_pShim->GetManagedEventQueue()->QueueEvent(new CreateThreadEvent(pAppDomain, pThread));
    }
    return S_OK;
} // end of methodICorDebugManagedCallback::CreateThread


// Implementation of ICorDebugManagedCallback::ExitThread
HRESULT ShimProxyCallback::ExitThread(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread)
{
    m_pShim->PreDispatchEvent();
    class ExitThreadEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;

    public:
        // Ctor
        ExitThreadEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->ExitThread(m_pAppDomain, m_pThread);
        }
    }; // end class ExitThreadEvent

    m_pShim->RemoveDuplicateCreationEventIfPresent(pThread);
    m_pShim->GetManagedEventQueue()->QueueEvent(new ExitThreadEvent(pAppDomain, pThread));
    return S_OK;
} // end of methodICorDebugManagedCallback::ExitThread


// Called from fake attach events.
//
// Arguments:
//   pAppDomain - appdomain for the LoadModule debug event
//   pModule - module being loaded.
//
// Notes:
//   See code:ShimProcess::QueueFakeAttachEvents
//   This is the fake version of code:ShimProxyCallback::LoadModule.
//   It sends an IPC event to go in process to collect information that we can't yet get via
//   DAC from out-of-proc.
void ShimProxyCallback::FakeLoadModule(ICorDebugAppDomain *pAppDomain, ICorDebugModule *pModule)
{
    class FakeLoadModuleEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugModule > m_pModule;

    public:
        // Ctor
        FakeLoadModuleEvent(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule, ShimProcess * pShim) :
             ManagedEvent(),
             m_pShim(pShim)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pModule.Assign(pModule);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            // signal that we are in the callback--this will be cleared in code:CordbProcess::ContinueInternal
            m_pShim->SetInLoadModule(true);
            return args.GetCallback1()->LoadModule(m_pAppDomain, m_pModule);
        }

        // we need access to the shim in Dispatch so we can set the InLoadModule flag to keep track
        // when we are actually in the callback. We need this information to be able to emulate
        // the hresult logic in v2.0.
        ShimProcess * m_pShim;
    }; // end class LoadModuleEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new FakeLoadModuleEvent(pAppDomain, pModule, m_pShim));
} // end of methodICorDebugManagedCallback::LoadModule


// Implementation of ICorDebugManagedCallback::LoadModule
HRESULT ShimProxyCallback::LoadModule(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule)
{
    m_pShim->PreDispatchEvent();
    class LoadModuleEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugModule > m_pModule;

    public:
        // Ctor
        LoadModuleEvent(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pModule.Assign(pModule);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->LoadModule(m_pAppDomain, m_pModule);
        }
    }; // end class LoadModuleEvent

    if (!m_pShim->RemoveDuplicateCreationEventIfPresent(pModule))
    {
        m_pShim->GetManagedEventQueue()->QueueEvent(new LoadModuleEvent(pAppDomain, pModule));
    }
    return S_OK;
} // end of methodICorDebugManagedCallback::LoadModule


// Implementation of ICorDebugManagedCallback::UnloadModule
HRESULT ShimProxyCallback::UnloadModule(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule)
{
    m_pShim->PreDispatchEvent();
    class UnloadModuleEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugModule > m_pModule;

    public:
        // Ctor
        UnloadModuleEvent(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pModule.Assign(pModule);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->UnloadModule(m_pAppDomain, m_pModule);
        }
    }; // end class UnloadModuleEvent

    m_pShim->RemoveDuplicateCreationEventIfPresent(pModule);
    m_pShim->GetManagedEventQueue()->QueueEvent(new UnloadModuleEvent(pAppDomain, pModule));
    return S_OK;
} // end of methodICorDebugManagedCallback::UnloadModule


// Implementation of ICorDebugManagedCallback::LoadClass
HRESULT ShimProxyCallback::LoadClass(ICorDebugAppDomain * pAppDomain, ICorDebugClass * pClass)
{
    m_pShim->PreDispatchEvent();
    class LoadClassEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugClass > m_pClass;

    public:
        // Ctor
        LoadClassEvent(ICorDebugAppDomain * pAppDomain, ICorDebugClass * pClass) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pClass.Assign(pClass);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->LoadClass(m_pAppDomain, m_pClass);
        }
    }; // end class LoadClassEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new LoadClassEvent(pAppDomain, pClass));
    return S_OK;
} // end of methodICorDebugManagedCallback::LoadClass


// Implementation of ICorDebugManagedCallback::UnloadClass
HRESULT ShimProxyCallback::UnloadClass(ICorDebugAppDomain * pAppDomain, ICorDebugClass * pClass)
{
    m_pShim->PreDispatchEvent();
    class UnloadClassEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugClass > m_pClass;

    public:
        // Ctor
        UnloadClassEvent(ICorDebugAppDomain * pAppDomain, ICorDebugClass * pClass) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pClass.Assign(pClass);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->UnloadClass(m_pAppDomain, m_pClass);
        }
    }; // end class UnloadClassEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new UnloadClassEvent(pAppDomain, pClass));
    return S_OK;
} // end of methodICorDebugManagedCallback::UnloadClass


// Implementation of ICorDebugManagedCallback::DebuggerError
HRESULT ShimProxyCallback::DebuggerError(ICorDebugProcess * pProcess, HRESULT errorHR, DWORD errorCode)
{
    m_pShim->PreDispatchEvent();
    class DebuggerErrorEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;
        HRESULT m_errorHR;
        DWORD m_errorCode;

    public:
        // Ctor
        DebuggerErrorEvent(ICorDebugProcess * pProcess, HRESULT errorHR, DWORD errorCode) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_errorHR = errorHR;
            this->m_errorCode = errorCode;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->DebuggerError(m_pProcess, m_errorHR, m_errorCode);
        }
    }; // end class DebuggerErrorEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new DebuggerErrorEvent(pProcess, errorHR, errorCode));
    return S_OK;
} // end of methodICorDebugManagedCallback::DebuggerError


// Implementation of ICorDebugManagedCallback::LogMessage
HRESULT ShimProxyCallback::LogMessage(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, LONG lLevel, _In_ LPWSTR pLogSwitchName, _In_ LPWSTR pMessage)
{
    m_pShim->PreDispatchEvent();
    class LogMessageEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        LONG m_lLevel;
        StringCopyHolder m_pLogSwitchName;
        StringCopyHolder m_pMessage;

    public:
        // Ctor
        LogMessageEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, LONG lLevel, LPCWSTR pLogSwitchName, LPCWSTR pMessage) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_lLevel = lLevel;
            this->m_pLogSwitchName.AssignCopy(pLogSwitchName);
            this->m_pMessage.AssignCopy(pMessage);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->LogMessage(m_pAppDomain, m_pThread, m_lLevel, const_cast<WCHAR*>((const WCHAR*)m_pLogSwitchName), const_cast<WCHAR*>((const WCHAR*)m_pMessage));
        }
    }; // end class LogMessageEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new LogMessageEvent(pAppDomain, pThread, lLevel, pLogSwitchName, pMessage));
    return S_OK;
} // end of methodICorDebugManagedCallback::LogMessage


// Implementation of ICorDebugManagedCallback::LogSwitch
HRESULT ShimProxyCallback::LogSwitch(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, LONG lLevel, ULONG ulReason, _In_ LPWSTR pLogSwitchName, _In_ LPWSTR pParentName)
{
    m_pShim->PreDispatchEvent();
    class LogSwitchEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        LONG m_lLevel;
        ULONG m_ulReason;
        StringCopyHolder m_pLogSwitchName;
        StringCopyHolder m_pParentName;

    public:
        // Ctor
        LogSwitchEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, LONG lLevel, ULONG ulReason, LPCWSTR pLogSwitchName, LPCWSTR pParentName) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_lLevel = lLevel;
            this->m_ulReason = ulReason;
            this->m_pLogSwitchName.AssignCopy(pLogSwitchName);
            this->m_pParentName.AssignCopy(pParentName);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->LogSwitch(m_pAppDomain, m_pThread, m_lLevel, m_ulReason, const_cast<WCHAR*>((const WCHAR*)m_pLogSwitchName), const_cast<WCHAR*>((const WCHAR*)m_pParentName));
        }
    }; // end class LogSwitchEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new LogSwitchEvent(pAppDomain, pThread, lLevel, ulReason, pLogSwitchName, pParentName));
    return S_OK;
} // end of methodICorDebugManagedCallback::LogSwitch


// Implementation of ICorDebugManagedCallback::CreateAppDomain
HRESULT ShimProxyCallback::CreateAppDomain(ICorDebugProcess * pProcess, ICorDebugAppDomain * pAppDomain)
{
    m_pShim->PreDispatchEvent();
    class CreateAppDomainEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;

    public:
        // Ctor
        CreateAppDomainEvent(ICorDebugProcess * pProcess, ICorDebugAppDomain * pAppDomain) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_pAppDomain.Assign(pAppDomain);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->CreateAppDomain(m_pProcess, m_pAppDomain);
        }
    }; // end class CreateAppDomainEvent

    if (!m_pShim->RemoveDuplicateCreationEventIfPresent(pAppDomain))
    {
        m_pShim->GetManagedEventQueue()->QueueEvent(new CreateAppDomainEvent(pProcess, pAppDomain));
    }
    return S_OK;
} // end of methodICorDebugManagedCallback::CreateAppDomain


// Implementation of ICorDebugManagedCallback::ExitAppDomain
HRESULT ShimProxyCallback::ExitAppDomain(ICorDebugProcess * pProcess, ICorDebugAppDomain * pAppDomain)
{
    m_pShim->PreDispatchEvent();
    class ExitAppDomainEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;

    public:
        // Ctor
        ExitAppDomainEvent(ICorDebugProcess * pProcess, ICorDebugAppDomain * pAppDomain) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_pAppDomain.Assign(pAppDomain);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->ExitAppDomain(m_pProcess, m_pAppDomain);
        }
    }; // end class ExitAppDomainEvent

    m_pShim->RemoveDuplicateCreationEventIfPresent(pAppDomain);
    m_pShim->GetManagedEventQueue()->QueueEvent(new ExitAppDomainEvent(pProcess, pAppDomain));
    return S_OK;
} // end of methodICorDebugManagedCallback::ExitAppDomain


// Implementation of ICorDebugManagedCallback::LoadAssembly
HRESULT ShimProxyCallback::LoadAssembly(ICorDebugAppDomain * pAppDomain, ICorDebugAssembly * pAssembly)
{
    m_pShim->PreDispatchEvent();
    class LoadAssemblyEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugAssembly > m_pAssembly;

    public:
        // Ctor
        LoadAssemblyEvent(ICorDebugAppDomain * pAppDomain, ICorDebugAssembly * pAssembly) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pAssembly.Assign(pAssembly);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->LoadAssembly(m_pAppDomain, m_pAssembly);
        }
    }; // end class LoadAssemblyEvent

    if (!m_pShim->RemoveDuplicateCreationEventIfPresent(pAssembly))
    {
        m_pShim->GetManagedEventQueue()->QueueEvent(new LoadAssemblyEvent(pAppDomain, pAssembly));
    }
    return S_OK;
} // end of methodICorDebugManagedCallback::LoadAssembly


// Implementation of ICorDebugManagedCallback::UnloadAssembly
HRESULT ShimProxyCallback::UnloadAssembly(ICorDebugAppDomain * pAppDomain, ICorDebugAssembly * pAssembly)
{
    m_pShim->PreDispatchEvent();
    class UnloadAssemblyEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugAssembly > m_pAssembly;

    public:
        // Ctor
        UnloadAssemblyEvent(ICorDebugAppDomain * pAppDomain, ICorDebugAssembly * pAssembly) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pAssembly.Assign(pAssembly);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->UnloadAssembly(m_pAppDomain, m_pAssembly);
        }
    }; // end class UnloadAssemblyEvent

    m_pShim->RemoveDuplicateCreationEventIfPresent(pAssembly);
    m_pShim->GetManagedEventQueue()->QueueEvent(new UnloadAssemblyEvent(pAppDomain, pAssembly));
    return S_OK;
} // end of methodICorDebugManagedCallback::UnloadAssembly


// Implementation of ICorDebugManagedCallback::ControlCTrap
HRESULT ShimProxyCallback::ControlCTrap(ICorDebugProcess * pProcess)
{
    m_pShim->PreDispatchEvent();
    class ControlCTrapEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess> m_pProcess;

    public:
        // Ctor
        ControlCTrapEvent(ICorDebugProcess * pProcess) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            HRESULT hr = args.GetCallback1()->ControlCTrap(m_pProcess);

            // Pass the callback result to the CordbProcess
            CordbProcess *proc = static_cast<CordbProcess*>((ICorDebugProcess*) m_pProcess);
            proc->HandleControlCTrapResult(hr);
            return hr;
        }
    }; // end class ControlCTrapEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new ControlCTrapEvent(pProcess));
    return S_OK;
} // end of methodICorDebugManagedCallback::ControlCTrap


// Implementation of ICorDebugManagedCallback::NameChange
HRESULT ShimProxyCallback::NameChange(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread)
{
    m_pShim->PreDispatchEvent();
    class NameChangeEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;

    public:
        // Ctor
        NameChangeEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->NameChange(m_pAppDomain, m_pThread);
        }
    }; // end class NameChangeEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new NameChangeEvent(pAppDomain, pThread));
    return S_OK;
} // end of methodICorDebugManagedCallback::NameChange


// Implementation of ICorDebugManagedCallback::UpdateModuleSymbols
HRESULT ShimProxyCallback::UpdateModuleSymbols(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule, IStream * pSymbolStream)
{
    m_pShim->PreDispatchEvent();
    class UpdateModuleSymbolsEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugModule > m_pModule;
        RSExtSmartPtr<IStream > m_pSymbolStream;

    public:
        // Ctor
        UpdateModuleSymbolsEvent(ICorDebugAppDomain * pAppDomain, ICorDebugModule * pModule, IStream * pSymbolStream) :
             ManagedEvent()
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pModule.Assign(pModule);
            this->m_pSymbolStream.Assign(pSymbolStream);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->UpdateModuleSymbols(m_pAppDomain, m_pModule, m_pSymbolStream);
        }
    }; // end class UpdateModuleSymbolsEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new UpdateModuleSymbolsEvent(pAppDomain, pModule, pSymbolStream));
    return S_OK;
} // end of methodICorDebugManagedCallback::UpdateModuleSymbols


// Implementation of ICorDebugManagedCallback::EditAndContinueRemap
HRESULT ShimProxyCallback::EditAndContinueRemap(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFunction * pFunction, BOOL fAccurate)
{
    m_pShim->PreDispatchEvent();
    class EditAndContinueRemapEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugFunction > m_pFunction;
        BOOL m_fAccurate;

    public:
        // Ctor
        EditAndContinueRemapEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFunction * pFunction, BOOL fAccurate) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pFunction.Assign(pFunction);
            this->m_fAccurate = fAccurate;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->EditAndContinueRemap(m_pAppDomain, m_pThread, m_pFunction, m_fAccurate);
        }
    }; // end class EditAndContinueRemapEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new EditAndContinueRemapEvent(pAppDomain, pThread, pFunction, fAccurate));
    return S_OK;
} // end of methodICorDebugManagedCallback::EditAndContinueRemap


// Implementation of ICorDebugManagedCallback::BreakpointSetError
HRESULT ShimProxyCallback::BreakpointSetError(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugBreakpoint * pBreakpoint, DWORD dwError)
{
    m_pShim->PreDispatchEvent();
    class BreakpointSetErrorEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugBreakpoint > m_pBreakpoint;
        DWORD m_dwError;

    public:
        // Ctor
        BreakpointSetErrorEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugBreakpoint * pBreakpoint, DWORD dwError) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pBreakpoint.Assign(pBreakpoint);
            this->m_dwError = dwError;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback1()->BreakpointSetError(m_pAppDomain, m_pThread, m_pBreakpoint, m_dwError);
        }
    }; // end class BreakpointSetErrorEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new BreakpointSetErrorEvent(pAppDomain, pThread, pBreakpoint, dwError));
    return S_OK;
} // end of methodICorDebugManagedCallback::BreakpointSetError


// Implementation of ICorDebugManagedCallback2::FunctionRemapOpportunity
HRESULT ShimProxyCallback::FunctionRemapOpportunity(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFunction * pOldFunction, ICorDebugFunction * pNewFunction, ULONG32 oldILOffset)
{
    m_pShim->PreDispatchEvent();
    class FunctionRemapOpportunityEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugFunction > m_pOldFunction;
        RSExtSmartPtr<ICorDebugFunction > m_pNewFunction;
        ULONG32 m_oldILOffset;

    public:
        // Ctor
        FunctionRemapOpportunityEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFunction * pOldFunction, ICorDebugFunction * pNewFunction, ULONG32 oldILOffset) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pOldFunction.Assign(pOldFunction);
            this->m_pNewFunction.Assign(pNewFunction);
            this->m_oldILOffset = oldILOffset;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->FunctionRemapOpportunity(m_pAppDomain, m_pThread, m_pOldFunction, m_pNewFunction, m_oldILOffset);
        }
    }; // end class FunctionRemapOpportunityEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new FunctionRemapOpportunityEvent(pAppDomain, pThread, pOldFunction, pNewFunction, oldILOffset));
    return S_OK;
} // end of methodICorDebugManagedCallback2::FunctionRemapOpportunity


// Implementation of ICorDebugManagedCallback2::CreateConnection
HRESULT ShimProxyCallback::CreateConnection(ICorDebugProcess * pProcess, CONNID dwConnectionId, _In_ LPWSTR pConnectionName)
{
    m_pShim->PreDispatchEvent();
    class CreateConnectionEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;
        CONNID m_dwConnectionId;
        StringCopyHolder m_pConnectionName;

    public:
        // Ctor
        CreateConnectionEvent(ICorDebugProcess * pProcess, CONNID dwConnectionId, LPCWSTR pConnectionName) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_dwConnectionId = dwConnectionId;
            this->m_pConnectionName.AssignCopy(pConnectionName);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->CreateConnection(m_pProcess, m_dwConnectionId, const_cast<WCHAR*>((const WCHAR*)m_pConnectionName));
        }
    }; // end class CreateConnectionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new CreateConnectionEvent(pProcess, dwConnectionId, pConnectionName));
    return S_OK;
} // end of methodICorDebugManagedCallback2::CreateConnection


// Implementation of ICorDebugManagedCallback2::ChangeConnection
HRESULT ShimProxyCallback::ChangeConnection(ICorDebugProcess * pProcess, CONNID dwConnectionId)
{
    m_pShim->PreDispatchEvent();
    class ChangeConnectionEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;
        CONNID m_dwConnectionId;

    public:
        // Ctor
        ChangeConnectionEvent(ICorDebugProcess * pProcess, CONNID dwConnectionId) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_dwConnectionId = dwConnectionId;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->ChangeConnection(m_pProcess, m_dwConnectionId);
        }
    }; // end class ChangeConnectionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new ChangeConnectionEvent(pProcess, dwConnectionId));
    return S_OK;
} // end of methodICorDebugManagedCallback2::ChangeConnection


// Implementation of ICorDebugManagedCallback2::DestroyConnection
HRESULT ShimProxyCallback::DestroyConnection(ICorDebugProcess * pProcess, CONNID dwConnectionId)
{
    m_pShim->PreDispatchEvent();
    class DestroyConnectionEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;
        CONNID m_dwConnectionId;

    public:
        // Ctor
        DestroyConnectionEvent(ICorDebugProcess * pProcess, CONNID dwConnectionId) :
             ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_dwConnectionId = dwConnectionId;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->DestroyConnection(m_pProcess, m_dwConnectionId);
        }
    }; // end class DestroyConnectionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new DestroyConnectionEvent(pProcess, dwConnectionId));
    return S_OK;
} // end of methodICorDebugManagedCallback2::DestroyConnection



// Implementation of ICorDebugManagedCallback2::Exception
HRESULT ShimProxyCallback::Exception(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFrame * pFrame, ULONG32 nOffset, CorDebugExceptionCallbackType dwEventType, DWORD dwFlags)
{
    m_pShim->PreDispatchEvent();
    class ExceptionEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugFrame > m_pFrame;
        ULONG32 m_nOffset;
        CorDebugExceptionCallbackType m_dwEventType;
        DWORD m_dwFlags;

    public:
        // Ctor
        ExceptionEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFrame * pFrame, ULONG32 nOffset, CorDebugExceptionCallbackType dwEventType, DWORD dwFlags) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pFrame.Assign(pFrame);
            this->m_nOffset = nOffset;
            this->m_dwEventType = dwEventType;
            this->m_dwFlags = dwFlags;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->Exception(m_pAppDomain, m_pThread, UpdateFrame(m_pThread, m_pFrame), m_nOffset, m_dwEventType, m_dwFlags);
        }
    }; // end class ExceptionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new ExceptionEvent(pAppDomain, pThread, pFrame, nOffset, dwEventType, dwFlags));
    return S_OK;
} // end of methodICorDebugManagedCallback2::Exception


// Implementation of ICorDebugManagedCallback2::ExceptionUnwind
HRESULT ShimProxyCallback::ExceptionUnwind(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, CorDebugExceptionUnwindCallbackType dwEventType, DWORD dwFlags)
{
    m_pShim->PreDispatchEvent();
    class ExceptionUnwindEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        CorDebugExceptionUnwindCallbackType m_dwEventType;
        DWORD m_dwFlags;

    public:
        // Ctor
        ExceptionUnwindEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, CorDebugExceptionUnwindCallbackType dwEventType, DWORD dwFlags) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_dwEventType = dwEventType;
            this->m_dwFlags = dwFlags;
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->ExceptionUnwind(m_pAppDomain, m_pThread, m_dwEventType, m_dwFlags);
        }
    }; // end class ExceptionUnwindEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new ExceptionUnwindEvent(pAppDomain, pThread, dwEventType, dwFlags));
    return S_OK;
} // end of methodICorDebugManagedCallback2::ExceptionUnwind


// Implementation of ICorDebugManagedCallback2::FunctionRemapComplete
HRESULT ShimProxyCallback::FunctionRemapComplete(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFunction * pFunction)
{
    m_pShim->PreDispatchEvent();
    class FunctionRemapCompleteEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugFunction > m_pFunction;

    public:
        // Ctor
        FunctionRemapCompleteEvent(ICorDebugAppDomain * pAppDomain, ICorDebugThread * pThread, ICorDebugFunction * pFunction) :
             ManagedEvent(pThread)
        {
            this->m_pAppDomain.Assign(pAppDomain);
            this->m_pThread.Assign(pThread);
            this->m_pFunction.Assign(pFunction);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->FunctionRemapComplete(m_pAppDomain, m_pThread, m_pFunction);
        }
    }; // end class FunctionRemapCompleteEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new FunctionRemapCompleteEvent(pAppDomain, pThread, pFunction));
    return S_OK;
} // end of methodICorDebugManagedCallback2::FunctionRemapComplete


// Implementation of ICorDebugManagedCallback2::MDANotification
HRESULT ShimProxyCallback::MDANotification(ICorDebugController * pController, ICorDebugThread * pThread, ICorDebugMDA * pMDA)
{
    m_pShim->PreDispatchEvent();
    class MDANotificationEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugController > m_pController;
        RSExtSmartPtr<ICorDebugThread > m_pThread;
        RSExtSmartPtr<ICorDebugMDA > m_pMDA;

    public:
        // Ctor
        MDANotificationEvent(ICorDebugController * pController, ICorDebugThread * pThread, ICorDebugMDA * pMDA) :
             ManagedEvent(pThread)
        {
            this->m_pController.Assign(pController);
            this->m_pThread.Assign(pThread);
            this->m_pMDA.Assign(pMDA);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback2()->MDANotification(m_pController, m_pThread, m_pMDA);
        }
    }; // end class MDANotificationEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new MDANotificationEvent(pController, pThread, pMDA));
    return S_OK;
} // end of methodICorDebugManagedCallback2::MDANotification

// Implementation of ICorDebugManagedCallback3::CustomNotification
// Arguments:
//      input:
//          pThread    - thread on which the notification occurred
//          pAppDomain - appDomain in which the notification occurred
// Return value: S_OK
HRESULT ShimProxyCallback::CustomNotification(ICorDebugThread * pThread, ICorDebugAppDomain * pAppDomain)
{
    m_pShim->PreDispatchEvent();
    class CustomNotificationEvent  : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugAppDomain > m_pAppDomain;
        RSExtSmartPtr<ICorDebugThread > m_pThread;

    public:
        // Ctor
        CustomNotificationEvent(ICorDebugThread * pThread, ICorDebugAppDomain * pAppDomain) :
          ManagedEvent(pThread)
          {
              this->m_pAppDomain.Assign(pAppDomain);
              this->m_pThread.Assign(pThread);
          }

          HRESULT Dispatch(DispatchArgs args)
          {
              return args.GetCallback3()->CustomNotification(m_pThread, m_pAppDomain);
          }
    }; // end class CustomNotificationEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new CustomNotificationEvent(pThread, pAppDomain));
    return S_OK;
}

// Implementation of ICorDebugManagedCallback4::BeforeGarbageCollection
// Arguments:
//      input:
//          pController - controller in which the notification occurred
// Return value: S_OK
HRESULT ShimProxyCallback::BeforeGarbageCollection(ICorDebugProcess* pProcess)
{
    m_pShim->PreDispatchEvent();
    class BeforeGarbageCollectionEvent : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess> m_pProcess;

    public:
        // Ctor
        BeforeGarbageCollectionEvent(ICorDebugProcess* pProcess) :
            ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback4()->BeforeGarbageCollection(m_pProcess);
        }
    }; // end class BeforeGarbageCollectionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new BeforeGarbageCollectionEvent(pProcess));
    return S_OK;
}

// Implementation of ICorDebugManagedCallback4::AfterGarbageCollection
// Arguments:
//      input:
//          pController - controller in which the notification occurred
// Return value: S_OK
HRESULT ShimProxyCallback::AfterGarbageCollection(ICorDebugProcess* pProcess)
{
    m_pShim->PreDispatchEvent();
    class AfterGarbageCollectionEvent : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess > m_pProcess;

    public:
        // Ctor
        AfterGarbageCollectionEvent(ICorDebugProcess* pProcess) :
            ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback4()->AfterGarbageCollection(m_pProcess);
        }
    }; // end class AfterGarbageCollectionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new AfterGarbageCollectionEvent(pProcess));
    return S_OK;
}

// Implementation of ICorDebugManagedCallback4::DataBreakpoint
// Arguments:
//      input:
//          pProcess - process in which the notification occurred
// Return value: S_OK
HRESULT ShimProxyCallback::DataBreakpoint(ICorDebugProcess* pProcess, ICorDebugThread* pThread, BYTE* pContext, ULONG32 contextSize)
{
    m_pShim->PreDispatchEvent();
    class DataBreakpointEvent : public ManagedEvent
    {
        // callbacks parameters. These are strong references
        RSExtSmartPtr<ICorDebugProcess> m_pProcess;
        RSExtSmartPtr<ICorDebugThread> m_pThread;
        CONTEXT m_context;
        ULONG32 m_contextSize;

    public:
        // Ctor
        DataBreakpointEvent(ICorDebugProcess* pProcess, ICorDebugThread* pThread, BYTE* pContext, ULONG32 contextSize) :
            ManagedEvent()
        {
            this->m_pProcess.Assign(pProcess);
            this->m_pThread.Assign(pThread);

            _ASSERTE(contextSize == sizeof(CONTEXT));
            this->m_contextSize = min(contextSize, sizeof(CONTEXT));
            memcpy(&(this->m_context), pContext, this->m_contextSize);
        }

        HRESULT Dispatch(DispatchArgs args)
        {
            return args.GetCallback4()->DataBreakpoint(m_pProcess, m_pThread, reinterpret_cast<BYTE*>(&m_context), m_contextSize);
        }
    }; // end class AfterGarbageCollectionEvent

    m_pShim->GetManagedEventQueue()->QueueEvent(new DataBreakpointEvent(pProcess, pThread, pContext, contextSize));
    return S_OK;
}
