NSIS 自定義安裝介面準確獲取安裝進度完美解決方案
友情提醒:隨著7zip版本快速更新,nsis7z外掛已經不能全面相容新版,使用本例子請將7zip版本降至9.2x以下並下載最新版nsis7z.dll!
----------------------------------------------------------------------------------------------------------------
幾乎所有玩過nsis的人在製作安裝進度頁面時都會遇到一個比較棘手的問題,畫出進度條容易,但準確掌握檔案釋放進度,同時再去配合進度條的進度在nsis看來幾乎是個無法逾越的障礙,因為迄今為止NSIS尚無可直接使用的指令或者函式來獲取相關資料。網路上解決這個問題大部分做法都是大約分為若干段,20%...40%...80%...100%這樣大概做個進度的樣子,其實與釋放的檔案幾乎沒什麼聯絡,並且誤差非常大,我這個辦法可以盡最大可能的讓進度條進度與檔案釋放進度相匹配,腳本里面使用到兩個nsis外掛:
官方下載:
NSIS7Z plug-in
http://nsis.sourceforge.net/Nsis7z_plug-in
BgWorker plug-in
http://nsis.sourceforge.net/BgWorker_plug-in
將你要封裝的檔案按照部署的結構用7zip壓縮備用
原理:自定義介面設定計數器啟動後臺執行緒,然後獲取7z外掛的回撥函式資料。
封裝指令碼:
Outfile "customProgressBar.exe"
!include nsDialogs.nsh
!define /math PBM_SETRANGE32 ${WM_USER} + 6 #定義nsis未包含的進度條相關常量#編寫:水晶石
InstallDir "C:\test"
page custom custompage
Function custompage
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 100 100 100% 30u "開始安裝..."
Pop $9
SetCtlColors $9 0x000000 0xECE9D8
${NSD_CreateProgressBar} 0 50 100% 20 ""
Pop $8
${NSD_CreateTimer} OnDialogTimer
50
nsDialogs::Show
FunctionEnd
Function OnDialogTimer
SendMessage $8 ${PBM_SETRANGE32} 1 100
GetFunctionAddress $0 Extractfunc
BgWorker::CallAndWait #啟動一個低優先順序的後臺執行緒
FunctionEnd
Function Extractfunc
SetOutPath $INSTDIR
File "test.7z"
GetFunctionAddress $R9 Callback
Nsis7z::ExtractWithCallback "test.7z"
$R9
Delete "$OUTDIR\test.7z"
FunctionEnd
Function Callback
Pop $R8
Pop $R9
System::Int64Op $R8 * 100
Pop $R0
System::Int64Op $R0 / $R9
Pop $R3
SendMessage $8 ${PBM_SETPOS} $R3 0
${NSD_SetText} $9 "已經安裝$R3%"
${if} $R8 = $R9
${NSD_SetText} $9 "安裝完成"
#由於計算方式的四捨五入特性,進度條到安裝完成時會有位元組級別的誤差,此處消除。
SendMessage $8 ${PBM_SETPOS} 100 0
System::Call "user32::InvalidateRect(i$hwndparent,i0,i 1)"
${endif}
FunctionEnd
Section
DetailPrint "..."
SectionEnd