在定制 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;// 标志是否成功
- }
来源: https://www.cnblogs.com/tangyanzhi1111/p/10594812.html