文章目录
- VS2022 - C#程序简单打包操作
- 概述
- 笔记
- 实验过程
- 新建工程
- 让依赖的运行时程序安装包在安装时运行(如果发现运行时不能每次都安装程序,就不要做这步)
- 关于”运行时安装程序无法每次都安装成功“的应对
- 知识点
- 尝试打包
- 旧工程bug修复
- 从需求属性中,可以原作者勾选的dotnet组件去掉
- 备注
- 打包工程要注意编译信息和运行时的报错信息
- END
VS2022 - C#程序简单打包操作
概述
以前用VS2019对C++程序打包做了一个笔记(vs2019 - 打包(开发机win10x64 - 目标机win7x64 - debug版程序))
有个打包新手同学(刚接触C#打包,才接触了10天),要对C#写的测试程序进行打包,自己搞不定。私信让我帮他搞一下。
看他私信明确要求是有偿服务,就帮他搞一下。如果没看到有偿字样的胡言乱语,俺应该直接将私信删了,没义务啊。
打包的事情全部依赖于VSIDE, 作为用户,我们如果要简单打包,需要的操作特别少,只需要几个固定的步骤就可以完成一个简单的打包。
这个笔记作为解决完问题的一个记录,也作为C#打包新手同学的小礼物。
他遇到的打包问题简单,实际解决后,也和我解决问题前的预计差不多。
开始远程看他桌面前,商量用“腾讯会议”来远程,我没用过. 以前和同事远程都是用TeamViewer,AnyDesk,向日葵,那时的同事没人用"腾讯会议"。
因为确实第一次用么,确实不会用。结果我加入会议后,不知道怎么请求操纵对方桌面,这不就是一个菜单在哪里的问题么?
但是我第一次用,我应该不知道菜单在哪里。如果能找到菜单那么应该是在常见,显眼的位置,或者和VS/IDEA比较像。
他居然质疑我不论是搞C++的还是其他IT行业,不知道怎么操作"腾讯会议"的远程控制的菜单位置,这是基本的素质问题。
我不知道他咋能说出这样的话。你是让我帮你解决打包工程的问题,又不是你面试我。现在哥也不需要别人来面试我,没需求啊。只要你让哥看一下你演示的问题(不局限在C#打包这样简单的问题),哥立马会给你分析一些可能的原因,再看哥做一些实验来验证想法,就能将问题解决掉,再将随着实验做的调试笔记转成pdf传给你,华丽的展示解决问题的思路和整个过程,你这辈子再也不会嫌弃哥不会操作"腾讯会议", 再也不会质疑哥的基本素质。
你会操作"腾讯会议",也就是你们同事之间都用这个,一个工具,用过一次就会。我现在用过一次,我也会了,5分钟的事。这和素质有啥关系?
你能保证不同公司的人都用你知道的远程桌面工具? 现在开源的远程桌面工具也有很多,你都用过啊?我要是从开源的远程工具上改一个特别版给我们一起用,我保证让你不会用。
那你都会用"腾讯会议"来远程演示了,那你自己遇到的C#简单打包问题,你咋搞不定呢? 离你给我留私信都一个星期了,你都没搞定,这和会不会操作"腾讯会议"有啥关联?
哥在和你聊之前,也没打包过c#的安装程序。你交代了有偿任务后,准备好环境后,1个小时就搞定了。你看看哥基本素质咋样?
我的优点之一,就是分析问题能力强,解决问题能力强,思想火花落地能力强。
根本不需要,也不care谁说我基本素质有问题,特别是还要求着我帮忙的人,那我就更不care了。
笔记
看了远程问题演示,问题主要可能有2个:
- 桌面快捷方式有可能没指向C#写的主EXE.
- C#运行时可能没装。
他给的打包工程,文件添加的链接位置和我本地不一样,只能新建工程。
因为是简单的工程,新建工程比修复他的打包工程还简单。
后来发现,因为VS有bug, 他添加了错误组件无法去掉,导致编译报错,只能是新建工程,而不能修复工程。
C#我不常用,VS2022也不常用。
用VS2022准备C#环境用了一点时间。问题本身的解决时间并不长,主要时间花在验证调试想法上了。
实验过程
先在没有dotnet6.0的设备上运行RTGCheckTool.exe,报错如下
点击是,从MS官网在线下载dotnet6.0的安装包
https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/runtime-desktop-6.0.36-windows-x64-installer?cid=getdotnetcore
顺手将x86版本的dotnet6.0也下载下来备用。
https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/runtime-desktop-6.0.36-windows-x86-installer?cid=getdotnetcore
运行下载好的dotnet6.0的安装包 windowsdesktop-runtime-6.0.36-win-x64.exe, 先将运行环境装好(用来测试程序本身是否可以在本地正常运行,如果正常,再打包)。
测试了一下,主程序运行起来了。
这说明,只需要在debug文件夹内的exe和dll基础上,再安装了windowsdesktop-runtime-6.0.36-win-x64.exe,程序就是可以运行的。
现在可以用VS2022打开打包工程Setup1.vdproj, 来图形化配置打包参数了。
但是发现,用VS2022无法正常打开.vdproj这种工程文件。如果在选工程文件时,强行输入*, 然后选vdproj, 也会打开失败。
后来发现,VS2022安装完,并没有打开vdproj的能力,需要通过扩展,安装打包插件才可以。
等有提示了,说关闭VS后,继续安装。就关掉VS, 等MS安装工程的插件安装完成。
先试试,是否VS2022能正常打开已经存在的setup1.vdproj
试了一下,ok.
现在决定,是在这个工程上改bug, 还是新建工程来打包?
因为这是有问题的工程,还是先新建工程打包后,安装运行正常了,将打包流程弄清楚了。再从原始打包工程上改好了。
新建工程
就用第一个模板"Setup Project"就行。
尝试编译空的打包工程,可以编译过。
将左视图切到文件系统,用来添加打包的文件(在本地可以运行的文件集合exe, dll, 其他文件)
用鼠标,将要安装到TARGET文件夹的文件,全部拖到左视图的TARGET文件夹中。
用鼠标拖动的方法的好处,连子文件夹内的文件都添加进来了。
在用户桌面上添加应用exe的快捷方式,直接添加不好指向exe, 参数不熟啊。
直接在文件树应用文件夹中的主exe上右击,选择建立快捷方式。
这样可以保证这个exe的快捷方式参数都是对的,不用自己填。
在快捷方式上左击,在右边视图中的属性窗口上改快捷方式的名称为自己想要的中意名称。
如果需要图标,也可以自己选。
先将自己选中的图标,拷贝到相对于安装工程的目录。然后改属性Icon.
将图标拖动到安装工程的应用文件夹。
在主程序exe的快捷方式属性中,点击icon右边的按钮,浏览图标位置,确定即可。
设置完图标后,看到内容是Icon, 看不到图标的具体路径,不管他,这是VS做的不够好,不管他。
将快捷方式由应用文件夹拖动到打包工程的桌面文件夹。
让依赖的运行时程序安装包在安装时运行(如果发现运行时不能每次都安装程序,就不要做这步)
实验表明, windowsdesktop-runtime-6.0.36-win-x64.exe 不是每次都运行成功,导致安装程序失败,这不是我们能解决的问题。所以,windowsdesktop-runtime-6.0.36-win-x64.exe只推荐在用户计算机上手工安装一次,并不建议作为依赖的安装程序包含在主安装程序中。
这里只是说明如何给C#的打包程序添加安装时,需要安装依赖的安装包后,才结束安装的操作。
如果有自己的程序(保证不会更新系统DLL, 只是一些逻辑功能),需要在安装时运行一下,可以用这种方法。
在应用文件夹中,拖入下载好的windowsdesktop-runtime-6.0.36-win-x64.exe
现在让程序安装拷贝操作后,运行windowsdesktop-runtime-6.0.36-win-x64.exe,将dotnet环境装好后,再结束安装。
切到自定义操作
在安装环节,添加自定义操作
在自定义操作弹出的item对话框中,选中要在安装结束前运行的dotnet6的runtime exe, 点击OK添加。
那现在配置就完事了(需求已经满足,拷贝文件到安装文件夹,然后运行runtime.exe,再结束安装)
关于”运行时安装程序无法每次都安装成功“的应对
可以在“Custom Actions/Install"中加入自己的程序,由自己的程序来检测当前计算机是否由依赖,如果没依赖,就运行同级目录中的运行时安装包,这样控制的粒度就很细。也不用去探索VS是否提供检测运行时是否存在的功能。
知识点
windows本身就有命令 dotnet, 可以列出DotNet运行时都装了哪些。
将这个知识点包进自己的程序,就可以知道是否有自己关心的运行时是否已经安装。
先检测是否有dotnet命令,如果没有,自然需要安装。
如果有dotnet命令,再列出所有已经安装的运行时,在里面找是否有自己关心的运行时。如果没有,则需安装。
这个方法好。
C:\Users\me>dotnet --list-runtimes
Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 9.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 9.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 9.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
尝试打包
编译成功了
========== 全部重新生成: 1 成功,0 失败,0 已跳过 ==========
========== 重新生成 于 20:56:53 完成,耗时 19.678 秒 ==========
有些警告,来分析一下,是否碍事。
重新生成开始于 20:56:33...
------ Starting pre-build validation for project 'LsSetupV3' ------
WARNING: Unable to find dependency 'SYSTEM.SECURITY.CRYPTOGRAPHY.ALGORITHMS' (Signature='B03F5F7F11D50A3A' Version='6.0.0.0') of assembly 'ICSharpCode.SharpZipLib.dll'
WARNING: Unable to find dependency 'SYSTEM.SECURITY.CRYPTOGRAPHY.PRIMITIVES' (Signature='B03F5F7F11D50A3A' Version='6.0.0.0') of assembly 'ICSharpCode.SharpZipLib.dll'
WARNING: Unable to find dependency 'SYSTEM.NUMERICS.VECTORS' (Signature='B03F5F7F11D50A3A' Version='6.0.0.0') of assembly 'ICSharpCode.SharpZipLib.dll'
ICSharpCode.SharpZipLib.dll 这种是C#本身的DLL, 说没找到啥依赖,这不怕,只要安装拷贝后,先运行runtime.exe就ok, 不管这个,没啥影响。
------ Pre-build validation for project 'LsSetupV3' completed ------
------ 已启动全部重新生成: 项目: LsSetupV3, 配置: Debug ------
Building file 'D:\my_dev\all_mine\for_user\csdn_wq\LsSetup\LsSetupV3\LsSetupV3\Debug\LsSetupV3.msi'...
WARNING: File 'RTGCheckTool.exe' targeting 'x64' is not compatible with the project's target platform 'x86'
这是说exe是x64版本,但是打包工程是x86的,这不对,要改。
将打包工程改为x64的。
工程安装前,自动卸载旧版本,为所有用户安装。
现在再尝试打包,也是编译过了,看一下警告,是否有潜在问题。
重新生成开始于 21:07:48...
------ Starting pre-build validation for project 'LsSetupV3' ------
WARNING: Unable to find dependency 'SYSTEM.COLLECTIONS.CONCURRENT' (Signature='B03F5F7F11D50A3A' Version='6.0.0.0') of assembly 'ICSharpCode.SharpZipLib.dll'
WARNING: Unable to find dependency 'SYSTEM.SECURITY.CRYPTOGRAPHY.PRIMITIVES' (Signature='B03F5F7F11D50A3A' Version='6.0.0.0') of assembly 'ICSharpCode.SharpZipLib.dll'
这个不需要管,只要安装程序安装了目标文件夹中的windowsdesktop-runtime-6.0.36-win-x64.exe,依赖就有了。
------ Pre-build validation for project 'LsSetupV3' completed ------
------ 已启动全部重新生成: 项目: LsSetupV3, 配置: Debug ------
Building file 'D:\my_dev\all_mine\for_user\csdn_wq\LsSetup\LsSetupV3\LsSetupV3\Debug\LsSetupV3.msi'...
WARNING: Two or more objects have the same target location ('[targetdir]\npoi.ooxml.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\npoi.ooxml.dll')
这个不用管,应用文件夹中没有重复的文件,这应该是VS的bug.
没有其他警告了。
试运行一下安装程序,看看效果如何?
看工程属性,找到生成好的安装程序。
从时间上看,这是刚生成的,运行安装程序看看效果。
先关掉VS, 再运行安装程序。
如果已经安装了程序,先卸载程序。发现windowsdesktop-runtime-6.0.36-win-x64.exe的每次安装,选修复时,不是每次都成功。
安装时,会先弹出运行时的安装程序(windowsdesktop-runtime-6.0.36-win-x64.exe),选择修复,等待修复完成。如果windowsdesktop-runtime-6.0.36-win-x64.exe安装失败,就会导致整个安装程序失败。
改一下安装程序,不包括自定义动作安装"windowsdesktop-runtime-6.0.36-win-x64.exe", 让安装程序和 windowsdesktop-runtime-6.0.36-win-x64.exe 分开,这样,只需要安装一次 windowsdesktop-runtime-6.0.36-win-x64.exe,setup程序可以安装多次,这样比较好。
重新打包,先安装windowsdesktop-runtime-6.0.36-win-x64.exe, 只需安装一次成功就行。再同一个计算机上,以后只安装setup.msi.
如果不确定是否安装了依赖,可以先安装setup.msi, 等运行时报错时,再安装windowsdesktop-runtime-6.0.36-win-x64.exe。
可以看到,已经正常安装完了。
桌面上也有了主程序的快捷方式。
运行一下试试。
C#主程序运行正常, ok了
到此,基于新工程模板建立的打包工程完全成功。
现在卸掉此工程,下一步来调试旧工程,看看问题出在哪里?
可以看到,控制面板中也有这个已经安装的程序。将此程序卸载。
旧工程bug修复
先将工程改为x64版本
将打包的桌面文件夹的快捷方式先删了,这个快捷方式不对,重新添加主程序exe的快捷方式。
先重新编译一下工程,看看是否报错
报错了
重新生成开始于 21:47:13...
------ Starting pre-build validation for project 'Setup1' ------
ERROR: Unable to find source file 'D:\my_dev\all_mine\for_user\csdn_wq\RTGCheckToolHigher\bin\Debug\net6.0-windows\RTGCheckTool.pdb' for file 'RTGCheckTool.pdb', located in '[TARGETDIR]', the file may be absent or locked.
ERROR: Unable to find source file 'D:\my_dev\all_mine\for_user\csdn_wq\RTGCheckToolHigher\bin\Debug\net6.0-windows\MathNet.Numerics.dll' for assembly 'MathNet.Numerics.dll', located in '[TARGETDIR]'
ERROR: Unable to find source file 'D:\my_dev\all_mine\for_user\csdn_wq\RTGCheckToolHigher\bin\Debug\net6.0-windows\RTGCheckTool.deps.json' for file 'RTGCheckTool.deps.json', located in '[TARGETDIR]', the file may be absent or locked.
ERROR: Unable to find source file 'D:\my_dev\all_mine\for_user\csdn_wq\RTGCheckToolHigher\bin\Debug\net6.0-windows\NPOI.Core.dll' for assembly 'NPOI.Core.dll', located in '[TARGETDIR]'
原因,添加的文件都在另外一台计算机上做的,这个工程是拷贝到本机的,所有这些文件的硬链接都不对了。
删掉TARGET目录中的所有文件。
删的时候,如果有子文件夹,要删除子文件夹中文件,然后在子文件夹的父目录才能删除子文件夹。
按照前文方式添加所有文件,用鼠标拖过来就行
做主程序RTGCheckTool.exe的快捷方式,改名,然后拖到桌面文件夹。见前文,不重复描述。
编译工程,报错
ERROR: 要在“系统必备”对话框中启用“从与我的应用程序相同的位置下载系统必备组件”,必须将“Microsoft .NET Framework 4.7.2 (x86 和 x64)”项的文件“DotNetFX472\NDP472-KB4054530-x86-x64-AllOS-ENU.exe”下载到本地计算机。有关详细信息,请参见 http://go.microsoft.com/fwlink/?LinkId=616018。
ERROR: 要在“系统必备”对话框中启用“从与我的应用程序相同的位置下载系统必备组件”,必须将“Microsoft .NET Framework 4.7.2 (x86 和 x64)”项的文件“DotNetFX472\NDP472-KB4054530-x86-x64-AllOS-CHS.exe”下载到本地计算机。有关详细信息,请参见 http://go.microsoft.com/fwlink/?LinkId=616018。
ERROR: 要在“系统必备”对话框中启用“从与我的应用程序相同的位置下载系统必备组件”,必须将“.NET 运行时 6.0.36 (x64)”项的文件“net6coreruntime_x64\dotnet-runtime-6.0.36-win-x64.exe”下载到本地计算机。有关详细信息,请参见 http://go.microsoft.com/fwlink/?LinkId=616018。
ERROR: General failure building bootstrapper
ERROR: Unrecoverable build error - 0x80004005
========== 全部重新生成: 0 成功,1 失败,0 已跳过 ==========
========== 重新生成 于 21:53:54 完成,耗时 03.580 秒 ==========
这个工程开始加了Dotnet系统组件,应该删了才行。因为系统组件通过windowsdesktop-runtime-6.0.36-win-x64.exe来单独安装。
切到启动条件页
将启动条件中的DotNet组件删掉,不需要。
只能删掉一个,还剩一个无法删除。
那重新编译一下试试,还是报错。
剩下的一个组件,不确定是否是这个原因编译报错。
从需求属性中,可以原作者勾选的dotnet组件去掉
但是,启动选项中还有Dotnet4.72的选项。
再尝试编译,ok了
Packaging file 'NPOI.Core.dll'...
Packaging file 'NPOI.OOXML.dll'...
========== 全部重新生成: 1 成功,0 失败,0 已跳过 ==========
========== 重新生成 于 0:15:36 完成,耗时 19.460 秒 ==========
备注
到此,针对旧打包工程的分析,修复都已经完成。
VS打包工程是有bug, 这个我以前也发现过。如果发现打包工程有些设置,自己无意中设置错了,也只能开一个新打包工程,没有其他方法。
旧工程的问题主要是以下2点
- 添加了需求组件,这个不需要,通过手工先安装windowsdesktop-runtime-6.0.36-win-x64.exe来解决,不需要添加啥Dotnet组件。
- 快捷方式要从exe本身来创建,然后改名,然后拷贝到打包工程的桌面文件夹中。而不要在桌面文件夹中直接建立exe的快捷方式。这种方法不是不行,而是我们不熟(快捷方式的参数咋填啊?你能保证填对么?),还是让VS的UI来直接生成正确的快捷方式,我们来改名,移动位置好一些。
打包工程要注意编译信息和运行时的报错信息
不管打包工程是否编译过,都要检查所有警告信息,如果有不对的地方(e.g. x64的exe, 打包工程却是x86的),要改正。
如果点击快捷方式这种没动静,或者报错,要针对具体情况分析,是缺少依赖(运行时没安装)?还是快捷方式没指向exe本身?