Click here to Skip to main content
15,892,809 members
Articles / Programming Languages / MSIL

ILRewriting for beginners

Rate me:
Please Sign up or sign in to vote.
4.56/5 (15 votes)
27 Sep 2012Ms-PL11 min read 62.3K   1.4K   46  
Runtime IL-Rewriting can be used to add behavior such as logging to applications, or redirect calls from one API to another. This article and accompanying source code explains how to substitute a method call at runtime.
// ----------------------------------------------------------------------------------------------
// Copyright (c) Mattias H�gstr�m.
// ----------------------------------------------------------------------------------------------
// This source code is subject to terms and conditions of the Microsoft Public License. A 
// copy of the license can be found in the License.html file at the root of this distribution. 
// If you cannot locate the Microsoft Public License, please send an email to 
// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
// by the terms of the Microsoft Public License.
// ----------------------------------------------------------------------------------------------
// You must not remove this notice, or any other, from this software.
// ----------------------------------------------------------------------------------------------


#include "stdafx.h"
#include <string>
#include "ILRewriteProfilerImpl.h"
#include "StringHelper.h"
#include "ProfilerLoggers.h"
#include "ILRewriter.h"
#include "FunctionInfo.h"
#include "OpCodeParser.h"
#include "MetadataHelper.h"
#include "InterceptAPI.h"

//#include "ILRewriteConsoleLogger.h"
//#include "ILRewriteDebugLogger.h"

#include <wchar.h>
#include <corhlpr.h>
#include <memory>

#pragma comment(lib, "CorGuids.lib")


CRITICAL_SECTION g_cs_ilRewite;


void ILRewriteProfilerImpl::Check(HRESULT hr)
{
   if (hr != S_OK)
      throw "HRESULT is != S_OK";
}

HRESULT ILRewriteProfilerImpl::SetEventMask()
{
   //COR_PRF_MONITOR_NONE	= 0,
   //COR_PRF_MONITOR_FUNCTION_UNLOADS	= 0x1,
   //COR_PRF_MONITOR_CLASS_LOADS	= 0x2,
   //COR_PRF_MONITOR_MODULE_LOADS	= 0x4,
   //COR_PRF_MONITOR_ASSEMBLY_LOADS	= 0x8,
   //COR_PRF_MONITOR_APPDOMAIN_LOADS	= 0x10,
   //COR_PRF_MONITOR_JIT_COMPILATION	= 0x20,
   //COR_PRF_MONITOR_EXCEPTIONS	= 0x40,
   //COR_PRF_MONITOR_GC	= 0x80,
   //COR_PRF_MONITOR_OBJECT_ALLOCATED	= 0x100,
   //COR_PRF_MONITOR_THREADS	= 0x200,
   //COR_PRF_MONITOR_REMOTING	= 0x400,
   //COR_PRF_MONITOR_CODE_TRANSITIONS	= 0x800,
   //COR_PRF_MONITOR_ENTERLEAVE	= 0x1000,
   //COR_PRF_MONITOR_CCW	= 0x2000,
   //COR_PRF_MONITOR_REMOTING_COOKIE	= 0x4000 | COR_PRF_MONITOR_REMOTING,
   //COR_PRF_MONITOR_REMOTING_ASYNC	= 0x8000 | COR_PRF_MONITOR_REMOTING,
   //COR_PRF_MONITOR_SUSPENDS	= 0x10000,
   //COR_PRF_MONITOR_CACHE_SEARCHES	= 0x20000,
   //COR_PRF_MONITOR_CLR_EXCEPTIONS	= 0x1000000,
   //COR_PRF_MONITOR_ALL	= 0x107ffff,
   //COR_PRF_ENABLE_REJIT	= 0x40000,
   //COR_PRF_ENABLE_INPROC_DEBUGGING	= 0x80000,
   //COR_PRF_ENABLE_JIT_MAPS	= 0x100000,
   //COR_PRF_DISABLE_INLINING	= 0x200000,
   //COR_PRF_DISABLE_OPTIMIZATIONS	= 0x400000,
   //COR_PRF_ENABLE_OBJECT_ALLOCATED	= 0x800000,

   // New in VS2005
   //COR_PRF_ENABLE_FUNCTION_ARGS	= 0x2000000,
   //COR_PRF_ENABLE_FUNCTION_RETVAL	= 0x4000000,
   //COR_PRF_ENABLE_FRAME_INFO	= 0x8000000,
   //COR_PRF_ENABLE_STACK_SNAPSHOT	= 0x10000000,
   //COR_PRF_USE_PROFILE_IMAGES	= 0x20000000,
   // End New in VS2005

   //COR_PRF_ALL	= 0x3fffffff,
   //COR_PRF_MONITOR_IMMUTABLE	= COR_PRF_MONITOR_CODE_TRANSITIONS | COR_PRF_MONITOR_REMOTING | COR_PRF_MONITOR_REMOTING_COOKIE | COR_PRF_MONITOR_REMOTING_ASYNC | COR_PRF_MONITOR_GC | COR_PRF_ENABLE_REJIT | COR_PRF_ENABLE_INPROC_DEBUGGING | COR_PRF_ENABLE_JIT_MAPS | COR_PRF_DISABLE_OPTIMIZATIONS | COR_PRF_DISABLE_INLINING | COR_PRF_ENABLE_OBJECT_ALLOCATED | COR_PRF_ENABLE_FUNCTION_ARGS | COR_PRF_ENABLE_FUNCTION_RETVAL | COR_PRF_ENABLE_FRAME_INFO | COR_PRF_ENABLE_STACK_SNAPSHOT | COR_PRF_USE_PROFILE_IMAGES

   // set the event mask 
   //DWORD eventMask = (DWORD)(COR_PRF_MONITOR_ENTERLEAVE);
   DWORD eventMask = COR_PRF_MONITOR_NONE;
   //eventMask |= COR_PRF_MONITOR_THREADS; // create / delete thread
   eventMask |= COR_PRF_MONITOR_JIT_COMPILATION;
   //eventMask |= COR_PRF_MONITOR_MODULE_LOADS;
   //
   //eventMask |= COR_PRF_MONITOR_CODE_TRANSITIONS;
   //eventMask |= COR_PRF_MONITOR_SUSPENDS;

   // eventMask |= COR_PRF_ENABLE_STACK_SNAPSHOT;
   // eventMask |= COR_PRF_MONITOR_SUSPENDS;
   eventMask |= COR_PRF_DISABLE_INLINING;
   eventMask |= COR_PRF_DISABLE_OPTIMIZATIONS;
   //	eventMask | = COR_PRF_MONITOR_IMMUTABLE;

   return m_corProfilerInfo->SetEventMask(eventMask);
}


STDMETHODIMP ILRewriteProfilerImpl::QueryInterface(
   REFIID riid , 
   void **ppObj)
{
   LPOLESTR clsid = nullptr;

   HRESULT hr = StringFromCLSID(riid, &clsid);
   if (SUCCEEDED(hr))
   {
      std::wstring clsidString(clsid);
      g_debugLogger << "ILRewriteProfilerImpl::QueryInterface(" << ConvertStlString(clsidString).c_str() << ")" << std::endl;
      ::CoTaskMemFree(clsid);
   }
   if (riid == IID_IUnknown)
   {
      *ppObj = this; 
      AddRef() ;
      g_debugLogger.WriteLine("QueryInterface -> IUnknown");
      return S_OK;
   }

   if (riid == IID_ILRewriteProfiler)
   {
      *ppObj = static_cast<ILRewriteProfiler*>(this) ;
      AddRef() ;
      g_debugLogger.WriteLine("QueryInterface -> IDiagProfiler");
      return S_OK;
   }

   if (riid == IID_ICorProfilerCallback)
   {
      *ppObj = static_cast<ICorProfilerCallback*>(this) ;
      AddRef() ;
      g_debugLogger.WriteLine("QueryInterface -> ICorProfilerCallback");
      return S_OK;
   }

   if (riid == IID_ICorProfilerCallback2)
   {
      *ppObj = static_cast<ICorProfilerCallback2*>(this) ;
      AddRef();
      g_debugLogger.WriteLine("QueryInterface -> ICorProfilerCallback2");
      return S_OK;
   }

   if (riid == IID_ICorProfilerCallback3)
   {
      *ppObj = dynamic_cast<ICorProfilerCallback3*>(this) ;
      AddRef();
      g_debugLogger.WriteLine("QueryInterface -> ICorProfilerCallback");
      return S_OK;
   }

   if (riid == IID_ICorProfilerInfo)
   {
      g_debugLogger.WriteLine("QueryInterface -> ICorProfilerInfo");
      *ppObj = m_corProfilerInfo;
      return S_OK;
   }

   if (riid == IID_ICorProfilerInfo2)
   {
      g_debugLogger.WriteLine("QueryInterface -> ICorProfilerInfo2");
      *ppObj = m_corProfilerInfo2;
      return S_OK;
   }

   *ppObj = NULL ;
   g_debugLogger.WriteLine("QueryInterface -> E_NOINTERFACE");
   return E_NOINTERFACE ;
}

ULONG STDMETHODCALLTYPE ILRewriteProfilerImpl::AddRef()
{
   return InterlockedIncrement(&m_nRefCount) ;
}

ULONG STDMETHODCALLTYPE ILRewriteProfilerImpl::Release()
{     
   long nRefCount=0;
   nRefCount=InterlockedDecrement(&m_nRefCount) ;
   if (nRefCount == 0) 
   {
      g_debugLogger.Close();
   }
   return nRefCount;
}

STDMETHODIMP ILRewriteProfilerImpl::ProfilerAttachComplete(void)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ProfilerDetachSucceeded(void)
{
   return S_OK;
};

STDMETHODIMP ILRewriteProfilerImpl::InitializeForAttach( 
   /* [in] */ IUnknown *pCorProfilerInfoUnk,
   /* [in] */ void *pvClientData,
   /* [in] */ UINT cbClientData)
{
   return S_OK;
}

//
// Called when a profiler is attached using environment variables
//
STDMETHODIMP ILRewriteProfilerImpl::Initialize(IUnknown *pICorProfilerInfoUnk)
{
   g_debugLogger.WriteLine("ILRewriteProfilerImpl::Initialize()");

   // get the ICorProfilerInfo interface
   HRESULT hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo, (LPVOID*)&m_corProfilerInfo);
   if (FAILED(hr))
   {
      g_debugLogger.WriteLine("Error: Failed to get ICorProfilerInfo");
      return E_FAIL;
   }
   else
   {
      g_debugLogger.WriteLine("Got ICorProfilerInfo");
   }

   hr = pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo2, (LPVOID*)&m_corProfilerInfo2);
   if (FAILED(hr))
   {
      m_corProfilerInfo2 = nullptr;
      g_debugLogger.WriteLine("Error: Failed to get ICorProfiler2");
   }
   else
   {
      g_debugLogger.WriteLine("Got ICorProfilerInfo2");
   }

   // Tell the profiler API which events we want to listen to
   // Some events fail when we attach afterwards

   hr = SetEventMask();
   if (FAILED(hr))
   {
      g_debugLogger.WriteLine("Error: Failed to set event mask");
   }
   else
   {
      g_debugLogger.WriteLine("SetEventMask()");
   }

   g_debugLogger.WriteLine("Successfully initialized profiling");
   
   
   //g_debugLogger.WriteLine("Deactivating echo to OutputDebug");
   

   // We do not need echo to OutputDebugString
   //g_profilerData.m_debugLogger.Echo2OutputDebug(false);

   m_rewritehelper.SetCorProfilerInfo(m_corProfilerInfo);
   InitializeCriticalSection(&g_cs_ilRewite);
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ThreadAssignedToOSThread(ThreadID managedThreadID, DWORD osThreadID) 
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::Shutdown()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AppDomainCreationStarted(AppDomainID appDomainID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AppDomainCreationFinished(AppDomainID appDomainID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AppDomainShutdownStarted(AppDomainID appDomainID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AppDomainShutdownFinished(AppDomainID appDomainID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AssemblyLoadStarted(AssemblyID assemblyID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AssemblyLoadFinished(AssemblyID assemblyID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AssemblyUnloadStarted(AssemblyID assemblyID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::AssemblyUnloadFinished(AssemblyID assemblyID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ModuleLoadStarted(ModuleID moduleID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ModuleLoadFinished(ModuleID moduleID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ModuleUnloadStarted(ModuleID moduleID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ModuleUnloadFinished(ModuleID moduleID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ModuleAttachedToAssembly(ModuleID moduleID, AssemblyID assemblyID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ClassLoadStarted(ClassID classID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ClassLoadFinished(ClassID classID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ClassUnloadStarted(ClassID classID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ClassUnloadFinished(ClassID classID, HRESULT hrStatus)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::FunctionUnloadStarted(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::JITCompilationStarted(FunctionID functionID, BOOL fIsSafeToBlock)
{
   EnterCriticalSection(&g_cs_ilRewite);

   std::ostringstream o;
   o << "ILRewriteProfilerImpl::JITCompilationStarted(";
   o << functionID;
   o << ")" << std::endl;
   std::string msg = o.str();
   g_debugLogger << msg.c_str();

   FunctionInfo* functionInfo = m_rewritehelper.CreateFunctionInfo(functionID);
   if (!functionInfo->IsValid())
      return S_OK;


   //ILRewriteDebugLogger ilDebugLogger = ILRewriteDebugLogger(m_corProfilerInfo, functionInfo);

   std::auto_ptr<ILRewriter> rewriter(m_rewritehelper.CreateILRewriter(nullptr /*&ilDebugLogger*/, functionInfo));
   if (rewriter->CanRewrite())
   {
      // Add Prelude
      // g_debugLogger code writes to OutputDebug
      // Use DebugView.exe to see the logs

      ULONG oldSize = rewriter->GetOldMethodSize();
      LPCBYTE oldBytes = rewriter->GetOldMethodBytes();
      std::string hexStringOldBytes = PrintHex(oldBytes, oldSize);
      g_debugLogger << "Old ILBytes " << hexStringOldBytes << std::endl;
      g_debugLogger << "CanRewrite == True" << std::endl;
      LPBYTE newBytes = (LPBYTE) rewriter->GetNewILBytes();
      ULONG newSize = rewriter->GetNewMethodSize();
      std::string hexStringNewBytes = PrintHex(newBytes, newSize);
      g_debugLogger << "New ILBytes " << hexStringNewBytes << std::endl;

      {
         // Replace calls to DateTime.Now
         // This is just a reference sample
         // It is easy to replace methods with other methods having the exact same signature
         // It is just a question of changing the "function pointer", the mdMemberRef token

         COR_ILMETHOD_TINY* tiny = reinterpret_cast<COR_ILMETHOD_TINY*>(newBytes);
         ULONG codeSize = 0;
         BYTE* codeOffset = nullptr;
         if (tiny->IsTiny())
         {
            codeSize = tiny->GetCodeSize();
            codeOffset = tiny->GetCode();
         }
         else
         {
            COR_ILMETHOD_FAT* fat =  reinterpret_cast<COR_ILMETHOD_FAT*>(newBytes);
            codeSize = fat->CodeSize;
            codeOffset = fat->GetCode();
         }

         ULONG replaceCount = InterceptAPI::ReplaceDateTimeNowCalls(m_corProfilerInfo, functionInfo->GetModuleID(), codeOffset, codeSize);
         if (replaceCount != 0)
         {
            g_debugLogger << "Replaced DateTime::Now #" << replaceCount << " times" << std::endl;
         }
      }
         
      Check(m_corProfilerInfo->SetILFunctionBody(functionInfo->GetModuleID(), functionInfo->GetToken(), newBytes));
   }
   else
   {
      g_debugLogger << "CanRewrite == False" << std::endl;
   }
   LeaveCriticalSection(&g_cs_ilRewite);
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::JITCompilationFinished(FunctionID functionID, HRESULT hrStatus, BOOL fIsSafeToBlock)
{
   std::ostringstream o;
   o << "ILRewriteProfilerImpl::JITCompilationFinished(";
   o << functionID;
   o << ")" << std::endl << std::endl;
   std::string msg = o.str();
   g_debugLogger << msg.c_str();
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::JITCachedFunctionSearchStarted(FunctionID functionID, BOOL *pbUseCachedFunction)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::JITCachedFunctionSearchFinished(FunctionID functionID, COR_PRF_JIT_CACHE result)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::JITFunctionPitched(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::JITInlining(FunctionID callerID, FunctionID calleeID, BOOL *pfShouldInline)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::UnmanagedToManagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ManagedToUnmanagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ThreadCreated(ThreadID threadID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ThreadDestroyed(ThreadID threadID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingClientInvocationStarted()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingClientReceivingReply(GUID *pCookie, BOOL fIsAsync)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingClientInvocationFinished()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingServerInvocationStarted()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingServerInvocationReturned()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeSuspendFinished()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeSuspendAborted()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeResumeStarted()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeResumeFinished()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeThreadSuspended(ThreadID threadID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RuntimeThreadResumed(ThreadID threadID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::MovedReferences(ULONG cmovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], ULONG cObjectIDRangeLength[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ObjectAllocated(ObjectID objectID, ClassID classID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ObjectsAllocatedByClass(ULONG classCount, ClassID classIDs[], ULONG objects[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ObjectReferences(ObjectID objectID, ClassID classID, ULONG objectRefs, ObjectID objectRefIDs[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RootReferences(ULONG rootRefs, ObjectID rootRefIDs[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionThrown(ObjectID thrownObjectID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionUnwindFunctionEnter(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionUnwindFunctionLeave()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionSearchFunctionEnter(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionSearchFunctionLeave()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionSearchFilterEnter(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionSearchFilterLeave()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionSearchCatcherFound(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionCLRCatcherFound()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionCLRCatcherExecute()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionOSHandlerEnter(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionOSHandlerLeave(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionUnwindFinallyEnter(FunctionID functionID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionUnwindFinallyLeave()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionCatcherEnter(FunctionID functionID,
   ObjectID objectID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ExceptionCatcherLeave()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::COMClassicVTableCreated(ClassID wrappedClassID, REFGUID implementedIID, void *pVTable, ULONG cSlots)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::COMClassicVTableDestroyed(ClassID wrappedClassID, REFGUID implementedIID, void *pVTable)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::ThreadNameChanged(ThreadID threadID, ULONG cchName, WCHAR name[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::SurvivingReferences(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], ULONG cObjectIDRangeLength[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::GarbageCollectionFinished()
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::FinalizeableObjectQueued(DWORD finalizerFlags, ObjectID objectID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::RootReferences2(ULONG cRootRefs, ObjectID rootRefIDs[], COR_PRF_GC_ROOT_KIND rootKinds[], COR_PRF_GC_ROOT_FLAGS rootFlags[], UINT_PTR rootIDs[])
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::HandleCreated(GCHandleID handleID, ObjectID initialObjectID)
{
   return S_OK;
}

STDMETHODIMP ILRewriteProfilerImpl::HandleDestroyed(GCHandleID handleID)
{
   return S_OK;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Architect Visma Software AB
Sweden Sweden
Mattias works at Visma, a leading Nordic ERP solution provider. He has good knowledge in C++/.Net development, test tool development, and debugging. His great passion is memory dump analysis. He likes giving talks and courses.

Comments and Discussions