.Net 7 高階玩法,自定義一個CLR執行時

2023-02-04 15:00:59

前言:

曾幾何時,一直想自己客製化一個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 控制檯應用程式,程式碼就是一個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=\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

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";//這個是上面的AppConsole路徑。
	//這個呢,就是上面的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!

如下圖所示:



結尾:

這個是一個非常小型且精簡的CLR執行時程式。遮蔽了繁瑣的實現過程。你可以通過這個小型的CLR執行時,構建自己的客製化型的執行時。比如這個Host_Path,ConsoleApp傳參方式等等。本篇只是最基礎的展示。

以上是C++和C#混搞,對於部分.Net程式設計師可能有點難度。
如果你對.Net的CLR核心技術感興趣,或者有不明白的地方,可以掃碼關注我。