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; //返回程序集
}

原文地址:https://www.cnblogs.com/tangyanzhi1111/p/10616058.html

时间: 2024-08-06 03:41:39

CoreCLR Host源码分析(C++)的相关文章

Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类)

概述 Host 是应用程序域级的单例,代表了Orchard应用程序.其处理应用程序生命周期中的初始化.BeginRequest事件.EndRequest事件等. 可以简单理解为HttpApplication的功能转移到了Host身上.从源码角度上看,Host对应的是实现了IOrchardHost接口的 DefaultOrchardHost类. 回顾一下之前对Orchard.Web.MvcApplication类的分析.在Orchard启动时,会创建一个DefaultOrchardHost对象:

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A

Spark的Master和Worker集群启动的源码分析

基于spark1.3.1的源码进行分析 spark master启动源码分析 1.在start-master.sh调用master的main方法,main方法调用 def main(argStrings: Array[String]) { SignalLogger.register(log) val conf = new SparkConf val args = new MasterArguments(argStrings, conf) val (actorSystem, _, _, _) =

Hadoop之HDFS原理及文件上传下载源码分析(上)

HDFS原理 首先说明下,hadoop的各种搭建方式不再介绍,相信各位玩hadoop的同学随便都能搭出来. 楼主的环境: 操作系统:Ubuntu 15.10 hadoop版本:2.7.3 HA:否(随便搭了个伪分布式) 文件上传 下图描述了Client向HDFS上传一个200M大小的日志文件的大致过程: 首先,Client发起文件上传请求,即通过RPC与NameNode建立通讯. NameNode与各DataNode使用心跳机制来获取DataNode信息.NameNode收到Client请求后,

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html 在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup.在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解

spark core源码分析6 Spark job的提交

本节主要讲解SparkContext的逻辑 首先看一个spark自带的最简单的例子: object SparkPi { def main(args: Array[String]) { val conf = new SparkConf().setAppName("Spark Pi") val spark = new SparkContext(conf) val slices = if (args.length > 0) args(0).toInt else 2 val n = ma

Libevent源码分析-timer和signal处理

timer处理 Signal处理 timerfd和signalfd timerfd signalfd timer处理 在Libevent源码分析-event处理流程中,使用了定时器,来看一下源码: evtimer_set(&ev, time_cb, NULL);//设置定时器事件 其中evtimer_set是个宏定义 #define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) //event_set原型 void ev

Tomcat源码分析之—具体启动流程分析

从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息.Catalina.base信息,在initClassLoaders方法中初始化类加载器,然后通过反射初始化org.apache.catalina.startup.Catalina作为catalina守护进程: 一.load Bootstrap中load流程: 反射调用Catalina的load方法

storm操作zookeeper源码分析-cluster.clj

storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中).backtype.storm.cluster定义了两个重要protocol:ClusterState和StormClusterState.clojure中的protocol可以看成java中的接口,封装了一组方法.ClusterState协议中封装了一组与zookeeper进行交互的基础函数,如获取子节点函数,获取子节点数据函数等,ClusterState协