8

.Net 7 高端玩法,自定义一个CLR运行时

 1 year ago
source link: https://www.cnblogs.com/tangyanzhi1111/p/17091281.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

.Net 7 高端玩法,自定义一个CLR运行时

曾几何时,一直想自己定制一个CLR运行时玩玩。本篇带你一步一步打造一个属于自己的.Net 7运行时。

假设你的电脑已经安装了.Net,并且运行正常。在进行自定义运行时之前,首先需要准备三样东西。

其一:
找到你当前安装的.Net宿主目录,一般的默认目录都是:

C:\Program Files\dotnet\host\fxr

在这个目录下面是你的当前电脑安装的.Net 版本了。比如7.0.0或者其它版本,它是一个文件夹,它的路径看起来是这样:

C:\Program Files\dotnet\host\fxr\7.0.0

这个路径下面有一个hostfxr.dll文件,记住它,后面要用。

其二:
我们进入到这个网址:

https://github.com/dotnet/runtime/blob/main/src/native/corehost/hostfxr.h

可以看到这个github路径下,是一个hostfxr.h的标准C头文件。你把它里面的内容复制到记事本,然后保存文件名为:hostfxr.h。后面要用。

其三:
准备一个.Net 控制台应用程序,项目名称:Test。代码非常简单,就是一个Helloworld输出,如下:

    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
            Console.ReadLine();
        }
    }

把它编译之后,找到它的路径。

.Net 7的运行时里面有个规定。路径分为,主机路径Host_path也就是你需要运行程序的Debug路径,比如本例的

Host_Path=E:\Visual Studio Project\Test\Test\bin\Debug\net6.0

APP路径,也就是的程序编译之后的DLL路径,本例如下:

ConsoleApp=E:\Visual Studio Project\Test\Test\bin\Debug\net6.0\Test.dll

.Net根目录路径:

DotNet_Root=C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.8

注意以上 .Net运行时和.Net程序的概念。.Net运行时版本是7.0.0,控制台的.Net版本是6.0.8。

OK,假如你以上三样准备好了,我们继续下面的步骤。

用Visual Studio新建一个C++控制台应用程序,取名:SuZhu。新建之后,会跳出一个SuZhu.cpp文件。把里面的代码全部删掉。用下面的代码替代:

#include <stdio.h>
#include <Windows.h>
#include "hostfxr.h"

hostfxr_main_startupinfo_fn startupinfo_fptr;// 实例化一个运行时入口函数指针,此指针用以调用了.Net 托管代码里面的Main函数入口

int main(int argc, char** argv)
{
        // 这个就是上面的Host_Path路径。注意CPP里面的路径是双斜杠
	const wchar_t* Host_Path = L"E:\\Visual Studio Project\\Test\\Test\\bin\\Debug\\net6.0";
	//这个就是上面的ConsoleApp
	const wchar_t* ConsoleApp = L"E:\\Visual Studio Project\\Test\\Test\\bin\\Debug\\net6.0\\Test.dll";
	//这个呢,就是上面的DotNet_Root路径。
	const wchar_t* DotNet_Root = L"C:\\Program Files\\dotnet\\shared\\Microsoft.NETCore.App\\7.0.0";
	//这里的argvV参数区别于Main的argv参数,主要用于运行时入口函数指针的参数。
	const wchar_t* argvV = L"";
	//用LoadLibraryExA加载上面前期准备的步骤里的hostfxr.dll
	HMODULE h = LoadLibraryExA("C:\\Program Files\\dotnet\\host\\fxr\\7.0.0\\hostfxr.dll", NULL, 0);
	//通过GetProcAddress函数获取到运行时入口函数指针,也就是上面实例化的startupinfo_fptr变量
	startupinfo_fptr = (hostfxr_main_startupinfo_fn)GetProcAddress(h, "hostfxr_main_startupinfo");
	//通过传入运行时入口函数指针的参数,包括Host_Path,DotNet_Root,ConsoleApp等参数。来运行CLR,用以调用ConsoleApp里面的Main函数入口。
	startupinfo_fptr(1, &argvV, Host_Path, DotNet_Root, ConsoleApp);

	return 0;
}

然后引入上面步骤二里面保存记事本的文件hostfxr.h。
点击项目展开-》头文件-》右键添加--》现有项目,选择hostfxr.h。

如果你以上步骤都实现了,并且没有问题。那么现在请摁Visual Sutdio的F5按钮运行当前CPP程序。

结果就会打印出Hello, World!

如下图所示:
image

这个是一个非常小型且精简的CLR运行时程序。屏蔽了繁琐的实现过程。你可以通过这个小型的CLR运行时,构建自己的定制型的运行时。比如这个Host_Path,ConsoleApp传参方式等等。本篇只是最基础的展示。

以上是C++和C#混搞,对于部分.Net程序员可能有点难度。
如果你对.Net的CLR核心技术感兴趣,或者有不明白的地方,可以扫码关注我。
image


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK