zoukankan      html  css  js  c++  java
  • C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(2)

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

      承接上篇文章的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('');
                            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('');
    
                // 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('');
                }
            }
        }
    

      下面的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的第三篇介绍写出来~~敬请期待哦~~~

  • 相关阅读:
    C#冒泡排序--详解
    盘古搜索--实例解析
    ajax提交表单序列化(serialize())数据
    随机数大揭秘
    静态代码块(主要是注意执行顺序)
    单例模式
    递归
    vue路由嵌套(邹文丰)
    vue computed和 methods、 watch 区别(邹文丰)
    vuex状态管理mutations,getters,actions总结(邹文丰)
  • 原文地址:https://www.cnblogs.com/kmsfan/p/5514462.html
Copyright © 2011-2022 走看看