老程序员分享:NSIS自定义界面,下载并安装Net.Framework4.8

简介: 老程序员分享:NSIS自定义界面,下载并安装Net.Framework4.8

以 ScreenToGif 这款软件为例,详细讲解如何在安装的过程中检测并下载net包进行安装。


前言


1、ScreenToGif 是一款开源的截屏软件,依赖于Net.Framework环境


2、本文讲解的NSIS安装过程为自定义界面,而非传统界面(需要传统界面的留言区留言)。


3、Win10系统好像是自动集成了Net.Framework4.8的环境


4、安装Net.Framework4.0以上的版本,需要先安装微软证书,再安装Net.Framework安装,否则可能安装不成功,如下图:


?


相关资源


微软证书2011下载链接:


Net.Framework4.8离线包下载链接:


本文中的安装示例包:


链接: 链接:


提取码: 2g6y


NSIS使用到的插件


1、nsNiuniuSkin:基于Duilib的界面库(自定义界面的界面库)


2、nsis7zU:压缩及解压


3、inetc:下载文件(增加下载回调,当前进度,下载包大小,已下载大小,下载速度 ,剩余时间等信息)


4、KillProcDLL:结束进程(增加向结束进程发送主线程消息,进而实现被结束的进程安全退出,默认的结束方式为强制结束进程)


系统相关的问题


1、Win10系统使用NSIS创建任务栏图标会失败,Win10以下的系统无问题。


2、如果你的应用程序启动需要管理员身份启动,哪么添加开机启动将会失败。


制作好的安装包安装过程:


?


安装过程的逻辑


1、验证系统当前的net版本是否低于 4.8.03761,如果低于 4.8.03761 则做如下逻辑:


下载微软证书


安装微软证书


下载net安装包


安装net安装包


NSIS功能代码分享


代码段相关的宏定义


# ====================== 自定义宏 产品信息==============================


!define PRODUCT_NAME "ScreenToGif"


#安装卸载项用到的KEY


!define PRODUCT_PATHNAME "ScreenToGif"


#安装路径追加的名称


!define INSTALL_APPEND_PATH "ScreenToGif"


#默认生成的安装路径


!define INSTALL_DEFALT_SETUPPATH ""


#执行文件名称


!define EXE_NAME "ScreenToGif.exe"


#版本号


!define PRODUCT_VERSION "1.0.0.0"


#主页地址


!define HOME_URL ""


#用户条款


!define TERMS_URL ""


#产品发布商


!define PRODUCT_PUBLISHER "Nicke Manarin"


#产品法律


!define PRODUCT_LEGAL "Nicke Manarin Copyright(c)2020"


#打包出来的文件名称


!define INSTALL_OUTPUTNAME "ScreenToGif${PRODUCT_VERSION}.exe"


#应用程序的数据目录


!define LOCAL_APPDATA_DIR "$LOCALAPPDATA\ScreenToGif"


#打包文件目录


!define APP_FILE_DIR "D:\myCode\app\app-qt-client\PackageDirectory\ScreenToGif"


#文件数量


!define APP_FILE_COUNT 9


#完整安装包下载地址


!define //代码效果参考:http://hnjlyzjd.com/hw/wz_24011.html

ALL_SETUP_DL_URL ""

#Net包名称


!define NET_PACK_NAME "ndp48-x86-x64-allos-enu.exe"


#Net包下载地址


!define NET_PACK_DL_URL ""


#微软证书名称(win7安装net4.6以上版本需下载微软证书并安装,否则net安装会失败)


#net4.0不需要安装微软证书


!define MS_ROOT_CERT_NAME "MicrosoftRootCertificateAuthority2011.cer"


#微软证书下载地址


!define MS_ROOT_CERT_DL_URL ""


获取net版本


;获取.Net Framework版本支持


Function GetNetFrameworkVersion


Push $1


Push $0


ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "Install"


ReadRegDWORD $1 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "Version"


StrCmp $0 1 KnowNetFrameworkVersion +1


ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" "Install"


ReadRegDWORD $1 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" "Version"


StrCmp $0 1 KnowNetFrameworkVersion +1


ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0\Setup" "InstallSuccess"


ReadRegDWORD $1 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0\Setup" "Version"


StrCmp $0 1 KnowNetFrameworkVersion +1


ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727" "Install"


ReadRegDWORD $1 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727" "Version"


StrCmp $1 "" +1 +2


StrCpy $1 "2.0.50727.832"


StrCmp $0 1 KnowNetFrameworkVersion +1


ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v1.1.4322" "Install"


ReadRegDWORD $1 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v1.1.4322" "Version"


StrCmp $1 "" +1 +2


StrCpy $1 "1.1.4322.573"


StrCmp $0 1 KnowNetFrameworkVersion +1


ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft.NETFramework\policy\v1.0" "Install"


ReadRegDWORD $1 HKLM "SOFTWARE\Microsoft.NETFramework\policy\v1.0" "Version"


StrCmp $1 "" +1 +2


StrCpy $1 "1.0.3705.0"


StrCmp $0 1 KnowNetFrameworkVersion +1


StrCpy $1 "not .NetFramework"


KnowNetFrameworkVersion:


Pop $0


Exch $1


FunctionEnd


下载微软证书


; 微软证书下载回调


Function MicrosoftCertificatePackDownLoadCallBack


; 0-当前进度(百分比)


Pop $0


; 1-累计大小


Pop $1


; 2-已下载大小


Pop $2


; 3-下载速度


Pop $3


; 4-剩余时间


Pop $4


;更新包下载进度


; 当前进度


push $0


; 当前剩余时间


push $4


FunctionEnd


;下载微软证书


Function DownloadMicrosoftCertificate


GetFunctionAddress $R9 MicrosoftCertificatePackDownLoadCallBack


inetc::get "${MS_ROOT_CERT_DL_URL}" "$TEMP\${MS_ROOT_CERT_NAME}" $R9


; 读取值


Pop $1


; 写入值($1="ok"表示下载成功)


Push $1


FunctionEnd


安装微软证书


AddCertificateToStore


Exch $0


Push $1


Push $R0


System::Call "crypt32::CryptQueryObject(i ${CERT_QUERY_OBJECT_FILE}, w r0, \


i ${CERT_QUERY_CONTENT_FLAG_ALL}, i ${CERT_QUERY_FORMAT_FLAG_ALL}, \


i 0, i 0, i 0, i 0, i 0, i 0, *i .r0) i .R0"


${If} $R0 0


System::Call "crypt32::CertOpenStore(i ${CERT_STORE_PROV_SYSTEM}, i 0, i 0, \


i ${CERT_STORE_OPEN_EXISTING_FLAG}|${CERT_SYSTEM_STORE_LOCAL_MACHINE}, \


w 'ROOT') i .r1"


${If} $1 0


System::Call "crypt32::CertAddCertificateContextToStore(i r1, i r0, \


i ${CERT_STORE_ADD_ALWAYS}, i 0) i .R0"


System::Call "crypt32::CertFreeCertificateContext(i r0)"


${If} $R0 = 0


StrCpy $0 "Unable to add certificate to certificate store"


${Else}


StrCpy $0 "success"


${EndIf}


System::Call "crypt32::CertCloseStore(i r1, i 0)"


${Else}


System::Call "crypt32::CertFreeCertificateContext(i r0)"


StrCpy $0 "Unable to open certificate store"


${EndIf}


${Else}


StrCpy $0 "Unable to open certificate file"


${EndIf}


Pop $R0


Pop $1


Exch $0


FunctionEnd


; 安装微软证书


Function InstallMicrosoftCertificate


Push $TEMP\${MS_ROOT_CERT_NAME}


Call AddCertificateToStore


Pop $0


${If} $0 == success


; 安装完成,删除文件


Delete "$TEMP\${MS_ROOT_CERT_NAME}"


${EndIf}


; $0=success表示安装成功


Push $0


FunctionEnd


下载net安装包


; Net安装包下载回调


Function NetPackDownLoadCallBack


; 0-当前进度(百分比)


Pop $0


; 1-累计大小


Pop $1


; 2-已下载大小


Pop $2


; 3-下载速度


Pop $3


; 4-剩余时间


Pop $4


FunctionEnd


;下载 .NET Framework 4.0


Function DownloadNetFramework4


GetFunctionAddress $R9 NetPackDownLoadCallBack


inetc::get "${NET_PACK_DL_URL}" "$TEMP\${NET_PACK_NAME}" $R9


; 读取值


Pop $1


; 写入值($1="ok"表示下载成功)


Push $1


FunctionEnd


安装net安装包


; 安装net包


Function InstallDotNetPack


; 安装net包


ExecWait '$TEMP\${NET_PACK_NAME} /q /norestart /ChainingPackage FullX64Bootstrapper' $R1


; 安装成功(安装成功返回0 16386 文件损坏 返回当前版本号 文件不存在)


${If} $R1 == 0


; 安装完成,删除安装包


Delete "$TEMP\${NET_PACK_NAME}"


${EndIf}


; 返回值($R1=0表示安装成功)


Push $R1


FunctionEnd


Net环境检测


; 检查net环境


Function CheckNetCondition


; net版本验证及安装


;检测是否是需要的.NET Framework版本


Call GetNetFrameworkVersion


Pop $R1


; ${If} $R1 [/span> '4.7.03062'


${If} $R1 < '4.8.03761'


; 下载微软证书


GetFunctionAddress $0 DownloadMicrosoftCertificate


; 等待结果


BgWorker::CallAndWait


; 弹出下载结果


Pop $R1


; 下载成功验证


${If} $R1 == "ok"


; 微软证书


GetFunctionAddress $0 InstallMicrosoftCertificate


BgWorker::CallAndWait


; 弹出安装结果


Pop $R2


; 安装结果验证


${If} $R2 != success


#微软证书安装完成


${Endif}


${EndIf}


; 下载net安装包


GetFunctionAddress $0 DownloadNetFramework4


; 等待结果


BgWorker::CallAndWait


; 弹出下载结果


Pop $R3


; 下载成功验证


${If} $R3 == "ok"


; 安装net包


GetFunctionAddress $0 InstallDotNetPack


BgWorker::CallAndWait


; 弹出安装结果


Pop $R4


; 安装结果验证


${If} $R4 == 0


#net包安装成功


${EndIf}


${EndIf}


${EndIf}


FunctionEnd


结束指定进程


#注:ShowMsgBox 可更换为MessageBox使用系统提示框提示


; 结束进程


; 返回0 表示结束成功 返回1 表示退出安装


Function KillProc


#此处检测当前是否有程序正在运行,如果正在运行,提示先卸载再安装


nsProcess::_FindProcess "${EXE_NAME}"


Pop $R0


#验证查询结果


${If} $R0 == 0


; 弹框提示


StrCpy $R8 "检测到 ${EXE_NAME} 正在运行。点击 “确定” 结束进程${EXE_NAME},继续安装。点击 “取消” 退出安装程序。"


StrCpy $R7 "1"


Call ShowMsgBox


Pop $0


; 结束进程


${If} $0 == 1


; 设置安装提示


nsNiuniuSkin::SetControlAttribute $hInstallDlg "progress_tip" "text" "正在安全的结束进程,请稍后..."


#结束进程


KillProcDLL::KillProc"${EXE_NAME}"


${Else}


#设置返回值


push 1


; 退出


goto KillProcEnd


${EndIf}


#循环验证


${For} $R1 0 100


#等待100毫秒再查询结果


Sleep 100


#接收结果


nsProcess::_FindProcess "${EXE_NAME}"


#检测进程


Pop $R0


; 判断进程是否存在


${If} $R0 != 0


#设置返回值


push 0


; 查找进程结束


goto KillProcEnd


${EndIf}


${Next}


; 弹框提示


StrCpy $R8 "我们无法安全的结束正在运行的 ${EXE_NAME} 应用程序,请手动退出应用程序,再尝试安装!"


StrCpy $R7 "0"


Call ShowMsgBox


#设置返回值


push 1


; 结束


KillProcEnd:


${EndIf}


FunctionEnd


创建桌面快捷方式


;创建桌面快捷方式


Function CreateDeskTopIco


#添加到桌面快捷方式的动作在此添加


SetShellVarContext all


CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\${EXE_NAME}"


SetShellVarContext current


FunctionEnd


创建任务栏快捷方式


注:Win10下可能存在问题,系统机制原因


;创建任务栏快捷方式


Function CreateBarlnk


ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "CurrentVersion"


${if} $R0 >= 6.0


SetOutPath $INSTDIR


;注意这句与下一句是有先后顺序的(与ExecShell taskbarpin关联)


CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\${EXE_NAME}"


;创建任务栏快捷方式(win10系统会失败,并且导致程序运行)


;ExecShell taskbarpin "$DESKTOP\${PRODUCT_NAME}.lnk"


${StdUtils.InvokeShellVerb} $0 "$INSTDIR" "${EXE_NAME}" ${StdUtils.Const.ShellVerb.PinToTaskbar}


${else}


CreateShortCut "$QUICKLAUNCH\${PRODUCT_NAME}.lnk" "$INSTDIR\${EXE_NAME}"


${Endif}


FunctionEnd


添加开机启动


注:应用软件如果需要管理员身份启动,开机可能无法正常启动


; 创建开机启动


; 备注:开机启动的项目不能为管理员身份启动,否则会启动不起来


Function CreateBootStart


WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCT_NAME}" "$INSTDIR\${EXE_NAME}"


FunctionEnd


创建开始菜单


Function CreateAppShortcut


SetShellVarContext all


CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"


CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\${EXE_NAME}"


CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\卸载${PRODUCT_NAME}.lnk" "$INSTDIR\uninst.exe"


SetShellVarContext current


FunctionEnd


创建卸载信息


# 生成卸载入口


Function CreateUninstall


#写入注册信息


SetRegView 32


WriteRegStr HKLM "Software\${PRODUCT_PATHNAME}" "InstPath" "$INSTDIR"


; WriteUninstaller "$INSTDIR\uninst.exe"


# 添加卸载信息到控制面板


WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_PATHNAME}" "DisplayName" "${PRODUCT_NAME}"


WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_PATHNAME}" "UninstallString" "$INSTDIR\uninst.exe"


WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_PATHNAME}" "DisplayIcon" "$INSTDIR\${EXE_NAME}"


WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_PATHNAME}" "Publisher" "${PRODUCT_PUBLISHER}"


WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_PATHNAME}" "DisplayVersion" "${PRODUCT_VERSION}"


FunctionEnd


卸载-删除快捷方式


;卸载时删除任务栏快捷方式


Function un.DelBarlnk


ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "CurrentVersion"


${if} $R0 >= 6.0


;win10系统会有问题


ExecShell taskbarunpin "$DESKTOP\${PRODUCT_NAME}.lnk"


${StdUtils.InvokeShellVerb} $0 "$INSTDIR" "${EXE_NAME}" ${StdUtils.Const.ShellVerb.UnpinFromTaskbar}


Delete "$DESKTOP\${PRODUCT_NAME}.lnk"


${else}


delete "$QUICKLAUNCH\${PRODUCT_NAME}.lnk"


${Endif}


FunctionEnd


;删除开始菜单,桌面图标


Function un.DeleteShotcutAndInstallInfo


SetRegView 32


DeleteRegKey HKLM "Software\${PRODUCT_PATHNAME}"


DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_PATHNAME}"


; 删除快捷方式


SetShellVarContext all


Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"


Delete "$SMPROGRAMS\${PRODUCT_NAME}\卸载${PRODUCT_NAME}.lnk"


RMDir "$SMPROGRAMS\${PRODUCT_NAME}\"


Delete "$DESKTOP\${PRODUCT_NAME}.lnk"


#删除开机启动


Delete "$SMSTARTUP\${PRODUCT_NAME}.lnk"


SetShellVarContext current


FunctionEnd


卸载删除开机启动


;卸载时删除开机启动


Function un.DelBootStart


DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCT_NAME}"


FunctionEnd


打开链接


; 打开链接


!define OpenURL '!insertmacro "_OpenURL"'


; 打开链接


!macro _OpenURL URL


Push "${URL}"


Call openLinkNewWindow


!macroend


; 新窗口打开链接


Function openLinkNewWindow


Push $3


Exch


Push $2


Exch


Push $1


Exch


Push $0


Exch


ReadRegStr $0 HKCR "http\shell\open\command" ""


# Get browser path


DetailPrint $0


StrCpy $2 '"'


StrCpy $1 $0 1


StrCmp $1 $2 +2 # if path is not enclosed in " look for space as final char


StrCpy $2 ' '


StrCpy $3 1


loop:


StrCpy $1 $0 1 $3


DetailPrint $1


StrCmp $1 $2 found


StrCmp $1 "" found


IntOp $3 $3 + 1


Goto loop


found:


StrCpy $1 $0 $3


StrCmp $2 " " +2


StrCpy $1 '$1"'


Pop $0


Exec '$1 $0'


Pop $0


Pop $1


Pop $2


Pop $3


FunctionEnd


;使用示例


${OpenURL} ""


完整源码下载

相关文章
|
2月前
|
Windows
.NET 隐藏/自定义windows系统光标
【10月更文挑战第20天】在.NET中,可以使用`Cursor`类来控制光标。要隐藏光标,可将光标设置为`Cursors.None`。此外,还可以通过从文件或资源加载自定义光标来更改光标的样式。例如,在表单加载时设置`this.Cursor = Cursors.None`隐藏光标,或使用`Cursor.FromFile`方法加载自定义光标文件,也可以将光标文件添加到项目资源中并通过资源管理器加载。这些方法适用于整个表单或特定控件。
|
4月前
|
开发框架 .NET Docker
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
|
4月前
|
C#
一款.NET开源、跨平台的DASH/HLS/MSS下载工具
一款.NET开源、跨平台的DASH/HLS/MSS下载工具
|
6月前
|
存储 分布式计算 大数据
MaxCompute操作报错合集之自定义udf的函数,引用了import net.sourceforge.pinyin4j.PinyinHelper;但是上传资源后,出现报错,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
117 0
|
7月前
|
开发框架 缓存 前端开发
安装ASP.NET AJAX (一安装)
安装ASP.NET AJAX (一安装)
113 0
|
7月前
|
SQL Windows
保姆级:Windows Server 2012上安装.NET Framework 3.5
保姆级:Windows Server 2012上安装.NET Framework 3.5
1263 0
|
7月前
|
存储 移动开发 前端开发
对象存储oss使用问题之OSS SDK .net 使用下载例程报错如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
120 0
|
7月前
|
安全 C# 开发者
.NET开源的一键自动化下载、安装、激活Microsoft Office利器
.NET开源的一键自动化下载、安装、激活Microsoft Office利器
167 5
|
7月前
|
Windows
windows server 2019 安装NET Framework 3.5失败,提示:“安装一个或多个角色、角色服务或功能失败” 解决方案
windows server 2019 安装NET Framework 3.5失败,提示:“安装一个或多个角色、角色服务或功能失败” 解决方案
1126 0
|
3月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
48 7