C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(2)
这篇文章是上篇的续集,本文将会继续介绍coreconsole.cpp里面的逻辑。也许大家会看一些CLR的书,我承认我没有看过,因为我觉得一个人,他再NB,那也是他自己的眼光,而且说句难听的,CLR也不是那个写书的人一个人完成的项目,所以他的眼光,我个人看来,也还是很有限的。 PS:谢谢@Grid Science 的建议
承接上篇文章的HostEnvironment,宿主环境:个人认为HOST是指的Windows内核。但是CLR有一个缺点,就是它并不是一个跨平台的,所以广义的说HOST应该是“操作系统内核”;下面我们来看看LoadCoreCLR这个方法,这个方法的核心宗旨就是从动态链接库当中得到CLR,如果出错,会记日志;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | //尝试去“载入”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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 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列表里面的项是否有包含文件,具体作用不详。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //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 ; } |
下面的方法是移除文件后缀的,应该是一个工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //移除文件后缀 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中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // 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的第三篇介绍写出来~~敬请期待哦~~~
__EOF__
作 者:ღKawaii
出 处:https://www.cnblogs.com/kmsfan/p/5514462.html
关于博主:一个普通的小码农,为了梦想奋斗
版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!

作者:
KMSFan
出处:http://www.cnblogs.com/kmsfan
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
欢迎大家加入KMSFan之家,以及访问我的优酷空间!
出处:http://www.cnblogs.com/kmsfan
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
欢迎大家加入KMSFan之家,以及访问我的优酷空间!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?