如何使用C#自制一个Windows安装包

原文链接:https://www.cnblogs.com/zhaotianff/p/17387496.html

以前都在用InstallShield制作安装包,基本需求是能满足的,但也有一些缺点:

1、界面不能完全定制

2、不能直接调用代码里的功能

平常使用一些其它软件,觉得安装界面挺炫的,类似下面这种。

其实安装的过程主要就是解压文件,注册文件等。所以想自己封装一个简易的安装工具,实现界面的完全定制。

使用.Net Framework开发安装包美中不足的就是需要依赖.Net Framework Runtime ,像上面这种不知道是用什么技术开发的,完全不需要依赖任何运行时。

好在Windows 10及以上版本都自带了.Net Framework。

我这里主要实现以下基本安装包功能

1、释放文件

2、安装依赖

3、注册COM组件

4、创建桌面快捷方式/开机启动

5、创建控制面板卸载程序项

6、安装进度及状态显示

效果如下:

释放文件

这里我直接将需要释放的文件压缩成zip文件,然后放到工程的资源文件中去。通过解压 到指定路径的形式来完成释放功能。

主要用到ZipArchive类

这里的fileBuffer就是资源里的压缩包

代码如下:

 1   using (MemoryStream ms = new MemoryStream(fileBuffer))2                 {3                     var zipArchive = new ZipArchive(ms);4 5                     foreach (var item in zipArchive.Entries)6                     {7                         //创建文件夹操作8 9                         //文件判断操作
10 
11                         //解压
12                         item.ExtractToFile(destFileName, true);
13 
14                       }
15                     }
16                 }

安装依赖

这里主要借助依赖库安装程序自身的命令行参数来完成。

像Microsoft Visual C++ 2015-2022 Redistributable (x64) ,可以通过/install /passive来进行直接安装。

一般来说大部分的依赖库可以通过 参数 /?进行查看

如果是 .msi格式的安装包 ,可以直接通过msiexec.exe来进行安装。可以参考https://www.cnblogs.com/zhaotianff/p/11558602.html

注册COM组件

直接调用regsvr32.exe /s执行安静注册即可

1 System.Diagnostics.Process.Start("regsvr32.exe", dllPath + " /s");

创建桌面快捷方式/开机启动

创建桌面快捷方式需要用到一个COM组件Windows Script Host Object。在项目中直接引用 即可

使用代码如下:

这里的exePath就是程序释放到的路径 如D:\install\xxx.exe

shotcutPath就是快捷方式的路径,如 C:\User\xx\Desktop\xxx.lnk

 1      private static void InternalCreateShortcut(string exePath, string shotcutPath)2         {3             try4             {5                 WshShell shell = new WshShell();6                 var exeName = System.IO.Path.GetFileNameWithoutExtension(exePath);7                 IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutPath);8                 shortcut.TargetPath = exePath;  //目标路径9                 shortcut.WorkingDirectory = System.IO.Path.GetDirectoryName(exePath); //工作目录
10                 shortcut.WindowStyle = 1;
11                 shortcut.Description = exeName;  //描述
12                 shortcut.IconLocation = exePath + ",0";  //图标位置
13                 shortcut.Arguments = ""; //启动参数
14                 shortcut.Save();
15             }
16             catch (Exception ex)
17             {
18                 
19             }
20         }

创建开机自启,

直接使用上面的函数,将lnk创建到 shell:Startup路径即可。

1  var shortcutPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName + ".lnk";

创建控制面板卸载程序项

这里主要对注册表进行操作

计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

增加一个GUID项,代表产品ID。

 然后在项下增加图中所示的键值

这里只需要增加一些常用的属性即可。上图是微软的安装程序创建的,我是直接参考上图创建。

完整的属性可以参考 Properties (Windows Installer) - Win32 apps | Microsoft Learn

我这里定义的数据结构如下:

     public class SetupProperty{public string ProductId => "{C8997941-26F4-4E38-A5BD-D6306F0A8FC2}";  //我的产品IDpublic string Comments => "描述";public string Contact => "";public string DisplayIcon => System.Reflection.Assembly.GetExecutingAssembly().Location;public string DisplayName => "控制面板显示名称";public string DisplayVersion => VersionUtil.GetVersionString();public int EstimatedSize { get; set; }public string HelpLink => "";public string InstallDate => DateTime.Now.ToString();public string InstallLocation { get; set; }public string InstallSource { get; set; }public string UninstallString { get; set; }public string Publisher => "发布者";}

创建代码如下:

     public void CreateUninstallInRegistry(SetupProperty setupProperty){try{var productKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{setupProperty.ProductId}");foreach (var property in setupProperty.GetType().GetProperties()){if (property.Name == nameof(setupProperty.ProductId))continue;if (property.Name == nameof(setupProperty.EstimatedSize)){productKey.SetValue(property.Name, property.GetValue(setupProperty), Microsoft.Win32.RegistryValueKind.DWord);}else{productKey.SetValue(property.Name, property.GetValue(setupProperty), Microsoft.Win32.RegistryValueKind.String);}}}catch{}  }

创建完成后就可以在控制面板看到自己添加的新项目。

这里需要注意的的UninstallString这个值就是在控制面板点击卸载时,系统执行的操作。文末的如何制作卸载程序这部分会说明如何设置UninstallString。

安装进度及状态显示

界面上放置一个progressbar,将每个阶段划分一定的比例,然后再计算tick,显示到progressbar上即可。

如何制作卸载程序

像微软的msi安装包安装后,都会缓存在

C:\ProgramData\Package Cache\{ProductId}\Installers

一些应用软件的msi安装包会缓存 在

C:\Users\x\AppData\Local\Downloaded Installations

之所以要缓存 ,因为后面卸载是需要用到这些安装包的,这里不做详细介绍,可以自行查找资料了解。

我这里也在安装完成后,将安装包缓存在C:\Users\x\AppData\Local\Downloaded Installations目录下。

然后在程序中增加一个卸载的命令行参数判断

    public enum SetupType{Install,UnInstall}public partial class App : Application{public static SetupType SetupType = SetupType.Install;protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);if (e.Args.Length > 0 && e.Args[0].ToUpper() == nameof(SetupType.UnInstall).ToUpper())SetupType = SetupType.UnInstall;}}

当程序以uninstall参数启动时,执行卸载。

在删除依赖库时,依旧是通过程序的命令行参数或msiexec来执行卸载。

像Microsoft Visual C++ 2015-2022 Redistributable (x64) 的卸载参数是/uninstall /passive

msiexec.exe的卸载参数是/uninstall {0} /qn

所以我们在安装完成后在设置注册表项的UninstallString键值时,需要设置为带uninstall的值。

假设产品id是{02A54AEC-9C54-4BAC-AAC7-FBA39DDC8381},安装程序的名称为setup.exe,UninstallString就设置为"C:\Users\x\AppData\Local\Downloaded Installations\setup.exe uninstall"

这样在控制面板中就能正确卸载。

最后需要注意的就是,像注册COM,创建注册表都是需要管理员权限 的,可以将程序设置为管理员权限运行。

示例代码

GitHub - zhaotianff/CustomInstaller: Simple custom installer

//还有一个64位系统下32位软件的注册表路径

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3267577.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构(Java):Map集合Set集合哈希表

目录 1、介绍 1.1 Map和Set 1.2 模型 2、Map集合 2.1 Map集合说明 2.2 Map.Entry<K&#xff0c;V> 2.3 Map常用方法 2.4 Map注意事项及实现类 3、Set集合 3.1 Set集合说明 3.2 Set常用方法 3.3 Set注意事项及其实现类 4、TreeMap&TreeSet 4.1 集合类TreeM…

嵌入式中什么是三次握手

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」&#xff0c;点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 在网络数据传输中&#xf…

pytorch3d的安装

在这个网址中&#xff0c;下载对应的pytorch3d安装包 https://anaconda.org/pytorch3d/pytorch3d/files下载完成后使用下面命令进行安装 conda install ./pytorch3d-0.7.7-py39_cu118_pyt201.tar.bz2

可见性::

目录 定义&#xff1a; 解决方法&#xff1a; ①使用synchronized实现缓存和内存的同步 修改一&#xff1a; 加入语句&#xff1a; 代码&#xff1a; 修改2&#xff1a; 在代码块中加入&#xff1a; 代码&#xff1a; 执行结果&#xff1a; 原因&#xff1a; ②使用…

Linux--Socket 编程 UDP(简单的回显服务器和客户端代码)

目录 0.上篇文章 1.V1 版本 - echo server 1.1认识接口 1.2实现 V1 版本 - echo server&#xff08;细节&#xff09; 1.3添加的日志系统&#xff08;代码&#xff09; 1.4 解析网络地址 1.5 禁止拷贝逻辑&#xff08;基类&#xff09; 1.6 服务端逻辑 &#xff08;代码&…

【C/C++】printf和cout的区别

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

解析资源库架构模式

无论应用程序的设计方法和实现技术如何发展&#xff0c;数据访问仍然是任何系统都需要考虑的基础技术问题。针对数据访问过程&#xff0c;我们可以理解为任何一个系统都应该存在这样一个起点&#xff0c;我们可以从这个起点遍历到具体的数据。换句话说&#xff0c;系统中应该存…

Python爬虫掌握-----4实战(爬取视频)

我们使用爬虫时难免会遇到爬取视频的情况&#xff0c;其实爬取图片视频&#xff0c;内容都是一样的。这里以b站视频为例。 一、开始 1.找到url&#xff0c;请求url 防盗链&#xff0c;需要写在UA伪装中 正常的三步&#xff1a; 1.url 2.requests请求 3.UA伪装 import req…

2024最新网络安全自学路线,内容涵盖3-5年技能提升

01 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

做一个能和你互动玩耍的智能机器人之二

智能机器人硬件的一些注意事项和知识和初学者的误区。 一。不要担心不会焊接&#xff0c;我也是购买后才发现&#xff0c;现在的很多板子和元器件可以无焊接使用&#xff0c;比如借助杜邦线和面包板&#xff0c;可以很方便连接。 二。arduino有很多种&#xff0c;一般用的是n…

【Java算法专场】二分查找(上)

目录 前言 什么是二分查找&#xff1f; 二段性 ​​​​​​​​​​​​​​​​​​​​​二分查找 算法分析 算法步骤 算法代码 算法示例 模板 在排序数组中查找元素的第一个和最后一个位置 算法分析 算法步骤 算法代码 算法示例 搜索插入位置 算法分析 算法步…

IEC104转MQTT网关支持将IEC104数据转换为华为云平台可识别的格式

随着智能电网和物联网技术的深度融合&#xff0c;传统电力系统中的IEC104协议设备正逐步向更加开放、智能的物联网体系转型。华为云作为全球领先的云计算和AI服务提供商&#xff0c;其物联网平台为IEC104设备的接入与数据处理提供了强大的支撑。本文将探讨IEC104转MQTT网关在MQ…

KETTLE运行出现乱码和无法执行问题及解决方案

一、乱码问题 &#xff08;1&#xff09;出现乱码&#xff0c;在数据库连接里面的选项里面加入&#xff1a;characterEncodingutf8和tinyInt1isBitfalse &#xff08;2&#xff09;取消简易转换&#xff0c;点开表输入&#xff0c;取消”允许简易转换”选项&a…

vue3.0学习笔记(一)——vue3简介与vite脚手架的使用

1. 为什么学vue3 Vue3现状&#xff1a; vue-next 2020年09月18日&#xff0c;正式发布vue3.0版本。但是由于刚发布周边生态不支持&#xff0c;大多数开发者处于观望。现在主流组件库都已经发布了支持vue3.0的版本&#xff0c;其他生态也在不断地完善中&#xff0c;这是趋势。…

梯度下降算法在逻辑回归中的应用

逻辑回归简介 sigmoid函数&#xff1a; g ( z ) 1 1 e − z g(z) \frac{1}{1e^{-z}} g(z)1e−z1​ 逻辑回归假设函数&#xff1a; y ^ h θ ( x ) g ( θ T x ) 1 1 e − θ T x \hat{y} h_{\theta}(x) g(\theta^Tx) \frac{1}{1e^{-\theta^Tx}} y^​hθ​(x)g(θTx)…

我的世界!

每位冒险家在《我的世界》中的出生点都各不相同&#xff0c; 有的出生在桦木森林&#xff0c;有的出生在草原&#xff0c; 还有的出生在临近海洋的沙滩。 这些环境叫做生物群系&#xff0c;也常被称为生态系统。 在《我的世界》中的不同生物群系具有不同的地域特色—— 不…

Redis的五种数据类型与命令

目录 引言 一 Redis的特性 二 Redis的安装 三 Redis的优点 四 Redis的五种数据类型与命令 五 Redis的配置文件 引言 Redis是什么&#xff1f; Remote Dictionary Service(远程字典服务器) Redis 是一个开源的(BSD许可)的&#xff0c;C语言编写的&#xff0c;高性能的数…

羊大师:夏夜贪凉,但为啥肚子还要‘保暖计划’?

在这个夏夜&#xff0c;当空调与风扇齐飞&#xff0c;冰镇西瓜与凉面共舞之时&#xff0c;你是否也曾有过这样的疑惑&#xff1a;明明热得汗流浃背&#xff0c;为啥老一辈总念叨着“睡觉再热也要给肚子盖被子”&#xff1f;这背后&#xff0c;藏着的可不仅仅是老一辈的固执&…

centos7手动编译安装redis-6.2.1.tar.gz

本章教程,主要通过手动编译安装的方式,进行安装redis-6.2.1版本,如果需要安装其它版本的,可以在这里找到对应版本进行下载,安装步骤基本上差不多。 下载地址:https://download.redis.io/releases/ 一、下载安装包 wget https://download.redis.io/releases/redis-6.2.1.…

SSM学习9:SpringBoot简介、创建项目、配置文件、多环节配置

简介 SpringBoot式用来简化Spring应用的初始搭建以及开发过程的一个框架 项目搭建 File -> New -> Project 选中pom.xml文件&#xff0c;设置为maven项目 项目启动成功 可以访问BasicController中的路径 配置文件 在resources目录下 application.properties 默…