Share via


Sample Code to invoke managed code inside profiling API

ProfilerCallback.cpp

// This is the function that will invoke the managed code through COM interop on another thread

// this function creates the CCW object

// [in] this pointer
DWORD WINAPI CreateManagedStub(LPVOID lpParam)
{
    _ManagedStub * pIManagedStub = NULL;
    HRESULT hr = CoCreateInstance(CLSID_ManagedStub, NULL, CLSCTX_INPROC_SERVER, IID__ManagedStub, (void **)&pIManagedStub); 
    if (FAILED(hr))
    {
        printf("Fail to CoCreateInstance on ManagedStub class 0x%x\n", hr);
        return 1;
    }
    if (pIManagedStub == NULL)
    {
        printf("pIManagedStub is null 0x%x\n", hr);
        return 1;
    }

    // we have the managed instance now.
    ((CProfilerCallback*)lpParam)->m_pIManagedStub = pIManagedStub;
    return 0;
}

// this function is the actual caller to the managed world. 
// this function can be used to get a managed dynamic method token back
// [in] this pointer; method token; assembly name
// [out] delegate type name
DWORD WINAPI ManagedPreStub(LPVOID lpParam)
{
    PMYDATA pData = (PMYDATA)lpParam;
    LPWSTR delegateName = NULL;
    if (pData->thisObj->m_pIManagedStub == NULL)
    {
        printf("pData->thisObj->m_pIManagedStub is null");
        return 1;
    }
    HRESULT hr = pData->thisObj->m_pIManagedStub->PreStub(pData->assemblyName, pData->methodTk, &delegateName);
    if (FAILED(hr))
    {
        printf("Fail to Call PreStub 0x%x\n", hr);
    }
    wcscpy_s(pData->delegateName, (wchar_t*)delegateName);
    return 0;
   
}

......

// Profiler callback function

HRESULT CProfilerCallback::JITCompilationStarted(UINT functionId,
                                                BOOL fIsSafeToBlock)
{
    HANDLE hThread = NULL;
    DWORD dwThreadId;
    /////////////////////////////////////////////////////////
    // We dont want to continue on JITCompilationStarted if the thread is for the "managed code" we are to call from this callback.

    // We store these thread ids in our skip thread hashtable

    // 1. if the JITCompilationStarted is on one of the skipping thread, avoid following steps.
    DWORD currentThreadId = GetCurrentThreadId();
    if (m_SkipJCHashTable->PLookup(currentThreadId))
        return S_OK;

    // create the ManagedStub object
    if (m_pIManagedStub==NULL) // if it is already created, no need to create twice
    {
        hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateManagedStub, this, 0, &dwThreadId);

       // add the thread Id to skip pool so that JITCompilationStarted will do nothing on that thread. 

       m_SkipJCHashTable->SetAt(dwThreadId, 0);  
        if (hThread != NULL)
        {
            WaitForSingleObject(hThread, INFINITE);
            CloseHandle(hThread);
        }
        m_SkipJCHashTable->RemoveKey(dwThreadId);  
    }

....

    ///////////////////////////////////////////////////////
    // try to define a managed dynamic method and get the dynamic method method token
    // prepare the parameters to be passed in
    PMYDATA pData = (PMYDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MYDATA));

    if( pData == NULL )
            goto exit;

    pData->assemblyName = wszAssemblyName;
    pData->methodTk = tkMethod;
    pData->thisObj = this;

    ProfilerPrintf("Working on asm %ws func %ws.", wszAssemblyName, wszFunctionName);
  
    hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ManagedPreStub, pData, 0, &dwThreadId);
    m_SkipJCHashTable->SetAt(dwThreadId, 0);  
    if (hThread != NULL)
    {
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);
    }
    m_SkipJCHashTable->RemoveKey(dwThreadId);

    // we free up the memory here instead of in the thread because we want some return value back.
    wchar_t wszDelegateName[512];

    if (pData->delegateName == NULL)
        return S_OK;
    // copy the return value out
    wcsncpy_s(wszDelegateName, _countof(pData->delegateName), pData->delegateName, _countof(pData->delegateName));

    HeapFree(GetProcessHeap(), 0, pData);

...

We have these definitions in ProfilerCallback.h:

private:

    CMap<DWORD, DWORD, int, int> * m_SkipJCHashTable;

      ...

    Enjoy!