Previously, I packaged files through NSIS, and later I found Inno Setup. After using it, I found that Inno is slightly better than NSIS personally, and the entire operation interface is much simpler than NSIS. There is a localization version that can be added, but I use the English original version here.

Wizard Settings

  1. Create a new file wizard after installation File-> New
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-08.png)
2. Click Next to enter the setting interface
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-12.png)
**Because most of the packaged installation packages are placed in specified folders, choose folder**
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-15.png)
3. Because the Revit plugin is a plugin based on Revit secondary development, there is no startup item, just check the following. If there are other files, it is also okay. I did not try to add folders here, I added subsequent folders directly in the script.
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-19.png)
Similarly, because there is no startup item, we do not need to create a start menu, just uncheck it here.
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-23.png)
4. Add license files and other information
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-27.png)
5. Add installation permissions which can also be edited via script later
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-31.png)
6. Select language, because I didn't install the localization pack, only English is selected
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-35.png)
6. Other settings
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-39.png)
7. Finished, then enter script editing content
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-43.png)

Script Settings

Specific content can be learned by viewing Inno’s API. Here I will talk about the nodes I used

  1. Sometimes we need to install some files in the installation package to the system path. Inno provides some system path nodes here, you can see the Constants node in the API, where
    • {app} User installation path
    • {localappdata} C:\Users\user\AppData\Local
    • {appdata} C:\Users\xu.lanhui\AppData\Roaming
  2. Source
    Here I used Source to add the company’s internal login confirmation tool and installed it to a separate path
1
Source: "C:\Users\xu.lanhui\Desktop\registor\*";DestDir:"{localappdata}\***\registor" ; Flags: ignoreversion recursesubdirs createallsubdirs
  1. [Run] Copy multiple addin files
    Because external applications can be called, you can use a language you are good at to write a file copy program and call it using Inno. Below are my input parameters
1
2
[Run]
Filename: "{app}\CopyFiles.exe" ;Description:"修改文件" ; Parameters:"""{app}"""; StatusMsg: "正在配置信息"; Flags: runhidden

All Script Coding and C# Copy Addin to Version File

  1. Inno script coding
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
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "BiMass"
#define MyAppVersion "1.4.2"
#define MyAppPublisher "TYDI"

[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{3B7C7466-9BA0-44B3-80D8-87DDF9997572}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
LicenseFile=D:\000 Development&TemplateFloder\Panel\Document.rtf
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=D:\000 Development&TemplateFloder\Panel\Output
OutputBaseFilename=Setup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=admin
UsedUserAreasWarning = no

[Dirs]
Name: "{localappdata}\***\registor"

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Files]

Source: "D:\000 Development&TemplateFloder\Panel\Panel\Install\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "C:\Users\user\Desktop\registor\*";DestDir:"{localappdata}\TengYuanTmp\registor" ; Flags: ignoreversion recursesubdirs createallsubdirs

; NOTE: Don't use "Flags: ignoreversion" on any shared system files


[Run]
Filename: "{app}\CopyFiles.exe" ;Description:"修改文件" ; Parameters:"""{app}"""; StatusMsg: "正在配置信息"; Flags: runhidden

  1. C# Copy license file to version addin
    • This is my file structure
![Image Description](https://cdn.bimath.com/blog/pg/Snipaste_2026-01-04_17-00-48.png)
- code
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
// See https://aka.ms/new-console-template for more information

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;

Console.WriteLine("Start Changing");
string path = string.Empty;
if(args.Length < 1)
{
path = System.Environment.CurrentDirectory;
}
else
{
path = args[0];
}


Console.WriteLine(path);
try
{
var localFile = @".\ProductName.addin";
var strContent = File.ReadAllText(localFile);

CopyFiles(strContent, path);
}
catch (Exception e)
{

Console.WriteLine(e.ToString());
throw;
}
Console.WriteLine("Done");
//Console.ReadKey();
return;


bool CopyFiles(string strContent, string targetPath)
{

if (strContent == null) throw new ArgumentNullException(nameof(strContent));
if (targetPath == null) throw new ArgumentNullException(nameof(targetPath));

int[] versions = new[] { 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 };
// Copy data to other version files, create new folder if the folder does not exist under the path
//const string localProgramDataPath = @"C:\ProgramData\Autodesk\Revit\";
const string localReplacePath = @"E:\\Productname\\RibbonPanel\\Panel\\bin\\Debug\\Panel.dll";
const string localDataPath = @"C:\ProgramData\Autodesk\Revit\Addins";
foreach (int version in versions)
{
string? content = strContent.Clone() as string;
var fullPath = @$"{targetPath}\{version}";//represents user installation path
Console.WriteLine($"fullPath:{fullPath}");
var localFullPath = @$"{localDataPath}\{version}";//represents programdata folder path
//Check if C drive path has created this folder in advance, if not create new
if (!File.Exists(localFullPath))
{
Directory.CreateDirectory(localFullPath);
Console.WriteLine(localFullPath);
}
//Check if the installation location has the specified version installation file, if not skip
if (Directory.Exists(fullPath))
{
if (content != null)
{
content = Regex.Replace(content, @localReplacePath, fullPath + @$"\Productname_{version}.dll");
Console.WriteLine(content);
File.WriteAllText(localFullPath + @"\Productname.addin", content);
}
}


//Console.WriteLine($"localPath:{fullPath}");
}

return false;
}