.NET DLL 的入口点
2024-04-21 15:04:22

在用开发 DLL 模块时,DLL 往往需要知道自身何时被加载,以便初始化资源。
在非托管 DLL 开发中,是有 DllMain 入口点函数的,在这里可以处理初始化、卸载等操作。
而在 .NET 中,DLL 和 EXE 都被称作为 程序集,程序集之间可以相互调用,无论是 EXE 或 DLL,这是与 Win32 开发中很大的一个不同之处。
而 DLL 程序集是没有入口点(EntryPoint)属性的。

那么如何解决 DLL 的初始化问题呢?
可以提供一个静态初始化方法,要求使用者必须先调用该方法进行 DLL 的初始化。但是这种解决方案一点都不酷。

在 .NET 程序集中,EXE 是有入口点(EntryPoint)属性的,那么我们可以将工程改为 EXE,并将文件后缀名改为 .dll

1
2
3
4
5
6
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetExt>.dll</TargetExt>
</PropertyGroup>
</Project>

在 EXE 的入口处调用 AppDomain.ExecuteAssembly 方法进行 DLL 的初始化即可。

1
AppDomain.CurrentDomain.ExecuteAssembly("MyDll.dll");

模块初始化器

从 .NET 5 开始,提供了 ModuleInitializerAttribute 属性来标注模块的初始化方法。

1
2
3
4
5
6
7
8
9
10
using System.Runtime.CompilerServices;

public static class MyInitializer
{
[ModuleInitializer]
public static void Initialize()
{
// 在加载模块时执行初始化操作
}
}

这样一来,无需显式调用初始化方法,初始化操作会在DLL被加载时自动执行。

相关阅读

Can a C# .dll assembly contain an entry point?
Module Initializers