相关文章推荐
文武双全的荒野  ·  node js base64 to ...·  8 月前    · 
阳刚的土豆  ·  WaterMarker - pdf ...·  8 月前    · 
朝气蓬勃的煎鸡蛋  ·  Python: keep open ...·  1 年前    · 
制作 NSIS 安装包时,如何打包 .NET Framework 4.0?

制作 NSIS 安装包时,如何打包 .NET Framework 4.0?

进行 Windows 软件开发时,一般都会依赖某个版本的 .Net Framework。因此我们在制作安装包时,需要将所依赖版本的 .Net Framework 进行打包。

首先创建语言文件 lang_ch.nsi,内容如下:

Unicode true
!define sec_prod "置顶王"
!define sec_brand "图加软件(TujiaStudio)"
!define sec_run "运行 "
!define sec_update "更新完成!$\r$\n$\r$\n马上运行 ${sec_prod} 吗?"
Function InitStrings
  Var /GLOBAL parent_dir
  Var /GLOBAL publisher
  Var /GLOBAL sec_shortcut
  Var /GLOBAL sec_desktop
  Var /GLOBAL sec_startmenu
  Var /GLOBAL sec_prod_descrip
  Var /GLOBAL sec_shortcut_descrip
  Var /GLOBAL sec_desktop_descrip
  Var /GLOBAL sec_startmenu_descrip
  Var /GLOBAL instalreadyrun
  Var /GLOBAL prodalreadyrun4inst
  Var /GLOBAL msgDotNetNotInstalled
  Var /GLOBAL msgDotNetDownloadBegin
  Var /GLOBAL msgDotNetDownloadCompleted
  Var /GLOBAL msgDotNetDownloadCanceled
  Var /GLOBAL msgDotNetDownloadFailed
  Var /GLOBAL msgPausingInstall
  Var /GLOBAL msgFinishInstallNet
  Var /GLOBAL msgRemoveNetInstaller
  Var /GLOBAL msgCancelInstallNet
  Var /GLOBAL msgProceedInstall
  StrCpy $publisher "图加软件"
  StrCpy $sec_shortcut "创建快捷方式"
  StrCpy $sec_desktop "桌面"
  StrCpy $sec_startmenu "启动菜单"
  StrCpy $sec_prod_descrip "${sec_prod}主程序组件"
  StrCpy $sec_shortcut_descrip "创建桌面或启动菜单快捷方式"
  StrCpy $sec_desktop_descrip "创建桌面快捷方式"
  StrCpy $sec_startmenu_descrip "创建启动菜单快捷方式"
  StrCpy $instalreadyrun "安装程序已经运行!"
  StrCpy $prodalreadyrun4inst "${sec_prod}正在运行,安装前请先退出程序!"
  StrCpy $msgDotNetNotInstalled "未安装.NET Framework 4.0.$\n是否从 microsoft.com 下载 .NET Framework 4.0 并安装?"
  StrCpy $msgDotNetDownloadBegin "开始下载 .NET Framework 4.0."
  StrCpy $msgDotNetDownloadCompleted "完成下载。"
  StrCpy $msgDotNetDownloadCanceled "下载取消。 是否继续安装?"
  StrCpy $msgDotNetDownloadFailed "下载取消:$\n$0$\n$\n是否继续安装?"
  StrCpy $msgPausingInstall "暂停安装${sec_prod},安装.NET Framework 4.0。"
  StrCpy $msgFinishInstallNet ".NET Framework 4.0 成功安装。移除 .NET Framework 4.0 安装包。"
  StrCpy $msgRemoveNetInstaller ".NET Framework 4.0 安装包成功移除。"
  StrCpy $msgCancelInstallNet ".NET Framework 4.0 安装被用户中止。"
  StrCpy $msgProceedInstall "继续安装${sec_prod}。"
FunctionEnd
Function un.InitStrings
  Var /GLOBAL uninstalreadyrun
  Var /GLOBAL prodalreadyrun4uninst
  StrCpy $uninstalreadyrun "卸载程序已经运行!"
  StrCpy $prodalreadyrun4uninst "${sec_prod}正在运行,卸载前请先退出程序!"
FunctionEnd

然后创建安装包源码文件 TMK_installer.nsi,内容如下(注意其中 IsDotNetInstalled 这个函数的定义及调用):

Unicode true
; Defines.
!define prod_name "TMK"
!define version "2.0.0"
!define size 432
!define out_file "${prod_name}_Setup_V${version}.exe"
!define exe_file "TopMostKing.exe"
!define mutex_id "${prod_name}_Inst_Mutex"
!define mutex_id_un "${prod_name}_Uninst_Mutex"
!define mutex_id_prod "TopMostKing"
!define lang_file "lang_ch.nsi"
!define root_key HKCU
!define request_lvl admin
!define DOT_MAJOR 4
!define DOT_MINOR 0
!define DOTNET40Full_URL  "https://www.microsoft.com/downloads/info.aspx?na=41&srcfamilyid=0a391abd-25c1-4fc0-919f-b21f31ab88b7&srcdisplaylang=en&u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f9%2f5%2fA%2f95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE%2fdotNetFx40_Full_x86_x64.exe"
;Includes
!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!include ${lang_file}
; Callbacks.
Function .onInit
  Call InitStrings
  ; Check TMK running.
  System::Call 'kernel32::CreateMutex(p 0, i 0, t "${mutex_id_prod}") p .r1 ?e'
  Pop $R0
  StrCmp $R0 0 +3
    MessageBox MB_OK|MB_ICONEXCLAMATION "$prodalreadyrun4inst"
    Abort
  ; Check single instance of installer.
  System::Call 'kernel32::CreateMutex(p 0, i 0, t "${mutex_id}") p .r1 ?e'
  Pop $R0
  StrCmp $R0 0 +3
    MessageBox MB_OK|MB_ICONEXCLAMATION "$instalreadyrun"
    Abort
FunctionEnd
Function un.onInit
  Call un.InitStrings
  ; Check TMK running.
  System::Call 'kernel32::CreateMutex(p 0, i 0, t "${mutex_id_prod}") p .r1 ?e'
  Pop $R0
  StrCmp $R0 0 +3
    MessageBox MB_OK|MB_ICONEXCLAMATION "$prodalreadyrun4uninst"
    Abort
  ; Check single instance of installer.
  System::Call 'kernel32::CreateMutex(p 0, i 0, t "${mutex_id_un}") p .r1 ?e'
  Pop $R0
  StrCmp $R0 0 +3
    MessageBox MB_OK|MB_ICONEXCLAMATION "$uninstalreadyrun"
    Abort
FunctionEnd
; Custom calls.
Function IsDotNetInstalled
	Push $0
	Push $1
	Push $2
	Push $3
	Push $4
	Push $5
	Push $6
	Push $7
  StrCpy $0 "0"
  StrCpy $1 "SOFTWARE\Microsoft\.NETFramework" ; Registry entry to look in.
  StrCpy $2 0
  StartEnum:
  ; Enumerate the versions installed.
  EnumRegKey $3 HKLM "$1\policy" $2
  ; If we don't find any versions installed, it's not here.
  StrCmp $3 "" NoDotNET notEmpty
  ; We found something.
  notEmpty:
      ; Find out if the RegKey starts with 'v'.  
      ; If it doesn't, goto the next key.
      StrCpy $4 $3 1 0
      StrCmp $4 "v" +1 goNext
      StrCpy $4 $3 1 1
      ; It starts with 'v'.  Now check to see how the installed major version
      ; relates to our required major version.
      ; If it's equal check the minor version, if it's greater, 
      ; we found a good RegKey.
      IntCmp $4 ${DOT_MAJOR} +1 goNext yesDotNetReg
      ; Check the minor version.  If it's equal or greater to our requested 
      ; version then we're good.
      StrCpy $4 $3 1 3
      IntCmp $4 ${DOT_MINOR} yesDotNetReg goNext goNext
  goNext:
      ; Go to the next RegKey.
      IntOp $2 $2 + 1
      goto StartEnum
  yesDotNetReg:
      ; Now that we've found a good RegKey, let's make sure it's actually
      ; installed by getting the install path and checking to see if the 
      ; mscorlib.dll exists.
      EnumRegValue $2 HKLM "$1\policy\$3" 0
      ; $2 should equal whatever comes after the major and minor versions 
      ; (ie, v1.1.4322)
      StrCmp $2 "" NoDotNET
      ReadRegStr $4 HKLM $1 "InstallRoot"
      ; Hopefully the install root isn't empty.
      StrCmp $4 "" NoDotNET
      ; Build the actuall directory path to mscorlib.dll.
      StrCpy $4 "$4$3.$2\mscorlib.dll"
      IfFileExists $4 NewDotNET NoDotNET
	NoDotNET:
		MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
		$msgDotNetNotInstalled \
		/SD IDYES IDYES DownloadDotNET IDNO NewDotNET
		goto GiveUpDotNET ;IDCANCEL
	DownloadDotNET:
		DetailPrint $msgDotNetDownloadBegin
		NSISDL::download ${DOTNET40Full_URL} "$TEMP\dotnetfx40_full.exe"
		DetailPrint $msgDotNetDownloadCompleted
		Pop $0
		${If} $0 == "cancel"
			MessageBox MB_YESNO|MB_ICONEXCLAMATION \
			$msgDotNetDownloadCanceled \
			IDYES NewDotNET IDNO GiveUpDotNET
		${ElseIf} $0 != "success"
			MessageBox MB_YESNO|MB_ICONEXCLAMATION \
			$msgDotNetDownloadFailed \
			IDYES NewDotNET IDNO GiveUpDotNET
		${EndIf}
		DetailPrint $msgPausingInstall
		ExecWait '$TEMP\dotnetfx40_full.exe /q /c:"install /q"'
		DetailPrint $msgFinishInstallNet
		Delete "$TEMP\dotnetfx40_full.exe"
		DetailPrint $msgRemoveNetInstaller
		goto NewDotNet
	GiveUpDotNET:
		Abort $msgCancelInstallNet
	NewDotNET:
		DetailPrint $msgProceedInstall
    Pop $7
    Pop $6
    Pop $5
    Pop $4
    Pop $3
    Pop $2
    Pop $1
    Pop $0
FunctionEnd
; The name of the installer
Name "${sec_prod} ${version}" 
; The branding text.
BrandingText ${sec_brand}
; The file to write
OutFile ${out_file}
; CRC check.
CRCCheck on
; The default installation directory
InstallDir "$PROGRAMFILES\TujiaStudio\${prod_name}"
; Registry key to check for directory (so if you install again, it will 
; overwrite the old one automatically)
InstallDirRegKey ${root_key} "Software\TujiaStudio\${prod_name}" "InstallDir"
; Request application privileges for Windows
RequestExecutionLevel ${request_lvl}
Function "MyRun"
  ShellExecAsUser::ShellExecAsUser "open" "$INSTDIR\${exe_file}"
FunctionEnd
;--------------------------------
;Pages
;--------------------------------
  !define MUI_HEADERIMAGE
  !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\tmk.bmp"
  !define MUI_HEADERIMAGE_RIGHT
  !insertmacro MUI_PAGE_LICENSE "License.txt"
  !insertmacro MUI_PAGE_COMPONENTS
  !insertmacro MUI_PAGE_DIRECTORY
  !insertmacro MUI_PAGE_INSTFILES
  !define MUI_FINISHPAGE_SHOWREADME "readme.txt"
  ;!define MUI_FINISHPAGE_RUN ${exe_file}
  !define MUI_FINISHPAGE_RUN
  !define MUI_FINISHPAGE_RUN_TEXT "${sec_run}${sec_prod}"
  !define MUI_FINISHPAGE_RUN_FUNCTION "MyRun"
  !define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\tmk.bmp"
  !insertmacro MUI_PAGE_FINISH
  !insertmacro MUI_UNPAGE_CONFIRM
  !insertmacro MUI_UNPAGE_INSTFILES
;--------------------------------
;Languages
;--------------------------------
  !insertmacro MUI_LANGUAGE "SimpChinese"
;--------------------------------
; Installer
Section ${sec_prod} sec_prod_idx
  SectionIn RO
  ; Set output path to the installation directory.
  SetOutPath $INSTDIR
  ; Check .NET 4.0
  Call IsDotNetInstalled
  ; Put file there
  SetOutPath $INSTDIR
  File ..\readme.txt
  IfSilent block1 block2
block1:
  ClearErrors
  SetOverwrite try
  File ..\${exe_file}
  File ..\TujiaStudio.dll
  IfErrors block1 done
block2:
  File ..\${exe_file}
  File ..\TujiaStudio.dll
  Goto done
done:
  SetOverwrite on
  ; Write info to registry
  WriteRegStr ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "DisplayIcon" "$INSTDIR\${exe_file}"
  WriteRegStr ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "DisplayName" "${sec_prod}"
  WriteRegStr ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "DisplayVersion" "${version}"
  WriteRegDWORD ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "EstimatedSize" ${size}
  WriteRegStr ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "Publisher" "$publisher"
  WriteRegStr ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "UninstallString" "$INSTDIR\uninstall.exe"
  WriteRegStr ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "URLInfoAbout" "http://www.tujiastudio.com"
  WriteRegDWORD ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "NoModify" 1
  WriteRegDWORD ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}" "NoRepair" 1
  WriteRegStr ${root_key} "Software\TujiaStudio\${prod_name}" "InstallDir" "$INSTDIR"
  WriteRegStr ${root_key} "Software\TujiaStudio\${prod_name}" "UninstallString" '"$INSTDIR\uninstall.exe"' 
  WriteUninstaller "$INSTDIR\uninstall.exe"
  IfSilent 0 false2
    MessageBox MB_YESNO "${sec_update}" IDYES true2 IDNO false2
    true2:
      Call MyRun
    false2:
SectionEnd
; Optional section (can be disabled by the user)
SectionGroup $sec_shortcut sec_shortcut_idx
Section $sec_desktop sec_desktop_idx
  SetShellVarContext current
  CreateShortCut "$DESKTOP\${prod_name}.lnk" "$INSTDIR\${exe_file}" \
  "" "$INSTDIR\${exe_file}" 0 SW_SHOWNORMAL "" ${sec_prod}
SectionEnd
Section $sec_startmenu sec_startmenu_idx
  CreateDirectory "$SMPROGRAMS\TujiaStudio"
  CreateShortcut "$SMPROGRAMS\TujiaStudio\${prod_name}.lnk" "$INSTDIR\${exe_file}" \
	"" "$INSTDIR\${exe_file}" 0 SW_SHOWNORMAL "" ${sec_prod}
SectionEnd
SectionGroupEnd
;--------------------------------
; Uninstaller
Section "Uninstall"
  ; Remove registry keys
  DeleteRegKey ${root_key} "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prod_name}"
  DeleteRegKey ${root_key} "Software\TujiaStudio\${prod_name}"
  DeleteRegKey /ifempty ${root_key} "Software\TujiaStudio"
  ; Remove files and uninstaller
  Delete $INSTDIR\uninstall.exe
  Delete $INSTDIR\${exe_file}
  Delete $INSTDIR\TujiaStudio.dll
  Delete $INSTDIR\readme.txt
  ; Remove shortcuts, if any
  Delete "$SMPROGRAMS\TujiaStudio\${prod_name}.lnk"
  Delete "$DESKTOP\${prod_name}.lnk"
  ; Remove directories used
  RMDir "$INSTDIR"
  ${GetParent} "$INSTDIR" $parent_dir
  RMDir "$parent_dir"
  RMDir "$SMPROGRAMS\TujiaStudio"
SectionEnd
;--------------------------------
;Descriptions
  ;Assign language strings to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${sec_prod_idx} $sec_prod_descrip