1. .DotNet版本检测代码准备。
Save the following code as DotNetVer.nsh file in your "NSIS/Include" folder. 比如:D:\Program Files (x86)\NSIS\Include\DotNetVer.nsh
; --------------------- ; DotNetVer.nsh ; Written by: David Grinberg ; Homepage: http://ontheperiphery.veraida.com/ ; Updated By: Brandon Hansen (http://www.remotehams.com/) ; --------------------- ; ; LogicLib extensions for checking Microsoft .NET Framework versions and service packs. ; ; Latests Updates by Brandon Hansen, KG6YPI (RemoteHams.com) ; Dec 26, 2011 - .NET Framework 4.0 detection fixes - client profile not being found ; Dec 07, 2010 - .NET Framework 4.0 detection added by Brandon Hansen (KG6YPI) ; ; Usage examples: ; ; ${If} ${HasDotNet4.0} ; DetailPrint "Microsoft .NET Framework 4.0 installed." ; ${If} ${DOTNETVER_4_0} AtLeastDotNetServicePack 1 ; DetailPrint "Microsoft .NET Framework 4.0 is at least SP1." ; ${Else} ; DetailPrint "Microsoft .NET Framework 4.0 SP1 not installed." ; ${EndIf} ; ${If} ${DOTNETVER_4_0} HasDotNetClientProfile 1 ; DetailPrint "Microsoft .NET Framework 4.0 (Client Profile) available." ; ${EndIf} ; ${If} ${DOTNETVER_4_0} HasDotNetFullProfile 1 ; DetailPrint "Microsoft .NET Framework 4.0 (Full Profile) available." ; ${EndIf} ; ${If} ${DOTNETVER_4_0} HasDotNetFullProfile 0 ; DetailPrint "Microsoft .NET Framework 4.0 (Full Profile) not available." ; ${EndIf} ; ${EndIf} !verbose push !verbose 3 !ifndef ___DOTNETVER__NSH___ !define ___DOTNETVER__NSH___ !include LogicLib.nsh !include Util.nsh # constants !define DOTNETVER_1_0 "1.0" !define DOTNETVER_1_1 "1.1" !define DOTNETVER_2_0 "2.0" !define DOTNETVER_3_0 "3.0" !define DOTNETVER_3_5 "3.5" !define DOTNETVER_4_0 "4.0" # variable declaration Var /GLOBAL __DONTNET_FOUNDVER !macro __DotNetVer_DeclareVars !ifndef __DOTNETVER_VARS_DECLARED !define __DOTNETVER_VARS_DECLARED Var /GLOBAL __DOTNET_1.0 Var /GLOBAL __DOTNET_1.1 Var /GLOBAL __DOTNET_2.0 Var /GLOBAL __DOTNET_3.0 Var /GLOBAL __DOTNET_3.5 Var /GLOBAL __DOTNET_4.0 Var /GLOBAL __DOTNETVER_1.0_SP Var /GLOBAL __DOTNETVER_1.1_SP Var /GLOBAL __DOTNETVER_2.0_SP Var /GLOBAL __DOTNETVER_3.0_SP Var /GLOBAL __DOTNETVER_3.5_SP Var /GLOBAL __DOTNETVER_4.0_SP Var /GLOBAL __DOTNET_1.0_CLIENT Var /GLOBAL __DOTNET_1.1_CLIENT Var /GLOBAL __DOTNET_2.0_CLIENT Var /GLOBAL __DOTNET_3.0_CLIENT Var /GLOBAL __DOTNET_3.5_CLIENT Var /GLOBAL __DOTNET_4.0_CLIENT Var /GLOBAL __DOTNET_1.0_FULL Var /GLOBAL __DOTNET_1.1_FULL Var /GLOBAL __DOTNET_2.0_FULL Var /GLOBAL __DOTNET_3.0_FULL Var /GLOBAL __DOTNET_3.5_FULL Var /GLOBAL __DOTNET_4.0_FULL StrCpy $__DOTNET_1.0 0 StrCpy $__DOTNET_1.1 0 StrCpy $__DOTNET_2.0 0 StrCpy $__DOTNET_3.0 0 StrCpy $__DOTNET_3.5 0 StrCpy $__DOTNET_4.0 0 StrCpy $__DOTNETVER_1.0_SP 0 StrCpy $__DOTNETVER_1.1_SP 0 StrCpy $__DOTNETVER_2.0_SP 0 StrCpy $__DOTNETVER_3.0_SP 0 StrCpy $__DOTNETVER_3.5_SP 0 StrCpy $__DOTNETVER_4.0_SP 0 StrCpy $__DOTNET_1.0_CLIENT 0 StrCpy $__DOTNET_1.1_CLIENT 0 StrCpy $__DOTNET_2.0_CLIENT 0 StrCpy $__DOTNET_3.0_CLIENT 0 StrCpy $__DOTNET_3.5_CLIENT 0 StrCpy $__DOTNET_4.0_CLIENT 0 StrCpy $__DOTNET_1.0_FULL 0 StrCpy $__DOTNET_1.1_FULL 0 StrCpy $__DOTNET_2.0_FULL 0 StrCpy $__DOTNET_3.0_FULL 0 StrCpy $__DOTNET_3.5_FULL 0 StrCpy $__DOTNET_4.0_FULL 0 !endif !macroend # lazy initialization macro !macro __DotNetVer_InitVars # only calculate version once StrCmp $__DONTNET_FOUNDVER "" dotnetver.noveryet Return dotnetver.noveryet: !insertmacro __DotNetVer_DeclareVars Push $0 ;registry count Push $1 ;registry key Push $2 ;version number Push $3 ;installed Push $4 ;service pack number Push $8 ;strLen helper var StrCpy $0 0 dotnetver.startenum: EnumRegKey $1 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP" $0 StrCmp $1 "" dotnetver.done IntOp $0 $0 + 1 StrCpy $2 $1 1 0 StrCmp $2 "v" +1 dotnetver.startenum StrCpy $2 $1 3 1 ; Check for .NET 1.0 to 3.5 ReadRegDWORD $3 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\$1" "Install" ReadRegDWORD $4 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\$1" "SP" ; This is a sanity check that works on .NET 1.0 to 3.5 ; if it fails check for dotnet 4 IntCmp $3 0 dotnetcheck.40 StrCmp $2 ${DOTNETVER_1_0} dotnetver.10 StrCmp $2 ${DOTNETVER_1_1} dotnetver.11 StrCmp $2 ${DOTNETVER_2_0} dotnetver.20 StrCmp $2 ${DOTNETVER_3_0} dotnetver.30 StrCmp $2 ${DOTNETVER_3_5} dotnetver.35 dotnetcheck.40: StrCmp $2 ${DOTNETVER_4_0} dotnetver.40 StrCmp $2 "4" dotnetver.40 Goto dotnetver.startenum dotnetver.10: StrCpy $__DOTNET_1.0 1 StrCpy $__DOTNETVER_1.0_SP $4 StrCpy $__DOTNET_1.0_FULL 1 Goto dotnetver.startenum dotnetver.11: StrCpy $__DOTNET_1.1 1 StrCpy $__DOTNETVER_1.1_SP $4 StrCpy $__DOTNET_1.1_FULL 1 Goto dotnetver.startenum dotnetver.20: StrCpy $__DOTNET_2.0 1 StrCpy $__DOTNETVER_2.0_SP $4 StrCpy $__DOTNET_2.0_FULL 1 Goto dotnetver.startenum dotnetver.30: StrCpy $__DOTNET_3.0 1 StrCpy $__DOTNETVER_3.0_SP $4 StrCpy $__DOTNET_3.0_FULL 1 Goto dotnetver.startenum dotnetver.35: StrCpy $__DOTNET_3.5 1 StrCpy $__DOTNETVER_3.5_SP $4 StrCpy $__DOTNET_3.5_FULL 1 Goto dotnetver.startenum dotnetver.40: ; Check for .NET 4.0 (Full Profile) ReadRegDWORD $3 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "Install" ReadRegDWORD $4 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "SP" StrLen $8 $3 IntCmp $8 0 dotnetcheck.40c IntCmp $3 0 dotnetcheck.40c StrCmp $2 ${DOTNETVER_4_0} dotnetver.40_Full StrCmp $2 "4" dotnetver.40_Full dotnetcheck.40c: ; Check for .NET 4.0 (Client Profile) ReadRegDWORD $3 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client" "Install" ReadRegDWORD $4 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client" "SP" StrLen $8 $3 IntCmp $8 0 dotnetver.startenum IntCmp $3 0 dotnetver.startenum StrCmp $2 ${DOTNETVER_4_0} dotnetver.40_Client StrCmp $2 "4" dotnetver.40_Client Goto dotnetver.startenum dotnetver.40_Full: StrCpy $__DOTNET_4.0 1 StrCpy $__DOTNETVER_4.0_SP $4 StrCpy $__DOTNET_4.0_FULL 1 Goto dotnetcheck.40c ; continue looking for other profiles dotnetver.40_Client: StrCpy $__DOTNET_4.0 1 StrCpy $__DOTNETVER_4.0_SP $4 StrCpy $__DOTNET_4.0_CLIENT 1 Goto dotnetver.startenum dotnetver.done: StrCpy $__DONTNET_FOUNDVER "1" Pop $8 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 !macroend !macro _HasDotNet _a _b _t _f ${CallArtificialFunction} __DotNetVer_InitVars !insertmacro _= `$__DOTNET_${_b}` `1` `${_t}` `${_f}` !macroend !macro __DotNetVer_DefineTest Ver !define HasDotNet${Ver} `"" HasDotNet ${Ver}` !macroend !insertmacro __DotNetVer_DefineTest ${DOTNETVER_1_0} !insertmacro __DotNetVer_DefineTest ${DOTNETVER_1_1} !insertmacro __DotNetVer_DefineTest ${DOTNETVER_2_0} !insertmacro __DotNetVer_DefineTest ${DOTNETVER_3_0} !insertmacro __DotNetVer_DefineTest ${DOTNETVER_3_5} !insertmacro __DotNetVer_DefineTest ${DOTNETVER_4_0} !macro _AtLeastDotNetServicePack _a _b _t _f ${CallArtificialFunction} __DotNetVer_InitVars !insertmacro _>= `$__DOTNETVER_${_a}_SP` `${_b}` `${_t}` `${_f}` !macroend !define AtLeastDotNetServicePack `AtLeastDotNetServicePack` !macro _AtMostDotNetServicePack _a _b _t _f ${CallArtificialFunction} __DotNetVer_InitVars !insertmacro _<= `$__DOTNETVER_${_a}_SP` `${_b}` `${_t}` `${_f}` !macroend !define AtMostDotNetServicePack `AtMostDotNetServicePack` !macro _IsDotNetServicePack _a _b _t _f ${CallArtificialFunction} __DotNetVer_InitVars !insertmacro _= `$__DOTNETVER_${_a}_SP` `${_b}` `${_t}` `${_f}` !macroend !define IsDotNetServicePack `IsDotNetServicePack` !macro _HasDotNetClientProfile _a _b _t _f ${CallArtificialFunction} __DotNetVer_InitVars !insertmacro _= `$__DOTNET_${_a}_CLIENT` `${_b}` `${_t}` `${_f}` !macroend !define HasDotNetClientProfile `HasDotNetClientProfile` !macro _HasDotNetFullProfile _a _b _t _f ${CallArtificialFunction} __DotNetVer_InitVars !insertmacro _= `$__DOTNET_${_a}_FULL` `${_b}` `${_t}` `${_f}` !macroend !define HasDotNetFullProfile `HasDotNetFullProfile` # done !endif # !___DOTNETVER__NSH___ !verbose pop
2. 准备打包文件。运行NSIS的VNISEdit 2.0.3编译环境。文件 -> 新建脚本(向导),用向导构建基本打包脚本框架。
3.修改向导生成的nsi文件。修改脚本、编译脚本、安装测试。不断完善。本实例包括.NET Framework 2.0 SP1检测和安装,DLL注册和卸载,已安装版本检测和重安装处理等,供学习参考。
; 该脚本使用 HM VNISEdit 脚本编辑器向导产生 ; 安装程序初始定义常量 !define VER_MAJOR 2 !define VER_MINOR 4 !define VER_REVISION 5 !define VER_BUILD 0 !define VERSION `${VER_MAJOR}.${VER_MINOR}.${VER_REVISION}.${VER_BUILD}` !define PRODUCT_NAME "Hello" !define PRODUCT_VERSION '${VERSION}' !define PRODUCT_PUBLISHER "My company, Inc." !define PRODUCT_WEB_SITE "http://www.mycompany.com" !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Hello.exe" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" SetCompressor lzma RequestExecutionLevel admin ; ------ MUI 现代界面定义 (1.67 版本以上兼容) ------ !include "MUI.nsh" !include "LogicLib.nsh" !include "DotNetVer.nsh" !include "WordFunc.nsh" !ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD !insertmacro VersionCompare !endif ; MUI 预定义常量 !define MUI_ABORTWARNING !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico" !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" ; 欢迎页面 !insertmacro MUI_PAGE_WELCOME ; 许可协议页面 !insertmacro MUI_PAGE_LICENSE "bin\COPYING.txt" ; 安装目录选择页面 !insertmacro MUI_PAGE_DIRECTORY ; 安装过程页面 !insertmacro MUI_PAGE_INSTFILES ; 安装完成页面 !define MUI_FINISHPAGE_RUN "$INSTDIR\Hello.exe" !insertmacro MUI_PAGE_FINISH ; 安装卸载过程页面 !insertmacro MUI_UNPAGE_INSTFILES ; 安装界面包含的语言设置 !insertmacro MUI_LANGUAGE "SimpChinese" ; 安装预释放文件 !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ; ------ MUI 现代界面定义结束 ------ Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" OutFile "Setup.exe" InstallDir "$PROGRAMFILES\Hello" InstallDirRegKey HKLM "${PRODUCT_UNINST_KEY}" "UninstallString" ShowInstDetails show ShowUnInstDetails show BrandingText " " Section "MainSection" SEC01 ;Shortcuts removal fails on Windows Vista SetShellVarContext all ;安装.NET Framework 2.0 SP1 ${If} ${HasDotNet2.0} DetailPrint "Microsoft .NET Framework 2.0 installed." ${If} ${DOTNETVER_2_0} IsDotNetServicePack 1 DetailPrint "Microsoft .NET Framework 2.0 SP1 installed." ${EndIf} ${If} ${DOTNETVER_2_0} IsDotNetServicePack 2 DetailPrint "Microsoft .NET Framework 2.0 SP2 installed." ${EndIf} ${If} ${DOTNETVER_2_0} IsDotNetServicePack 3 DetailPrint "Microsoft .NET Framework 2.0 SP3 installed." ${EndIf} ${Else} DetailPrint "正在安装 .NET Framework 2.0 SP1" SetDetailsPrint listonly SetOutPath "$INSTDIR" SetOverwrite on File "bin\NetFx20SP1_x86.exe" ExecWait '"$INSTDIR\NetFx20SP1_x86.exe" /quiet /norestart' ${EndIf} SetOutPath "$INSTDIR" SetOverwrite ifnewer File "bin\COPYING.txt" CreateDirectory "$SMPROGRAMS\Hello" CreateShortCut "$SMPROGRAMS\Hello\Hello.lnk" "$INSTDIR\Hello.exe" CreateShortCut "$DESKTOP\Hello.lnk" "$INSTDIR\Hello.exe" File "bin\Hello.exe" ;register dll File "bin\MSCOMM32.OCX" RegDLL "$INSTDIR\MSCOMM32.OCX" SectionEnd Section -AdditionalIcons ;Shortcuts removal fails on Windows Vista SetShellVarContext all WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" CreateShortCut "$SMPROGRAMS\Hello\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" CreateShortCut "$SMPROGRAMS\Hello\Uninstall.lnk" "$INSTDIR\uninst.exe" SectionEnd Section -Post WriteUninstaller "$INSTDIR\uninst.exe" WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\Hello.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\Hello.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 /****************************** * 以下是安装程序的卸载部分 * ******************************/ Section Uninstall ;Shortcuts removal fails on Windows Vista SetShellVarContext all ;unregister dll UnRegDLL "$INSTDIR\MSCOMM32.OCX" Delete "$INSTDIR\MSCOMM32.OCX" Delete "$INSTDIR\NetFx20SP1_x86.exe" Delete "$INSTDIR\${PRODUCT_NAME}.url" Delete "$INSTDIR\uninst.exe" Delete "$INSTDIR\Hello.exe" Delete "$INSTDIR\COPYING.txt" Delete "$SMPROGRAMS\Hello\Uninstall.lnk" Delete "$SMPROGRAMS\Hello\Website.lnk" Delete "$DESKTOP\Hello.lnk" Delete "$SMPROGRAMS\Hello\Hello.lnk" RMDir "$SMPROGRAMS\Hello" RMDir "$INSTDIR" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" SetAutoClose true SectionEnd #-- 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题。--# Function FuncUninstall ;卸载当前的版本 ReadRegStr $R1 HKLM "${PRODUCT_UNINST_KEY}" "UninstallString" ClearErrors ExecWait '$R1 _?=$INSTDIR' IfErrors no_remove_uninstaller IfFileExists "$INSTDIR/makensis.exe" no_remove_uninstaller Delete $R1 RMDir $INSTDIR no_remove_uninstaller: FunctionEnd Function FuncReinstall ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" ${If} $R0 == "" Abort ${EndIf} ${VersionCompare} ${VER_MAJOR}.${VER_MINOR}.${VER_REVISION}.${VER_BUILD} $R0 $R0 ${If} $R0 == 0 MessageBox MB_ICONINFORMATION|MB_YESNO "$(^Name) 已经安装。是否卸载后重新安装?" IDYES StartReinstall1 Abort StartReinstall1: Call FuncUninstall ${ElseIf} $R0 == 1 MessageBox MB_ICONINFORMATION|MB_YESNO "你已经安装了一个老版本。您应该在安装之前先卸载当前的版本。是否继续?" IDYES StartReinstall2 StartReinstall2: Call FuncUninstall ${ElseIf} $R0 == 2 MessageBox MB_ICONINFORMATION|MB_YESNO "你已经安装了一个较新的版本。安装旧的版本,最好先卸载当前的版本。是否继续?" IDYES StartReinstall3 StartReinstall3: Call FuncUninstall ${Else} Abort ${EndIf} FunctionEnd Function .onInit ;创建互斥防止重复运行 System::Call 'kernel32::CreateMutexA(i 0, i 0, t "hello_chs_installer") i .r1 ?e' Pop $R0 StrCmp $R0 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "另一个 NSIS 安装向导正在运行." Abort ;检测程序是否已经安装 ReadRegStr $R0 HKLM "${PRODUCT_DIR_REGKEY}" "" ${If} $R0 == "" MessageBox MB_ICONINFORMATION|MB_OK "立即开始全新安装 $(^Name)!" ${else} Call FuncReinstall ${EndIf} FunctionEnd Function un.onInit MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "您确实要完全移除 $(^Name) ,及其所有的组件?" IDYES +2 Abort FunctionEnd Function un.onUninstSuccess HideWindow MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从您的计算机移除。" FunctionEnd