在定制 CLR Host的时候,可以通过调用如下代码,来获取当前需要被宿主的程序调用入口:
hr = Host->CreateDelegate( domainId, L"Main,Version=1.0.0.0", L"Main.Program", // Target managed type L"Main", // Target entry point (static method) (INT_PTR*)&pfnDelegate);
CreateDelegate 会进入到corhost.cpp里面
HRESULT CorHost2::CreateDelegate( DWORD appDomainID, LPCWSTR wszAssemblyName, LPCWSTR wszClassName, LPCWSTR wszMethodName, INT_PTR* fnPtr) { WRAPPER_NO_CONTRACT; return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, wszMethodName, fnPtr); }
然后_CreateDelegate 会CorHost2::_CreateDelegate,这个函数里面首先实例化了一个AssemblySpec,然后用传递过来的程序集名称初始化,通过AssemblySpec的LoadfAssembly实例化程序集。
获取程序集的类加载器,通过类加载器加载TypeHandle,传递的参数分别为程序集实例和ClassName。然后再通过MemberLoader::FindMethodByName获取到类里面的所需要查找的方法。
通过AppDomain的GetUMEntryThunkCache函数返回UMEntryThunk,最后通过UMEntryThunk->GetCode()返回要查找的函数指针。代码如下:
HRESULT CorHost2::_CreateDelegate( DWORD appDomainID, LPCWSTR wszAssemblyName, LPCWSTR wszClassName, LPCWSTR wszMethodName, INT_PTR* fnPtr) { CONTRACTL { NOTHROW; if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} ENTRY_POINT; // This is called by a host. } CONTRACTL_END; HRESULT hr=S_OK; EMPTY_STRING_TO_NULL(wszAssemblyName); EMPTY_STRING_TO_NULL(wszClassName); EMPTY_STRING_TO_NULL(wszMethodName); if (fnPtr == NULL) return E_POINTER; *fnPtr = NULL; if(wszAssemblyName == NULL) return E_INVALIDARG; if(wszClassName == NULL) return E_INVALIDARG; if(wszMethodName == NULL) return E_INVALIDARG; if (!m_fStarted) return HOST_E_INVALIDOPERATION; BEGIN_ENTRYPOINT_NOTHROW; BEGIN_EXTERNAL_ENTRYPOINT(&hr); GCX_COOP_THREAD_EXISTS(GET_THREAD()); MAKE_UTF8PTR_FROMWIDE(szAssemblyName, wszAssemblyName); MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName); MAKE_UTF8PTR_FROMWIDE(szMethodName, wszMethodName); ADID id; id.m_dwId=appDomainID;//获取appdomid,通过CreateAppDomainWithManager函数来获取的 ENTER_DOMAIN_ID(id) GCX_PREEMP(); AssemblySpec spec; //实例化一个 AssemblySpec类 spec.Init(szAssemblyName); //用传递过来的程序集名称初始化这类 Assembly* pAsm=spec.LoadAssembly(FILE_ACTIVE);//加载此程序集,返回程序集实例 TypeHandle th=pAsm->GetLoader()->LoadTypeByNameThrowing(pAsm,NULL,szClassName);//获取到程序集的类加载器加载实例TypeHandle 并返回 MethodDesc* pMD=NULL; if (!th.IsTypeDesc()) { pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Unique);//通过typehandle的方法表以及传递过来的方法名称,获取到方法描述类methoddesc if (pMD == NULL) { // try again without the FM_Unique flag (error path) pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Default); if (pMD != NULL) { // the method exists but is overloaded ThrowHR(COR_E_AMBIGUOUSMATCH); } } } if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables()) ThrowHR(COR_E_MISSINGMETHOD); UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);//通过 appdomain 的 getumeentrythunk函数获取到umeentrythunk *fnPtr = (INT_PTR)pUMEntryThunk->GetCode(); //通过上面获取的 umentrythunk类调用参数getcode ,赋值给传递过来的需要的函数指针参数 END_DOMAIN_TRANSITION; END_EXTERNAL_ENTRYPOINT; END_ENTRYPOINT_NOTHROW; return hr;//标志是否成功 }