NSIS常用函数

发布于 2023-02-27 | 作者: A.A | 来源: CSDN博客 | 转载于: CSDN博客

#NSIS常用函数

##多语言设置

#定义多语言
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "SimpChinese"
Caption "$(LNG_NAME)"
Name "$(LNG_NAME)"
!define APPNAME "shenjianji"
LangString LNG_NAME ${LANG_ENGLISH} "appname"
LangString LNG_TITLE ${LANG_ENGLISH} "app installer"
LangString LNG_NAME ${LANG_SIMPCHINESE} "软件名称"
LangString LNG_TITLE ${LANG_SIMPCHINESE} "软件安装器"
LangString LNG_NAME ${LANG_JAPANESE} "応用"
LangString LNG_TITLE ${LANG_JAPANESE} "アプリケーションインストーラ"
Function .onInit
	#选择语言(加入到combobox)
	Push ""
	Push ${LANG_SIMPCHINESE}
	Push "Simplified Chinese"
	Push ${LANG_JAPANESE}
	Push "Japanese"
	Push ${LANG_ENGLISH}
	Push "English"
	Push A
	#显示语言选择框
	LangDLL::LangDialog "Installer Language" "Please select the language of the installer"
	Pop $LANGUAGE
	StrCmp $LANGUAGE "cancel" 0 +2
	Abort
	${If} ${LANG_SIMPCHINESE} = $Language
	MessageBox MB_OK "简体中文:$(LNG_TITLE)"
	${ElseIf} ${LANG_ENGLISH} = $Language
	MessageBox MB_OK "English: $(LNG_TITLE)"
	${ElseIf} ${LANG_JAPANESE} = $Language
	MessageBox MB_OK "日本語: $(LNG_TITLE)"
	${EndIf}
FunctionEnd

##判断系统位数

${If} ${RunningX64}
	MessageBox MB_OK "x64"
${Else}
	MessageBox MB_OK "x86"
${EndIf}

##安装路径合法性及磁盘剩余空间判断

Var Path_OK
Function pathcheck
	#MessageBox MB_OK "onWelcomepageNext:$INSTDIR"
	Push 0
	Pop $Path_OK
	#检查安装路径
	#INSTDIR不能为空路径
	StrCmp $INSTDIR "" badpath
	#INSTDIR不能为磁盘根目录
	StrCpy $R0 $INSTDIR "" -2
	StrCmp $R0 ":\" badpath
	StrCpy $R0 $INSTDIR "" -1
	StrCmp $R0 ":" badpath
	#
	SetOutPath "$INSTDIR"
	IfFileExists "$INSTDIR\*.*" 0 +2
	Goto spacecheck
	Goto badpath
spacecheck:
	#检查磁盘空间
	StrCpy $R3 "$INSTDIR" 3
	${DriveSpace} $R3 "/D=F /S=G" $R2
	Push $R2
	Pop $Disk_Space
	${If} $Disk_Space == 0
	MessageBox MB_OK "磁盘空间不足"
	Goto ownExit
	${EndIf}
	#检查通过
	Push 1
	Pop $Path_OK
	Goto ownExit
badpath:
	MessageBox MB_OK "非法路径"
ownExit:
FunctionEnd

##路径选择框及逻辑

Page custom DirectorySelectPage
Var Txt_Browser
Function OnChange_DirRequest
	#textarea编辑事件
 Pop $0
 System::Call "user32::GetWindowText(i $Txt_Browser,t .r0,i ${NSIS_MAX_STRLEN}) i .n"
 StrCpy $INSTDIR $0
	MessageBox MB_OK "OnChange_DirRequest $INSTDIR"
FunctionEnd
Function OnClick_DirectorySelect
	#点击浏览按钮事件
	Pop $0
	Push $INSTDIR 
	Call GetParent
	Pop $R0 
	Push $INSTDIR 
	Push "\"
	Push "${APPNAME}"
	Pop $R1
	nsDialogs::SelectFolderDialog "$(LNG_SELECTFOLDER)" ""
	Pop $0
	${If} $0 == "error"
	Return
	${EndIf}
	${If} $0 != ""
	StrCpy $INSTDIR "$0\$R1"
	system::Call `user32::SetWindowText(i $Txt_Browser, t "$INSTDIR")`
	${EndIf}
FunctionEnd
Function GetParent
	#得到选中目录用于拼接安装程序名称
	# Usage:
	# Push "C:\Program Files\Directory\Whatever"
	# Call GetParent
	# Pop $R0 # $R0 equal "C:\Program Files\Directory"
	Exch $R0 # input string
	Push $R1
	Push $R2
	Push $R3
	StrCpy $R1 0
	StrLen $R2 $R0
loop:
	IntOp $R1 $R1 + 1
	IntCmp $R1 $R2 get 0 get
	StrCpy $R3 $R0 1 -$R1
	StrCmp $R3 "\" get
	Goto loop
get:
	StrCpy $R0 $R0 -$R1
	Pop $R3
	Pop $R2
	Pop $R1
	Exch $R0 # output string
FunctionEnd
Function DirectorySelectPage
 #更改目录控件创建
 ${NSD_CreateDirRequest} 50 100 300 26 "$INSTDIR"
	Pop $Txt_Browser
	${NSD_OnChange} $Txt_Browser OnChange_DirRequest
	#浏览按钮
	${NSD_CreateBrowseButton} 350 100 80 26 "浏览"
	Pop $2
	StrCpy $1 $2
	GetFunctionAddress $3 OnClick_DirectorySelect
	SkinBtn::onClick $1 $3
FunctionEnd

##页面逻辑函数(上一步、下一步、最小化、关闭)

Function RelGotoPage
	#页面跳转的命令
	IntCmp $R9 0 0 Move Move
	StrCmp $R9 "X" 0 Move
	StrCpy $R9 "120"
Move:
	SendMessage $HWNDPARENT "0x408" "$R9" ""
FunctionEnd
Function onClickPre
	#上一步按钮事件
	StrCpy $R9 -1 #Goto the last page
	Call RelGotoPage
	Abort
FunctionEnd
Function onClickNext
	#下一步按钮事件
	StrCpy $R9 1 #Goto the next page
	Call RelGotoPage
	Abort
FunctionEnd
Function onMin
	#最小化事件
	ShowWindow $HWNDPARENT ${SW_MINIMIZE}
FunctionEnd
Function onClickCloseWithoutConfirm
	#无确认关闭
	System::Call 'kernel32::GetCurrentProcess()i.r0'
	System::Call Kernel32::TerminateProcess(ir0,i0)
FunctionEnd
Function onClickClose
	#确认关闭
	MessageBox MB_YESNO "$(LNG_WARNNING_CONFIRMEXIT)" /SD IDYES IDNO noexit
	System::Call 'kernel32::GetCurrentProcess()i.r0'
	System::Call Kernel32::TerminateProcess(ir0,i0)
noexit:
FunctionEnd

##解压文件并更新进度条
直接使用File释放文件因为没有回调所以没有实时进度,只能做假进度。而使用Nsis7z::ExtractWithCallback时,每释放一个文件都能触发一次回调,从而实现进度条更新

Page custom ProgressPage
Var PB_ProgressBar
Var CurPos7Z
Var TotPos7Z
Var Progress_Current
Var Progress_Total
Function ExtractCallback
	#解压回调
	# MessageBox MB_OK "UpdateProgress"
	#计算进度条百分比
	Pop $CurPos7Z
 Pop $TotPos7Z
	Push $CurPos7Z
	Pop $1
	Push $TotPos7Z
	Pop $2
	Push $1
	Pop $Progress_Current
	Push $2
	Pop $Progress_Total
	System::Int64Op $1 * 100
	Pop $3
	System::Int64Op $3 / $2
	Pop $0
	#MessageBox MB_OK "$1 $2 $0"
	#更新进度条
	SendMessage $PB_ProgressBar ${PBM_SETPOS} $0 0
FunctionEnd
Function NSD_TimerFun
 GetFunctionAddress $0 NSD_TimerFun
 nsDialogs::KillTimer $0
 !if 1 #是否在后台运行,1有效
	GetFunctionAddress $0 installing
 BgWorker::CallAndWait
	MessageBox MB_OK "finish"
 !else
	Call installing
	MessageBox MB_OK "finish"
 !endif
FunctionEnd
Function installing
	SetOutPath $INSTDIR
	SetOverwrite on
	#MessageBox MB_OK "installing: $INSTDIR"
	#Sleep 3000
	#释放压缩文件
	File /r "test.7z"
	GetFunctionAddress $R9 ExtractCallback
	Nsis7z::ExtractWithCallback "$INSTDIR\test.7z" $R9
	Delete "$INSTDIR\test.7z"
FunctionEnd
Function ProgressPage
	#安装进度条
 ${NSD_CreateProgressBar} 10 200 300 10 ""
 Pop $PB_ProgressBar
	#进度条初始化
	Push 0
	Pop $Progress_Current
	Push 100
	Pop $Progress_Total
	Push 0
	Pop $CurPos7Z
	Push 100
	Pop $TotPos7Z
	#开启定时器,更新进度条
 GetFunctionAddress $0 NSD_TimerFun
 nsDialogs::CreateTimer $0 1
FunctionEnd

	

##文件读写

Var Select_language
Function file
	#写入文件
	FileOpen $0 $INSTDIR\language.txt w
	IfErrors done1
	FileWrite $0 "Engilsh"
	FileClose $0
done1:
	#读取文件
	FileOpen $0 $INSTDIR\language.txt r
	IfErrors done2
	FileRead $0 $Select_language
	FileClose $0
done2:
	MessageBox MB_OK "$Select_language"
FunctionEnd

##新增及删除注册表、文件夹和快捷方式

	#新增注册表项
	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "appName" "${APPNAME}"
	WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "number" 1
	#删除注册表项
	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
	#新建文件夹
	SetOutPath "$INSTDIR\bin"
	createDirectory "$INSTDIR\newfolder"
	#删除文件夹(/r为递归删除,/REBOOTOK重启后删除)
	rmDir /r $INSTDIR\bin
	rmDir /REBOOTOK $INSTDIR
	#新建快捷方式
	CreateShortcut "$Desktop\${APPNAME}.lnk" "$INSTDIR\${APPNAME}.exe"
	#删除快捷方式
	delete "$Desktop\${APPNAME}.lnk"

##自定义check box

Page custom CheckboxPage
Var Bool_isCheck
Var check_box
Function OnClick_CheckBox
 ${IF} $Bool_isCheck == 1
 IntOp $Bool_Run $Bool_isCheck - 1
 StrCpy $1 $check_box
 SkinBtn::Set /IMGID=$PLUGINSDIR\checkbox1.bmp $1
	MessageBox MB_OK "$Bool_isCheck"
 ${ELSE}
 IntOp $Bool_Run $Bool_isCheck + 1
 StrCpy $1 $check_box
 SkinBtn::Set /IMGID=$PLUGINSDIR\checkbox2.bmp $1
	MessageBox MB_OK "$Bool_isCheck"
 ${EndIf}
FunctionEnd
Function CheckboxPage
	#checkbox
 ${NSD_CreateButton} 100 100 15 15 "checkbox"
 Pop $check_box
 StrCpy $1 $check_box
 SkinBtn::Set /IMGID=$PLUGINSDIR\checkbox2.bmp $1
 GetFunctionAddress $3 OnClick_CheckBox
 SkinBtn::onClick $1 $3
 StrCpy $Bool_isCheck 1
FunctionEnd