CoreCLR Host源码分析(C++)

Posted tangyanzhi1111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CoreCLR Host源码分析(C++)相关的知识,希望对你有一定的参考价值。

  废话不多说,直接上源码:

 

1.在托管程序集里面执行方法


HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId,//通过CreateAppDomainWithManager创造的domainid
                                      LPCWSTR pwzAssemblyPath,//要托管的.net core DLL 路径
                                      int argc, //传递进来参数个数
                                      LPCWSTR* argv,//传递进来参数数组
                                      DWORD *pReturnValue)//指示函数执行的结果标记
{
    CONTRACTL
    {
        THROWS; // Throws...as we do not want it to swallow the managed exception
        ENTRY_POINT;
    }
    CONTRACTL_END;

    // This is currently supported in default domain only
    if (dwAppDomainId != DefaultADID) //如果不等于默认defaultADID 直接返回失败标记
        return HOST_E_INVALIDOPERATION;

    // No point going further if the runtime is not running...
    if (!IsRuntimeActive() || !m_fStarted) //如果 coreclr host 没有在运行或者m_fstarted标记没有被启动,返回失败标记
    {
        return HOST_E_CLRNOTAVAILABLE;
    }   
   
    if(!pwzAssemblyPath) //如果托管的DLL为空,返回
        return E_POINTER;

    if(argc < 0)//如果参数个数小于零,返回
    {
        return E_INVALIDARG;
    }

    if(argc > 0 && argv == NULL)//如果参数个数大于零且参数数组等于零,返回
    {
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK; //初始化hr

    AppDomain *pCurDomain = SystemDomain::GetCurrentDomain(); //获取到当前appdomain的实例

    Thread *pThread = GetThread(); //获取到当前进程指针
    if (pThread == NULL) //如果进程指针为零
    {
        pThread = SetupThreadNoThrow(&hr);
        if (pThread == NULL)
        {
            goto ErrExit;
        }
    }

    if(pCurDomain->GetId().m_dwId != DefaultADID)//如果当前进程的ID不等于defaultadid返回
    {
        return HOST_E_INVALIDOPERATION;
    }

    INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
    INSTALL_UNWIND_AND_CONTINUE_HANDLER;

    _ASSERTE (!pThread->PreemptiveGCDisabled());

    Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath); //加载传递过来的托管程序集,并且实例化

#if defined(FEATURE_MULTICOREJIT)
    pCurDomain->GetMulticoreJitManager().AutoStartProfile(pCurDomain);
#endif // defined(FEATURE_MULTICOREJIT)

    {
        GCX_COOP();

        // Here we call the managed method that gets the cmdLineArgs array.
        SetCommandLineArgs(pwzAssemblyPath, argc, argv);//设置命令行参数

        PTRARRAYREF arguments = NULL;
        GCPROTECT_BEGIN(arguments);

        arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass);//分配内存
        for (int i = 0; i < argc; ++i)
        {
            STRINGREF argument = StringObject::NewString(argv[i]);//转换参数
            arguments->SetAt(i, argument);//设置参数数组标记
        }

        DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /*waitForOtherThreads */); //执行需要托管的method
        if (pReturnValue) //如果返回标记不为空
        {
            *pReturnValue = retval;//赋值
        }

        GCPROTECT_END();

    }

    UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
    UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;

ErrExit: //如果错误,调到errexit ,返回HR

    return hr;
}

  

2.利用非托管加载程序集

Assembly *AssemblySpec::LoadAssembly(LPCWSTR pFilePath) // 传递托管程序集路径
{
    CONTRACT(Assembly *)
    {
        THROWS;
        GC_TRIGGERS;
        MODE_ANY;
        PRECONDITION(CheckPointer(pFilePath));
        POSTCONDITION(CheckPointer(RETVAL));
        INJECT_FAULT(COMPlusThrowOM(););
    }
    CONTRACT_END;

    AssemblySpec spec; //初始化assemblyspec 类
    spec.SetCodeBase(pFilePath); //设置类的托管程序集路径
    RETURN spec.LoadAssembly(FILE_LOADED); //设置类的加载方式为 文件加载
}

DomainAssembly *AssemblySpec::LoadDomainAssembly(FileLoadLevel targetLevel, //加载方式,为文件加载,另外三个参数都为空
                                                 BOOL fThrowOnFileNotFound,
                                                 BOOL fRaisePrebindEvents,
                                                 StackCrawlMark *pCallerStackMark)
{
    CONTRACT(DomainAssembly *)
    {
        INSTANCE_CHECK;
        THROWS;
        GC_TRIGGERS;
        MODE_ANY;
        POSTCONDITION((!fThrowOnFileNotFound && CheckPointer(RETVAL, NULL_OK))
                      || CheckPointer(RETVAL));
        INJECT_FAULT(COMPlusThrowOM(););
    }
    CONTRACT_END;
 
    ETWOnStartup (LoaderCatchCall_V1, LoaderCatchCallEnd_V1); //初始化一些宏定义
    AppDomain* pDomain = GetAppDomain(); //获取当前 appdomain 的实例


    DomainAssembly *pAssembly = nullptr; //声明并赋值一个 domainassembly

    ICLRPrivBinder * pBinder = GetHostBinder(); //获取到 iclrprivbinder 对象
    
    // If no binder was explicitly set, check if parent assembly has a binder.
    if (pBinder == nullptr) //如果 pbinder等于零
    {
        pBinder = GetBindingContextFromParentAssembly(pDomain); //获取到父类和注入的一些方法
    }


    if (pBinder != nullptr)//如果获取到了
    {
        ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
        HRESULT hrCachedResult;
        if (SUCCEEDED(pBinder->FindAssemblyBySpec(GetAppDomain(), this, &hrCachedResult, &pPrivAssembly)) &&
            SUCCEEDED(hrCachedResult))//用pbinder找到appdomain 的pprivassembly
        {
            pAssembly = pDomain->FindAssembly(pPrivAssembly);//利用找到的pprivassembly,pdomain调用然后赋值给要返回的程序集
        }
    }

    if ((pAssembly == nullptr) && CanUseWithBindingCache()) //如果为空
    {
        pAssembly = pDomain->FindCachedAssembly(this);//pdomain带上当前类的实例去缓存里面找当前的程序集
    }

    if (pAssembly)//如果找到
    {
        pDomain->LoadDomainFile(pAssembly, targetLevel); //以文件方式加载程序集
        RETURN pAssembly; //然后返回
    }


    PEAssemblyHolder pFile(pDomain->BindAssemblySpec(this, fThrowOnFileNotFound, fRaisePrebindEvents, pCallerStackMark));//如果上面所有步骤都不行,实例化一个peassemblyholder,
    if (pFile == NULL)
        RETURN NULL;

    pAssembly = pDomain->LoadDomainAssembly(this, pFile, targetLevel);//利用这个实例化的peassemblyholder和this指针,以及文件加载的方式去获取程序集

    RETURN pAssembly; //返回程序集
}

 

以上是关于CoreCLR Host源码分析(C++)的主要内容,如果未能解决你的问题,请参考以下文章

C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole

C++随笔:.NET CoreCLR之GC探索

Docker中使用createdump调试coreclr

聊一聊 C++ 中的 namespace

置顶CoreCLR系列随笔

C++随笔:.NET CoreCLR之GC探索