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

  这篇文章是上篇的续集,本文将会继续介绍coreconsole.cpp里面的逻辑。也许大家会看一些CLR的书,我承认我没有看过,因为我觉得一个人,他再NB,那也是他自己的眼光,而且说句难听的,CLR也不是那个写书的人一个人完成的项目,所以他的眼光,我个人看来,也还是很有限的。

  承接上篇文章的HostEnvironment,宿主环境:个人认为HOST是指的Windows内核。但是CLR有一个缺点,就是它并不是一个跨平台的,所以广义的说HOST应该是“操作系统内核”;下面我们来看看LoadCoreCLR这个方法,这个方法的核心宗旨就是从动态链接库当中得到CLR,如果出错,会记日志;

//尝试去“载入”CoreCLR,它带有一个coreCLR的路径
    HMODULE TryLoadCoreCLR(const wchar_t* directoryPath) {

		//coreclr 路径
        wchar_t coreCLRPath[MAX_LONGPATH];
		//把形参赋给实参,也就是相当于coreCLRPath= directoryPath
        wcscpy_s(coreCLRPath, directoryPath);
		//把coreCLRDll,append到coreCLRPathd的后面,组成一个新的字符串
        wcscat_s(coreCLRPath, coreCLRDll);

		//日志记录开始:尝试从路径载入CoreCLR
        *m_log << W("Attempting to load: ") << coreCLRPath << Logger::endl;

		//LoadLibraryEx装载指定的动态链接库。
        HMODULE result = ::LoadLibraryExW(coreCLRPath, NULL, 0);

		//载入失败的时候,记录日志
        if (!result) {
            *m_log << W("Failed to load: ") << coreCLRPath << Logger::endl;
            *m_log << W("Error code: ") << GetLastError() << Logger::endl;
            return nullptr;
        }

        // Pin the module - CoreCLR.dll does not support being unloaded.

		//GetModuleHandleExW是获取一个应用程序或动态链接库的模块句柄
        HMODULE dummy_coreCLRModule;

		//如果是GET_MODULE_HANDLE_EX_FLAG_PIN,则模块一直映射在调用该函数的进程中,直到该进程结束
        if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, coreCLRPath, &dummy_coreCLRModule)) {
            *m_log << W("Failed to pin: ") << coreCLRPath << Logger::endl;
            return nullptr;
        }

        wchar_t coreCLRLoadedPath[MAX_LONGPATH];
        ::GetModuleFileNameW(result, coreCLRLoadedPath, MAX_LONGPATH);

        *m_log << W("Loaded: ") << coreCLRLoadedPath << Logger::endl;

		//返回动态链接库
        return result;
    }

  下面是HostEnvironment的构造函数,个人觉得主要的作用还是初始化,载入CoreCLR.

public:
    // The path to the directory that CoreCLR is in
	//CoreCLR的路径,注意区分“模块路径”和此路径的区别
    wchar_t m_coreCLRDirectoryPath[MAX_LONGPATH];

	//带有log参数的构造函数,并初始化LOG和CLR运行时
    HostEnvironment(Logger *logger)
        : m_log(logger), m_CLRRuntimeHost(nullptr) {

            // Discover the path to this exe‘s module. All other files are expected to be in the same directory.
			//获得目录下EXE模块的路径的长度
            DWORD thisModuleLength = ::GetModuleFileNameW(::GetModuleHandleW(nullptr), m_hostPath, MAX_LONGPATH);

            // Search for the last backslash in the host path.

			//寻找路径当中的最后一个分隔符"\\",如果找到了,就跳出循环
            int lastBackslashIndex;
            for (lastBackslashIndex = thisModuleLength-1; lastBackslashIndex >= 0; lastBackslashIndex--) {
                if (m_hostPath[lastBackslashIndex] == W(‘\\‘)) {
                    break;
                }
            }

            // Copy the directory path

			//用m_hostDirectoryPath代替之前的路径目录的地址
            ::wcsncpy_s(m_hostDirectoryPath, m_hostPath, lastBackslashIndex + 1);

            // Save the exe name
			//host 的EXE文件的名字,类似文件名,不过这里我有一个疑问:
			//m_hostPath是一个字符型的指针,而lastBackslashIndex+1是数字,把它们2个加起来是什么意思?
            m_hostExeName = m_hostPath + lastBackslashIndex + 1;

            *m_log << W("Host directory: ")  << m_hostDirectoryPath << Logger::endl;

            // Check for %CORE_ROOT% and try to load CoreCLR.dll from it if it is set
			//尝试从环境变量%CORE_ROOT%载入CoreCLR

			//coreRoot环境变量真实路径
            wchar_t coreRoot[MAX_LONGPATH];
            size_t outSize;

			//如果没有使用TryLoadCoreCLR方法的话,那么采用构造函数方式去初始化CoreCLR.
			m_coreCLRModule = NULL; // Initialize this here since we don‘t call TryLoadCoreCLR if CORE_ROOT is unset.

			//取环境变量的值
            if (_wgetenv_s(&outSize, coreRoot, MAX_LONGPATH, W("CORE_ROOT")) == 0 && outSize > 0)
            {
                wcscat_s(coreRoot, MAX_LONGPATH, W("\\"));
                m_coreCLRModule = TryLoadCoreCLR(coreRoot);
            }
            else
            {
                *m_log << W("CORE_ROOT not set; skipping") << Logger::endl;
                *m_log << W("You can set the environment variable CORE_ROOT to point to the path") << Logger::endl;
                *m_log << W("where CoreCLR.dll lives to help this executable find it.") << Logger::endl;
            }

            // Try to load CoreCLR from the directory that this exexutable is in
			//从"目录"中尝试载入CoreCLR.
            if (!m_coreCLRModule) {
                m_coreCLRModule = TryLoadCoreCLR(m_hostDirectoryPath);
            }

			//作用同上(thisModuleLength)
            if (m_coreCLRModule) {

                // Save the directory that CoreCLR was found in
                DWORD modulePathLength = ::GetModuleFileNameW(m_coreCLRModule, m_coreCLRDirectoryPath, MAX_LONGPATH);

                // Search for the last backslash and terminate it there to keep just the directory path with trailing slash
                for (lastBackslashIndex = modulePathLength-1; lastBackslashIndex >= 0; lastBackslashIndex--) {
                    if (m_coreCLRDirectoryPath[lastBackslashIndex] == W(‘\\‘)) {
                        m_coreCLRDirectoryPath[lastBackslashIndex + 1] = W(‘\0‘);
                        break;
                    }
                }

            } else {
                *m_log << W("Unable to load ") << coreCLRDll << Logger::endl;
            }
    }

	//析构函数,释放coreclr
    ~HostEnvironment() {
        if(m_coreCLRModule) {
            // Free the module. This is done for completeness, but in fact CoreCLR.dll
            // was pinned earlier so this call won‘t actually free it. The pinning is
            // done because CoreCLR does not support unloading.
            ::FreeLibrary(m_coreCLRModule);
        }
    }

  下面是判断TPA列表里面的项是否有包含文件,具体作用不详。

//TPA列表的每个项是否包含文件,至少有一项是包含文件的,那么返回TRUE
	//fileNameWithoutExtension:不带后缀的文件名
	//rgTPAExtensions:TPA后缀,注意这里是一个指针的指针。
	//countExtensions:后缀个数
    bool TPAListContainsFile(wchar_t* fileNameWithoutExtension, wchar_t** rgTPAExtensions, int countExtensions)
    {
        if (!m_tpaList.CStr()) return false;//如果程序集路径为空,直接返回FALSE

		//循环后缀。
        for (int iExtension = 0; iExtension < countExtensions; iExtension++)
        {
            wchar_t fileName[MAX_LONGPATH];
			// So that we don‘t match other files that end with the current file name
			//不匹配其他文件结尾(和当前文件名对比)
            wcscpy_s(fileName, MAX_LONGPATH, W("\\")); 

			//wcscat_s函数,把第三个参数添加都第一个参数的结尾
            wcscat_s(fileName, MAX_LONGPATH, fileNameWithoutExtension);
            wcscat_s(fileName, MAX_LONGPATH, rgTPAExtensions[iExtension] + 1);
            wcscat_s(fileName, MAX_LONGPATH, W(";")); // So that we don‘t match other files that begin with the current file name

			//类似于.NET中的Contains
            if (wcsstr(m_tpaList.CStr(), fileName))
            {
                return true;
            }
        }
        return false;
    }

  下面的方法是移除文件后缀的,应该是一个工具类

	//移除文件后缀
    void RemoveExtensionAndNi(wchar_t* fileName)
    {
        // Remove extension, if it exists
		//如果文件存在后缀,那么久移除
        wchar_t* extension = wcsrchr(fileName, W(‘.‘));
        if (extension != NULL)
        {
            extension[0] = W(‘\0‘);

            // Check for .ni
			//检测.ni文件,这种文件,我没在网上查到
            size_t len = wcslen(fileName);
            if (len > 3 &&
                fileName[len - 1] == W(‘i‘) &&
                fileName[len - 2] == W(‘n‘) &&
                fileName[len - 3] == W(‘.‘) )
            {
				//结束字符,相当于.NET中的substring了
                fileName[len - 3] = W(‘\0‘);
            }
        }
    }

  下面的2个方法都是加载文件到TpaList中。

    // Returns the semicolon-separated list of paths to runtime dlls that are considered trusted.
    // On first call, scans the coreclr directory for dlls and adds them all to the list.

	//返回可信任的且分号分隔的列表给运行时
	//第一次CALL的时候,搜索coreclr目录里面的所有DLL,并把它们添加到TPAList中去
    const wchar_t * GetTpaList() {
        if (!m_tpaList.CStr()) {

			//文件后缀集合
            wchar_t *rgTPAExtensions[] = {
				// Probe for .ni.dll first so that it‘s preferred if ni and il coexist in the same dir
				//如果是第一次加载 *.ni.dll文件,ni和il会有一个优先级的问题

                        W("*.ni.dll"),
                        W("*.dll"),
                        W("*.ni.exe"),
                        W("*.exe"),
                        };

            // Add files from %CORE_LIBRARIES% if specified
			//从%CORE_LIBRARIES%环境变量中加载文件,如果设定了此环境变量
            wchar_t coreLibraries[MAX_LONGPATH];
            size_t outSize;
            if (_wgetenv_s(&outSize, coreLibraries, MAX_LONGPATH, W("CORE_LIBRARIES")) == 0 && outSize > 0)
            {
                wcscat_s(coreLibraries, MAX_LONGPATH, W("\\"));
                AddFilesFromDirectoryToTPAList(coreLibraries, rgTPAExtensions, _countof(rgTPAExtensions));
            }
            else
            {
                *m_log << W("CORE_LIBRARIES not set; skipping") << Logger::endl;
                *m_log << W("You can set the environment variable CORE_LIBRARIES to point to a") << Logger::endl;
                *m_log << W("path containing additional platform assemblies,") << Logger::endl;
            }

			//从目录中加载文件到TpaList中
            AddFilesFromDirectoryToTPAList(m_coreCLRDirectoryPath, rgTPAExtensions, _countof(rgTPAExtensions));
        }

        return m_tpaList.CStr(); //返回tpaList;
    }

  今天就说到这里了,下一篇跟大家预告一下,会 把GC的第三篇介绍写出来~~敬请期待哦~~~

时间: 2024-11-05 18:55:40

C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(2)的相关文章

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

一看这个标题,是不去取名有点绕呢?或者是,还有些问题?报告LZ...你的标题取得有问题,是个病句!(^ω^)!!!先不要急,其实我今天带给大家的就是CoreCLR中的coreclr.其中它是在名字叫HOST的一个子目录里面的.我的理解是HOST=宿主,GC因为是寄宿在WINDOWS中的,那么它是依靠什么寄宿呢,core-Console是我们狭义上的控制台吗?我觉得不是,我们可以把这个控制台理解为CoreCLR宿主的一个控制台,它控制了各个模块的调度,这全是我个人的理解. 这篇文章我也是采取随机抽

【置顶】CoreCLR系列随笔

GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔:.NET CoreCLR之GC探索(3)(即将写的) CoreCLR探索系列 C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(1) C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(2)

ASP.NET vNext or .NET vNext?

ASP.NET vNext or .NET vNext? 从概念和基础开始 vNext在曝光以来绝大多数以ASP.NET vNext这样的的字眼出现,为什么这边会提及.NET vNext?原因是我认为ASP.NET只是其中的一种开发框架而已,其中真正核心重要的乃是底层的支撑层,至于底层还有些什么内容,下面会进行一次分析. .NET Framework.Mono..NET Core都是什么鬼? 相信有不少人对这一次vNext新诞生的名词抱有许多疑惑,它们到底是做什么的?负责什么内容?扮演者什么样的

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

今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize free object methodtable. The GC uses a special array-like methodtable as placeholder // for collected free space. // //初始化释放器(对象方法表),<-不知道翻译得对不对. //GC使用一

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

首先谢谢 @dudu 和 @张善友 这2位大神能订阅我,本来在写这个系列以前,我一直对写一些核心而且底层的知识持怀疑态度,我为什么持怀疑态度呢?因为一般写高层语言的人99%都不会碰底层,其实说句实话,我以前也不看这些东西,只是因为自己觉得对C++感兴趣,索性乱写点东西,如果有写得不好的地方,还请上面2位大神指出. 其实我现在虽然写的是C++,但是我打算在后面把C++和.NET的一些基础类库融合起来,我发现写CLR的文章特别少,不知道什么原因.反正,废话不多,开始今天的写作吧,今天依然是把重点集中

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

一直是.NET程序员,但是.NET的核心其实还是C++,所以我准备花 一点时间来研究CoreCLR和CoreFX.希望这个系列的文章能给大家带来 帮助. GC的代码有很多很多,而且结构层次对于一个初学者来说,很难很快或者很慢掌握,所以我的建议是,抓住一段功能,到实际当中去看.本来想从开头 跟大家讲的,但是看 开头也是乱的,反正也没有多少经验,索性随便讲. //返回第二个参数seg的直接前驱节点 heap_segment* heap_segment_prev (heap_segment* begi

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

有几天没写GC相关的文章了哈,今天我讲GC的方式是通过一个小的Sample来讲解,这个小的示例代码只有全部Build成功了才会有.地址为D:\coreclr2\coreclr\bin\obj\Windows_NT.x64.Debug\src\gc\sample,前缀路径大家替换成自己的路径就OK了. 首先我们还是从main函数来入手吧.首先是初始化GC. int __cdecl main(int argc, char* argv[]) { // // Initialize system info

ASP.Net请求处理机制初步探索之旅 - Part 2 核心

  上一篇我们了解了一个请求从客户端发出到服务端接收并转到ASP.Net处理入口的过程,这篇我们开始探索ASP.Net的核心处理部分,借助强大的反编译工具,我们会看到几个熟悉又陌生的名词(类):HttpWorkerRequest.HttpRuntime.HttpContext.HttpApplication等. 一.第一个入口:ISAPIRuntme.ProcessRequest()    ISAPIRuntime是进入NET托管环境的入口,在其PR方法中通过一个ecb句柄指向了当前请求报文体的

ASP.Net请求处理机制初步探索之旅 - Part 2 核心(转)

开篇:上一篇我们了解了一个请求从客户端发出到服务端接收并转到ASP.Net处理入口的过程,这篇我们开始探索ASP.Net的核心处理部分,借助强大的反编译工具,我们会看到几个熟悉又陌生的名词(类):HttpRuntime.HttpWorkerRequest.HttpContext.HttpApplication等. (1)Part 1:前奏 (2)Part 2:核心 (3)Part 3:管道 (4)Part 4:WebForm页面生命周期 (5)Part 5:MVC页面声命周期 一.第一个入口:I