NsisPlugin 1.0.2
dotnet add package NsisPlugin --version 1.0.2
NuGet\Install-Package NsisPlugin -Version 1.0.2
<PackageReference Include="NsisPlugin" Version="1.0.2" />
<PackageVersion Include="NsisPlugin" Version="1.0.2" />
<PackageReference Include="NsisPlugin" />
paket add NsisPlugin --version 1.0.2
#r "nuget: NsisPlugin, 1.0.2"
#:package NsisPlugin@1.0.2
#addin nuget:?package=NsisPlugin&version=1.0.2
#tool nuget:?package=NsisPlugin&version=1.0.2
NsisPlugin
![]()
NsisPlugin 是一个面向 C# 的现代化 NSIS(Nullsoft Scriptable Install System)插件开发框架。
它基于特性标注与 Roslyn 源生成器自动生成导出包装代码和初始化逻辑,用于减少 NSIS 插件开发中的非托管互操作样板代码,使开发者能够专注于插件业务本身。
文档导航
特性
- 特性驱动导出:使用
[NsisAction]声明插件入口,由源生成器自动生成导出包装代码。 - 自动参数绑定:自动从 NSIS 栈弹出参数并转换为目标类型,同时将返回值压回栈;对于不支持解析的参数类型,会在编译期给出诊断。
- 变量绑定:通过
[FromVariable]/[ToVariable]直接读取和写入 NSIS 变量。 - ANSI / Unicode 双编码支持:支持全局编码配置以及方法级编码覆盖。
- 编译期诊断:在不满足导出约束时提供诊断信息,便于尽早发现配置与声明错误。
前提条件
- .NET 9.0+
- 源生成器: 项目依赖 Roslyn 源生成器生成模块初始化器与导出包装代码。(.NET 5.0+)
- 支持 win-x86 Native AOT
- NSIS 插件需以原生共享库(Windows 下为
.dll)交付 - NSIS 只支持 32 位插件,因此在通过 AOT 发布时需指定
win-x86作为运行时标识符。
- NSIS 插件需以原生共享库(Windows 下为
- 参考文档:
安装
dotnet CLI
dotnet add package NsisPlugin
Package Manager
Install-Package NsisPlugin
快速开始
说明:以下示例仅演示插件入口的声明方式。要使 NSIS 能够实际加载插件,消费项目仍需发布为原生共享库;普通托管类库的
dotnet build产物通常不能直接作为 NSIS 插件使用。
1. 最简单的插件函数
以下代码将 Add 导出为 NSIS 插件入口点。源生成器会自动生成包装函数,并负责从 NSIS 栈读取参数以及将返回值压回栈:
using NsisPlugin;
public class MyPlugin
{
[NsisAction]
public static int Add(int a, int b) => a + b;
}
在 NSIS 脚本中调用:
; 假设编译生成的插件名为 MyPlugin.dll
MyPlugin::Add 3 5
Pop $0 ; $0 = "8"
2. 多种参数类型
NSIS 传递的参数均为字符串。
NsisPlugin 会自动按照 IParsable<TSelf> 规则进行转换;如果需要转换为自定义类型,需要实现该接口。
ps. string、int、double、bool、Guid、DateTime 等常用类型都已内置支持。
[NsisAction]
public static string Greet(string name) => $"Hello, {name}!";
[NsisAction]
public static double Power(double baseValue, int exponent) => Math.Pow(baseValue, exponent);
[NsisAction]
public static string IsEven(int number) => (number % 2 == 0) ? "true" : "false";
3. 自定义入口点名称
方法名与导出名称可以分离。entryPointFormat 支持 {0} 占位符,用于表示方法名:
[NsisAction("GetVersion")]
public static string Version() => "1.0.0";
// 也可使用格式字符串,入口点名称为 "Plugin_Greet"
[NsisAction("Plugin_{0}")]
public static string Greet(string name) => $"Hello, {name}!";
4. 读写 NSIS 变量
使用 [FromVariable] 从指定 NSIS 变量读取参数,使用 [ToVariable] 将返回值写入指定变量(而非压栈):
// 从 $R0 读取路径,将结果写入 $R1
[NsisAction]
[return: ToVariable(NsVariable.InstR1)]
public static string NormalizePath([FromVariable(NsVariable.InstR0)] string path) => path.Replace('/', '\\');
5. 同一方法多个入口点
同一方法可附加任意数量的 [NsisAction],分别定义不同的入口点名称和编码。不指定 Encoding 时,将使用项目级默认编码(由 NsisPluginUseUnicode 属性决定):
[NsisAction("ToUpper")] // 使用全局编码(由 NsisPluginUseUnicode 决定)
[NsisAction("ToUpper_A", Encoding = NsEncoding.Ansi)] // 使用 ANSI 编码
[NsisAction("ToUpper_U", Encoding = NsEncoding.Unicode)] // 使用 Unicode 编码
public static string ToUpper(string input) => input.ToUpper();
6. 特殊参数(StackT / Variables / ExtraParameters)
将 StackT、Variables 或 ExtraParameters 声明为方法参数时,源生成器会自动传入当前调用的上下文对象,不会从 NSIS 栈弹出。这三种类型可以自由组合,顺序不限,也可与普通参数混用:
[NsisAction]
public static void Summarize(string input, StackT stack, Variables vars, ExtraParameters extra)
{
// 手动向栈压入多个值
stack.Push(input.ToUpper());
stack.Push(input.Length.ToString());
// 将统计结果写入 NSIS 变量
vars.Set(NsVariable.InstR0, input.Length.ToString());
// 根据执行标志决定是否输出额外信息
if (extra.ExecFlags.Silent == 0) stack.Push("verbose");
}
7. 使用插件回调
通过 ExtraParameters 的 RegisterPluginCallback 方法注册 NsPluginCallback,回调参数类型为 Nspim:
[NsisAction]
public static void RegisterCallback()
{
NsPlugin.ExtraParameters.RegisterPluginCallback(OnMessage);
}
private static IntPtr OnMessage(Nspim message)
{
if(message == Nspim.NspimGuiunload)
{
// NSIS GUI 卸载时的清理逻辑
}
else if(message == Nspim.NspimUnload)
{
// 插件即将卸载
}
return IntPtr.Zero;
}
配置
NsisPluginUseUnicode
- 用于设置插件默认编码;方法级
Encoding可覆盖该设置。 false为 ANSI(默认),true为 Unicode。
如需将默认编码改为 Unicode,可在消费项目中添加:
<PropertyGroup>
<NsisPluginUseUnicode>true</NsisPluginUseUnicode>
</PropertyGroup>
NsisPluginGenerateInitializer
- 用于控制是否自动生成模块初始化器。
- 默认为
true,为false不会生成初始化器并且NsisPluginUseUnicode无效,需要消费项目自行完成初始化。
只有在你需要完全接管模块初始化流程时,才建议关闭该配置:
<PropertyGroup>
<NsisPluginGenerateInitializer>false</NsisPluginGenerateInitializer>
</PropertyGroup>
NsisPluginUseSharedEntryInit
- 用于控制导出包装代码是否复用同一个共享入口初始化助手。
- 默认为
false:每个导出入口各自完成编码切换、NsPlugin.Init和异常处理。 - 设为
true:生成一个共享的初始化帮助方法,各个导出入口只负责传入编码、入口点名称和实际调用逻辑。
如果你希望导出的初始化逻辑更集中,可在消费项目中启用:
<PropertyGroup>
<NsisPluginUseSharedEntryInit>true</NsisPluginUseSharedEntryInit>
</PropertyGroup>
命名约定
- 这三个项目级属性统一使用
NsisPlugin前缀,便于和普通 MSBuild 属性区分。 - 三者分别对应:默认编码、初始化器生成、共享入口初始化模式。
发布
要使 NSIS 能够加载插件,消费项目必须发布成 32 位原生共享库(Windows 下为 .dll)。
方法1:直接使用命令
dotnet publish <PROJECT_PATH> -r win-x86 /p:PublishAot=true
方法2:将配置写入项目文件
将下面的配置添加到消费项目的 .csproj 文件中:
现在发布就只需要 dotnet publish <PROJECT_PATH> 就行了。
<PropertyGroup>
<PublishAot>true</PublishAot>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>
AOT 发布体积优化
如果你希望进一步缩小发布产物体积,可以根据实际情况启用以下 AOT 优化选项:
<PropertyGroup>
<OptimizationPreference>Size</OptimizationPreference>
<InvariantGlobalization>true</InvariantGlobalization>
<DebuggerSupport>false</DebuggerSupport>
<StackTraceSupport>false</StackTraceSupport>
<UseSizeOptimizedLinq>true</UseSizeOptimizedLinq>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
</PropertyGroup>
说明:启用这些优化后,应对插件进行完整测试。某些 AOT 优化可能会移除未直接引用的代码路径,进而导致运行时行为变化。
更多背景与对比数据可参考:
注意事项
- 编码一致性:插件函数必须与调用它们的 NSIS 脚本使用相同编码(ANSI 或 Unicode)。
- 发布方式:源生成器仅负责生成导出包装代码;若消费项目未以原生共享库方式发布,NSIS 仍无法加载该插件。
- 字符串长度限制:写入栈或变量的字符串受 NSIS
string_size限制(由NsPlugin.StringSize反映)。超出长度时内容会被截断,且不会抛出异常。 - 类型转换失败:泛型扩展方法(
Pop<T>、Get<T>等)在转换失败时返回false,调用方应显式检查结果。 - 参数类型约束:导出方法的参数类型需要确保已实现
IParsable<TSelf>;不满足时源生成器会报告NSPGEN102。特殊参数StackT、Variables、ExtraParameters不受此限制。 - 返回值与变量:普通返回值会压回 NSIS 栈;使用
[ToVariable]时,结果写入指定变量且不再压栈。 - 手动初始化:当
NsisPluginGenerateInitializer设为false时,必须在插件加载阶段手动设置NsPlugin.ModuleHandle与NsPluginEnc.UseUnicode。 - Visual Studio 中生成器诊断不实时:
- 2026 (若高级配置未迁移,需要打开旧的选项框)
- 工具 → 选项 → 语言 → C# → 高级 → 源生成器(执行) → 修改为:自动。在任意更改后运行生成器
- 2022
- 工具 → 选项 → 文本编辑器 → C# → 高级 → 源生成器(执行) → 修改为:自动。在任意更改后运行生成器
- 2026 (若高级配置未迁移,需要打开旧的选项框)
License
本项目使用 MIT 协议。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.2 | 38 | 4/2/2026 |
| 1.0.1 | 33 | 4/2/2026 |
| 1.0.0 | 51 | 3/31/2026 |
| 1.0.0-preview.5 | 36 | 3/30/2026 |
| 1.0.0-preview.4 | 48 | 3/27/2026 |
| 1.0.0-preview.3 | 44 | 3/27/2026 |
| 1.0.0-preview.1 | 44 | 3/23/2026 |