写在前面:
- 我目前的学术研究方向比较传统,与 IT 关联不大(甚至难以学科交叉),在该领域纯属外行,文章在形式和内容上不期望与业内人士比肩。
- 我对计算机略有涉猎,偶尔做点东西娱乐自己,每当遇到一些值得整理的问题就顺手记录下来,没有广大程序猿和 IT 工作者那样的高尚情操,不是以能帮助到别人为初衷(若有幸当然更好),只是单纯地为了让自己的下次更顺利。所以在内容和形式上主要以服务我自己优先,望读者不喜勿喷。
目录
1 环境
软件环境:VS 2017 Community (安装 Unity 时自带的,已装 C#)
系统环境:Win10 1909 x64
2 安装 Installer Projects 扩展
添加方法:
- 打开vs,在菜单中点 工具 - 扩展和更新。
- 在打开的窗口左侧点 联机,然后在右上角输入“Installer Projects”,等搜索完毕后即可出现“Microsoft Visual Studio Installer Projects”,创建者是 Microsoft。选中它,点下载。
- 下载完毕后,提示需要关闭所有vs窗口才能安装。按要求关闭以后在弹出窗口(VSIX Installer)内点“修改”,等安装完成再次打开vs即可。
注:当时遇到 VSIX Installer 安装失败的问题。重启电脑自行解决。
3 创建工程
创建方法:
- 在菜单里:点 文件 - 新建。
- 在“新建项目”窗口内,依次点 其他项目类型 - Visual Studio Installer;然后选第一个 Setup Project,确定好项目名称和保存位置后,最后点确定。
4 设置工程
1 界面说明
-
左侧:目标计算机(安装包将要被安装到此机器)。左侧相当于安装包安装后对目标计算机作出的修改,其修改效果的视图。只会显示文件夹的层次结构。
-
右侧:显示左侧选定的某个文件夹内的待安装文件。此时是空的,稍后将文件放入即可。
2 特殊文件夹
在左侧,默认只有下列3个文件夹,其功能如下:
文件夹 | 描述 | Property |
---|---|---|
Application Folder | 安装包内文件在目标计算机中的安装位置。 | TARGETDIR |
User’s Desktop | 目标计算机的桌面。 | DesktopFolder |
User’s Programs Menu | 目标计算机的程序文件夹。(不过在我的机器上就等同于开始菜单根目录,点徽标键就能看见的那个,这正常吗?) | ProgramMenuFolder |
稍后只需将待安装文件放到这些文件夹内即可,而无需考虑这些文件夹在不同目标计算机内的实际路径不同的问题,安装程序会自动确定。
在工程内使用 [ 特殊文件夹的 Property 属性的值 ] (含括号)来代指这些特殊文件夹的真实路径。如:"[TARGETDIR]test.exe"。
关于 Application Folder,其相较其他特殊文件夹多一 DefaultLocation 属性,默认值为 [ProgramFilesFolder][Manufacturer]\[ProductName],代表默认安装路径(其中[ProgramFilesFolder] 代表 “C:\Program Files\” 或 “C:\Program Files (x86)\”,取决于此项目的 TargetPlatform 属性的值,但一定以"\"结尾;[Manufacturer] 和 [ProductName] 是项目的 Manufacturer 和 ProductName 属性的值,见后文)。
如果需要其他的特殊文件夹,可以右键 - Add Special Folder,添加所的特殊文件夹。其 Property 可先在左侧选中文件夹,然后在属性窗口中查看到。
3 项目的属性
注意:直接在解决方案资源管理器窗口中对项目点左键,在属性窗口中就会出现项目的属性。而不是对项目点右键,再点(工程的)属性。
必须修改的属性:
属性 | 描述 | 我的操作 |
---|---|---|
Manufacturer | 制造商,影响到安装路径 | 改 |
ProductName | 产品名称,影响到安装路径 | 改 |
RemovePreviousVersions | 安装前如果检测到旧版本是否先移除 | 必须改为 True,否则会造成新老版本重叠 |
TargetPlatform | 安装程序适用平台,影响到安装路径和所有待安装的 Assembly(部分 *.exe; *.dll 等) | 按需要改为 x86 或 x64(Itanium 选项是什么?) |
Version | 版本 | 务必认真对待,影响到程序的更新和升级;改完后建议生成新的 ProductCode 选是选否都可 |
建议修改的属性:
属性 | 描述 | 我的操作 |
---|---|---|
AddRemoveProgramsIcon | 安装后的程序在目标计算机的控制面板 - 程序和功能 中显示的图标 | 稍后将它指向图标文件,现在由于没有添加图标文件,还不能操作 |
Author | 作者名 | 改 |
Description | 安装包描述 | 改 |
Title | 标题,在文件资源管理器里把鼠标悬停到文件上会显示 | 改 |
其他的属性看情况修改。
4 配置安装前所需组件
在解决方案资源管理器窗口中对项目点右键,再点属性。在弹出的属性页中点 Prerequisites,在弹出的系统必备窗口中勾选安装包需要的组件。
如果没有,建议把系统必备窗口中的“创建用于安装系统必备组件的安装程序”勾掉,这影响到生成后的文件,稍后将提到。我这里把它勾掉了。
关于“系统必备组件的安装位置” 和 “Installation URL” 的配置我没有过多尝试,如有需要请搜索其他资料,或日后探索。
5 尝试生成
尝试生成,发现可以生成成功。
如果未勾选“创建用于安装系统必备组件的安装程序”则应当只有一个 .msi 的安装包;否则还有一个 setup.exe 文件(此时 .msi 也可单独运行,故猜测可能是用于安装系统必备组件的)。
5 添加待安装文件
1 需要准备的文件
- 待安装文件
将待安装文件夹备好。如果此时所有的待安装文件在一个文件夹里,则其名称不是安装后的目标名称, ProductName 才是目标名称。
需要确保安装文件内的所有Assembly(部分 .exe 和 .dll 等)都能够与 TargetPlatform 匹配。 - 图标文件
接下来有多处用到图标的地方。图标可以来自 .ico 或 .exe 或 .dll。我用独立的 ico。 - msiexec.exe
使用此文件创建卸载程序。
此文件位于"C:\Windows\System32\msiexec.exe"。它需要与 TargetPlatform 匹配, 虽然叫 System32 但如果你的机器是64位,则该文件也是64位的;或者你在用64位机器制作32位安装包,则在你的电脑上的那个是不匹配的。总之确保匹配而且在目标计算机能正常运行,则可以直接复制一份待用;或者直接到这里下载也可(x64 和 x86 均包含):
https://download.csdn.net/download/simoral/10429167
都准备好后大概是这样的:
- 把 图标文件 和 msiexec.exe 放到 待安装文件 内
把它们都放一起,它们最后都会被安装。为了更有层次,可在待安装文件夹内新建一个文件夹,名字随意,将图标文件和 msiexec.exe 放进去。
最终效果如下:
2 添加到安装包
先在 文件资源管理器 里进到待安装文件夹,在此 全选 - 复制(不要在文件夹外复制),然后在vs界面左侧点击“Application Folder”,然后在vs界面 右侧 点 右键 - 粘贴。
导入可能是一个漫长的过程,需要稍等。完成后效果大概这样:
可以发现,部分 .Net 编写的 .exe 和 .dll 等被认为是 Assembly,其他的被认为是 File。还有一部分 Assembly 被导入为与原文件同名的但扩展名大写者,与原文件同时存在;不用担心,实际安装时不会被输出。
导入后,别忘了之前的项目的属性的 AddRemoveProgramsIcon 尚未设定,此时已经可以设定了。
3 创建快捷方式
在右侧,对要创建快捷方式的 exe 点 右键 - Create Shortcut to xxx.exe 即可。
选中产生的快捷方式,修改其属性:
属性 | 描述 |
---|---|
(Name) | 显示的名称 |
Arguments | 该快捷方式的启动参数,没有可以空着 |
Description | 鼠标悬停时显示的提示 |
Icon | 图标 |
改好后,在右侧拖动快捷方式,到左侧的某个文件夹上松开,快捷方式进去了,则安装包安装后将在那里创建快捷方式。一般是拖进 User’s Desktop 或 User’s Programs Menu,就能在目标计算机桌面或程序菜单创建快捷方式了,或者两个都要。如果快捷方式较多,为了整洁,也可以在 User’s Programs Menu 内创建个文件夹什么的。
(P.S. 我想知道怎么能让 CSDN Markdown 不要自动把单独的英文引号转换为中文引号?转义字符也不行。)
4 创建卸载程序的快捷方式
原理:要操作一个具有 ProductCode 的程序的安装状态,本质上是运行 msiexec.exe 并传入参数(具体参数可手动运行它查看)。要卸载某个程序,只需要在 msiexec.exe 的快捷方式中传入参数为 /x {ProductCode}。
方法:创建 msiexec.exe 的快捷方式,修改属性,其中 Argument 属性改为:/x {ProductCode}。其中,{ProductCode} 可以在 项目的 ProductCode 属性 处获得,注意带着括号复制过来。
完毕后,将卸载快捷方式拖入适当的目标文件夹。
6 高级操作(你可能不需要)
1 安装后写入注册表
在项目上点右键 - View - 注册表,即可打开目标计算机上的注册表。
将目标注册表项键值插入,类似 Regedit,即可在安装后写入注册表。
这样做好处是不需要自己写代码操作注册表,那样需要获取管理员权限,还涉及不同机器位置不同的问题。但不确定在卸载时会不会卸载掉自定义的注册表,好像会,这里有待证实。
2 重写安装函数
参考:https://blog.csdn.net/smallbabylong/article/details/78756530
目标:重写原生的 BeforeInstall、AfterInstall、AfterRollback、AfterUninstall、BeforeRollback、BeforeUninstall 等函数以便能在相应的事件执行时执行我自己的代码。
方法:文件 - 添加 - 新建项目 - 已安装 - 其他语言 - Visual C# - 类库(.NET Framework)(不要点成另一个),命名并选择路径和框架,点确定。
在类库的项目下,删除 Class1.cs,添加 - 新建项 - 安装程序类(不是别的类),重命名、添加后打开(可能需要在弹出的对话框内点一下切换到代码视图)。
此安装程序类继承自 System.Configuration.Install.Installer。它里面默认只有一个构造函数。现在安装程序原本不能直接完成的功能,都可以在这个类里通过重写原生函数自己实现。复制下列代码加入构造函数之后,然后自行修改即可。
protected override void OnBeforeInstall(IDictionary savedState)
{
// 这里需要 protected 而不能是 public
//
//
// Do your things here ...
//
base.OnBeforeInstall(savedState);
}
public override void Install(IDictionary stateSaver)
{
//
// Do your things here ...
//
base.Install(stateSaver);
}
protected override void OnAfterInstall(IDictionary savedState)
{
// 这里需要 protected 而不能是 public
//
//
// Do your things here ...
//
base.OnAfterInstall(savedState);
}
public override void Uninstall(IDictionary savedState)
{
//
// Do your things here ...
//
base.Uninstall(savedState);
}
public override void Rollback(IDictionary savedState)
{
//
// Do your things here ...
//
base.Rollback(savedState);
}
7 生成
1 生成成功
强烈建议生成前先打开输出窗口以便观察错误提示。点视图 - 其他窗口 - 输出。
如果一切顺利,此时执行生成,即可生成成功。也可能会遇到一些问题。
2 可能遇到的问题
1 ERROR: … should be excluded because its source file … is under Windows System File Protection.
可能遇到的错误:
ERROR: ‘System.EnterpriseServices.tlb’ should be excluded because its source file ‘C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.EnterpriseServices.tlb’ is under Windows System File Protection.
原因:某些(被自动解析出来的)“受保护的” Assembly 不能被放入包。
办法:将出错对象的 Exclude 属性设为 True,则可使其排除在包外。不用担心,这些组件往往是系统核心文件,出于安全考虑才被禁止入包,所以每个机器都有该文件。
被排除的文件在右侧不显示, 但在解决方案管理器窗口的 Detected Dependencies 中,其左下角显示一小图标。
2 WARNING: Unable to find dependency …
可能遇到的警告(不会导致生成失败):
WARNING: Unable to find dependency ‘ICSHARPCODE.SHARPZIPLIB’ (Signature=‘1B03E6ACF1164F73’ Version=‘0.86.0.518’) of assembly ‘NPOI.OpenXml4Net.DLL’
原因:找不到依赖项。虽然该文件存在,但与要求的版本号(如图,0.86.0.518)不同也会触发。
办法:更换为正确的文件。
3 安装程序的实际运行
在文件资源管理器中查看,发现项目的 Description 和 Title 属性似乎会合并到“标题”里面,介意可以改掉,在文件的属性里可直接编辑。
运行时大概这样子的:
再运行就是安装了,然后就是完毕了;如果点取消会提示未完成;安装过程中取消会回滚操作。没有声明界面,整体流程比较简洁明了,如果有需要也可以自定义界面,在项目上点右键 - View - 用户界面。以后研究。
安装的程序可以在控制面板里管理,可以被软件管家之类的杀毒软件管理。如果已安装,再次运行安装包,会进入修复或卸载页面。
8 一些疑惑
- 我查的所有资料发现都要添加主输出,然而我很难理解它的作用?而且我没有添加也能正常工作。