NSIS实现安装前检测是否安装程序,程序是否运行,安装后关联程序默认打开方式,刷新文件图标
这段时间在公司研究C#程序的安装包尝试了vs自带的setup项目,效果不尽如意跟直接压缩没太大区别。老大让我试试用nullsoft做着试试…在这期间踩了好多好多坑…主要是网上找到的nullsoft教程都不太适合初学者。整理发布下我拼凑的这篇脚本。本人研究有限,仅为了项目开发而研究。高手勿喷。
正文开始,首先是nullsoft的官网,可以在下载页下载nsis。nsis仅是一个编译器
点击compile nsi scripts后把.nsi脚本文件扔进去就可以编译了。
这里是第一个坑…尼玛我才懒得学脚本语言。那好,再下载一个HM NIS Edit,其实嘛脚本文件拿什么文件编辑器打开都可以,但是这个HM NIS Edit自带向导,这就很友好了。这里提醒跟我一样c#的初学者一下打包的文件除了一些.txt文件和.pdb文件外几乎都是需要的…然后可以把需要打包的文件夹(release)先复制一份丢到其他文件夹中像这样
后面跟着向导弄完基本你的安装包就能正常工作了…
然后头疼的地方来了,定制化安装包,实现检测安装时是否在运行本软件,若运行则弹窗终止进程。检测是否安装旧版本,若安装则卸载旧版本。安装后自动关联文件默认打开方式,刷新文件图标。
还是那句话懒得学脚本语言。就白嫖呗。东拼西凑的可以用,有什么需要修改的自己看着办吧。上代码。
; Script generated by the HM NIS Edit Script Wizard.
!include "WordFunc.nsh"
!include "FileAssociation.nsh"
!include "FileFunc.nsh"
!include "nsProcess.nsh"
!include LogicLib.nsh
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "你的产品名字"
!define PRODUCT_VERSION "版本号"
!define PRODUCT_PUBLISHER "公司名"
!define PRODUCT_WEB_SITE "公司网址"
;定义注册表方便验证是否已安装,以及安装的版本
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\你的软件名.exe"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
;你产品的唯一标识号
!define UninstId "{BDB7DC98-77FE-4859-8B49-C66132185719}"
;定义打包方式,lzma追求最小体积
SetCompressor lzma
; MUI 1.67 compatible ------
!include "MUI.nsh"
; MUI Settings
!define MUI_ABORTWARNING
;定义安装程序图标
!define MUI_ICON "Install2.ico"
;定义卸载程序图标
!define MUI_UNICON "uninstall.ico"
; Language Selection Dialog Settings
!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"
; Welcome page
!insertmacro MUI_PAGE_WELCOME
; License page
!define MUI_LICENSEPAGE_CHECKBOX
;读取授权文件
!insertmacro MUI_PAGE_LICENSE "D:\repos\你的软件名\bin\x64\打包发布\授权文件.txt"
; Directory page
!insertmacro MUI_PAGE_DIRECTORY
; Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page
!define MUI_FINISHPAGE_RUN "$INSTDIR\你的软件名.exe"
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES
; Language files
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "SimpChinese"
; Reserve files
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
; MUI end ------
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "你的软件名.exe"
;不知道咋回事nsis一直默认写在x86下就干脆写死
InstallDir "C:\Program Files\你的产品名"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
ShowUnInstDetails show
;这个必须在调用前(.onit前)定义
!macro UninstallExisting exitcode uninstcommand
Push `${uninstcommand}`
Call UninstallExisting
Pop ${exitcode}
!macroend
Function .onInit
/*开始查找同名进程*/
nsProcess::_FindProcess "你的软件名.exe"
Pop $R0
IntCmp $R0 0 running no_running no_running
running:
MessageBox MB_ICONQUESTION|MB_YESNO "安装程序检测到 ${PRODUCT_NAME} 正在运行,是否强行关闭并继续安装?" IDYES dokill IDNO stopit
no_running:
GoTo endding
dokill:
nsProcess::_CloseProcess "你的软件名.exe"
Pop $R0
GoTo endding
stopit:
Abort
endding:
nsProcess::_Unload
/*查找同名进程结束*/
/*开始查找注册表看是否有装旧版本*/
ReadRegStr $0 HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "UninstallString"
${If} $0 != ""
${AndIf} ${Cmd} `MessageBox MB_YESNO|MB_ICONQUESTION "检测到有安装旧版本,需要卸载之前的版本吗?" /SD IDYES IDYES`
!insertmacro UninstallExisting $0 $0
${If} $0 <> 0
MessageBox MB_YESNO|MB_ICONSTOP "卸载失败, 继续安装吗?" /SD IDYES IDYES +2
Abort
${EndIf}
${EndIf}
/*结束查找注册表*/
;开始安装
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
;你软件中的文件
Section "MainSection" SEC01
SetOutPath "$INSTDIR"
File "D:\repos\你的软件名\bin\x64\打包发布\cef.pak"
SectionEnd
Section -AdditionalIcons
CreateShortCut "$SMPROGRAMS\你的产品名\Uninstall.lnk" "$INSTDIR\uninst.exe"
SectionEnd
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\你的软件名.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\你的软件名.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Function un.onUninstSuccess
HideWindow
/*清理注册表文件关联*/
${unregisterExtension} ".srp" "你的软件名"
${unregisterExtension} ".sdpc" "你的软件名"
/*清理注册表结束*/
;刷新文件图标
${RefreshShellIcons}
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从你的计算机移除。"
FunctionEnd
Function un.onInit
!insertmacro MUI_UNGETLANGUAGE
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "你确实要完全移除 $(^Name) ,其及所有的组件?" IDYES +2
Abort
;检测程序是否运行
nsProcess::_FindProcess "你的软件名.exe"
Pop $R0
IntCmp $R0 0 running no_running no_running
running:
MessageBox MB_ICONQUESTION|MB_YESNO "安装程序检测到 ${PRODUCT_NAME} 正在运行,是否强行关闭并继续卸载?" IDYES dokill IDNO stopit
no_running:
GoTo endding
dokill:
nsProcess::_CloseProcess "你的软件名.exe"
Pop $R0
GoTo endding
stopit:
Abort
endding:
nsProcess::_Unload
FunctionEnd
Section Uninstall
Delete "$INSTDIR\uninst.exe"
SetAutoClose true
SectionEnd
;添加文件关联
Section -AssociateToSdpcSrp
${registerExtension} "$INSTDIR\你的软件名.exe" ".srp" "你的软件名"
${registerExtension} "$INSTDIR\你的软件名.exe" ".sdpc" "你的软件名"
${RefreshShellIcons}
SectionEnd
;安装之前自动卸载旧版本
Function UninstallExisting
Exch $1 ; uninstcommand
Push $2 ; Uninstaller
Push $3 ; Len
StrCpy $3 ""
StrCpy $2 $1 1
StrCmp $2 '"' qloop sloop
sloop:
StrCpy $2 $1 1 $3
IntOp $3 $3 + 1
StrCmp $2 "" +2
StrCmp $2 ' ' 0 sloop
IntOp $3 $3 - 1
Goto run
qloop:
StrCmp $3 "" 0 +2
StrCpy $1 $1 "" 1 ; Remove initial quote
IntOp $3 $3 + 1
StrCpy $2 $1 1 $3
StrCmp $2 "" +2
StrCmp $2 '"' 0 qloop
run:
StrCpy $2 $1 $3 ; Path to uninstaller
StrCpy $1 161 ; ERROR_BAD_PATHNAME
GetFullPathName $3 "$2\.." ; $InstDir
IfFileExists "$2" 0 +4
ExecWait '"$2" /S _?=$3' $1 ; This assumes the existing uninstaller is a NSIS uninstaller, other uninstallers don't support /S nor _?=
IntCmp $1 0 "" +2 +2 ; Don't delete the installer if it was aborted
Delete "$2" ; Delete the uninstaller
RMDir "$3" ; Try to delete $InstDir
RMDir "$3\.." ; (Optional) Try to delete the parent of $InstDir
Pop $3
Pop $2
Exch $1 ; exitcode
FunctionEnd
Section
SetOutPath $InstDir
WriteUninstaller "$InstDir\uninst.exe"
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "DisplayName" "你的软件名"
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "UninstallString" '"$InstDir\uninst.exe"'
WriteRegStr HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}" "QuietUninstallString" '"$InstDir\uninst.exe" /S'
SectionEnd
Section Uninstall
Delete "$InstDir\你的软件名.exe"
DeleteRegKey HKCU "Software\Software\Microsoft\Windows\CurrentVersion\Uninstall\${UninstId}"
Delete "$InstDir\uninst.exe"
RMDir "$InstDir"
SectionEnd
一定要用nsprocess才能控制进程,网上说的啥findprocess,killprocess都过时了。nsprocess是需要在官网上下载插件安装的。把头文件丢入include文件夹中,dll丢plugin文件夹。我也不知道放哪个,就每个文件夹扔了一份反正能用就完事了。
然后脚本文件同一目录下扔个nsProcess.nsh和FileAssociation.nsh。
FileAssociation.nsh中代码如下
代码源自nullsoft官网
/*
_____________________________________________________________________________
File Association
_____________________________________________________________________________
Based on code taken from http://nsis.sourceforge.net/File_Association
Usage in script:
1. !include "FileAssociation.nsh"
2. [Section|Function]
${FileAssociationFunction} "Param1" "Param2" "..." $var
[SectionEnd|FunctionEnd]
FileAssociationFunction=[RegisterExtension|UnRegisterExtension]
_____________________________________________________________________________
${RegisterExtension} "[executable]" "[extension]" "[description]"
"[executable]" ; executable which opens the file format
;
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
${UnRegisterExtension} "[extension]" "[description]"
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
_____________________________________________________________________________
Macros
_____________________________________________________________________________
Change log window verbosity (default: 3=no script)
Example:
!include "FileAssociation.nsh"
!insertmacro RegisterExtension
${FileAssociation_VERBOSE} 4 # all verbosity
!insertmacro UnRegisterExtension
${FileAssociation_VERBOSE} 3 # no script
*/
!ifndef FileAssociation_INCLUDED
!define FileAssociation_INCLUDED
!include Util.nsh
!verbose push
!verbose 3
!ifndef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE 3
!endif
!verbose ${_FileAssociation_VERBOSE}
!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE`
!verbose pop
!macro FileAssociation_VERBOSE _VERBOSE
!verbose push
!verbose 3
!undef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE ${_VERBOSE}
!verbose pop
!macroend
!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_DESCRIPTION}`
Push `${_EXTENSION}`
Push `${_EXECUTABLE}`
${CallArtificialFunction} RegisterExtension_
!verbose pop
!macroend
!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_EXTENSION}`
Push `${_DESCRIPTION}`
${CallArtificialFunction} UnRegisterExtension_
!verbose pop
!macroend
!define RegisterExtension `!insertmacro RegisterExtensionCall`
!define un.RegisterExtension `!insertmacro RegisterExtensionCall`
!macro RegisterExtension
!macroend
!macro un.RegisterExtension
!macroend
!macro RegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R2 ;exe
Exch
Exch $R1 ;ext
Exch
Exch 2
Exch $R0 ;desc
Exch 2
Push $0
Push $1
ReadRegStr $1 HKCR $R1 "" ; read current file association
StrCmp "$1" "" NoBackup ; is it empty
StrCmp "$1" "$R0" NoBackup ; is it our own
WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value
NoBackup:
WriteRegStr HKCR $R1 "" "$R0" ; set our file association
ReadRegStr $0 HKCR $R0 ""
StrCmp $0 "" 0 Skip
WriteRegStr HKCR "$R0" "" "$R0"
WriteRegStr HKCR "$R0\shell" "" "open"
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0"
Skip:
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
Pop $1
Pop $0
Pop $R2
Pop $R1
Pop $R0
!verbose pop
!macroend
!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!macro UnRegisterExtension
!macroend
!macro un.UnRegisterExtension
!macroend
!macro UnRegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R1 ;desc
Exch
Exch $R0 ;ext
Exch
Push $0
Push $1
ReadRegStr $1 HKCR $R0 ""
StrCmp $1 $R1 0 NoOwn ; only do this if we own it
ReadRegStr $1 HKCR $R0 "backup_val"
StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key
DeleteRegKey HKCR $R0
Goto NoOwn
Restore:
WriteRegStr HKCR $R0 "" $1
DeleteRegValue HKCR $R0 "backup_val"
DeleteRegKey HKCR $R1 ;Delete key with association name settings
NoOwn:
Pop $1
Pop $0
Pop $R1
Pop $R0
!verbose pop
!macroend
!endif # !FileAssociation_INCLUDED
感谢nullsoft和网上各位大神,没有大神的辛苦努力哪有我这样小白的幸福生活!是他们让我的工作变得简单。
本人小白一名如果有误欢迎指正。
本文介绍了如何使用nullsoft NSIS来创建C#程序的安装包,包括安装前检查程序是否运行,检测并卸载旧版本,以及安装后关联程序默认打开方式和刷新文件图标。作者分享了遇到的困难和解决方法,并提供了相关脚本资源。

1957

被折叠的 条评论
为什么被折叠?



