How to Use the NSIS Unzip Plugin properly? - nsis

Im new to NSIS programming, so i found the NSISUNZ plugin to extract files.
This is my Code:
OutFile "TEst.exe"
Section
!addplugindir nsisunz
initPluginsDir
nsisunz::Unzip "C:\Users\user\Downloads\TestVerzeichnis.zip" "C:\Users\user\Downloads"
SectionEnd
I do not get an Error or something but the file does not get extracted.
For the installation of the plugin I just extracted the .dll file into the plugins folder.
What am I doing wrong here?
Thanks for answering

If the output is just a single letter then you most likely using the Unicode version of the plug-in in a Ansi installer.
Ideally you should create a Unicode installer with NSIS v3:
Move the plug-in to the Unicode plug-in subfolder inside the root plugins folder.
Add Unicode True to your .NSI.
If you are still using NSIS v2 then you need to find a different version of the plug-in, most likely the other file on the wiki.
Unicode True
!addplugindir /x86-unicode "$%userprofile%\Downloads\Nsisunz\Plugin unicode"
!include LogicLib.nsh
Function SplitWrite
Pop $2
StrCpy $3 ""
StrCpy $4 0
loop:
StrCpy $5 $2 1 $4
${If} $5 == "|"
${OrIf} $5 == ""
IntOp $6 $4 - 2
StrCpy $6 $2 2 $6
FileWriteByte $1 "0x$6"
${EndIf}
IntOp $4 $4 + 1
StrCmp $5 "" 0 loop
FunctionEnd
Section
InitPluginsDir
; Create a example .zip file
FileOpen $1 "$PluginsDir\test.zip" w
Push 50|4B|03|04|0A|00|00|00|00|00|AC|BA|93|50
Call SplitWrite
Push F8|06|53|6B|08|00|00|00|08|00|00|00|08|00|00|00|54|65|73|74|2E|74|78|74|48|65|6C|6C|6F|20|0D|0A|50|4B|01|02|3F|00|0A|00|00|00|00|00|AC|BA|93|50
Call SplitWrite
Push F8|06|53|6B|08|00|00|00|08|00|00|00|08|00|24|00|00|00|00|00|00|00|20|20|00|00|00|00|00|00|54|65|73|74|2E|74|78|74|0A|00|20|00|00|00|00|00|01|00|18|00
Call SplitWrite
Push D6|75|96|79|90|16|D6|01|96|4F|96|79|90|16|D6|01|96|4F|96|79|90|16|D6|01|50|4B|05|06|00|00|00|00|01|00|01|00|5A|00|00|00|2E|00|00|00|00|00
Call SplitWrite
FileClose $1
CreateDirectory "$PluginsDir\TestDir"
nsisunz::Unzip "$PluginsDir\test.zip" "$PluginsDir\TestDir"
Pop $0
DetailPrint $0 ; "success"
${If} $0 == "success"
FileOpen $1 "$PluginsDir\TestDir\Test.txt" r
FileRead $1 $2
FileClose $1
DetailPrint $2 ; "Hello"
${EndIf}
SectionEnd

Related

How to save log during uninstallation using NSIS

I'm trying to log the uninstallation process, especially the files and folders deleted by rmdir for debug. However, LogSet On and DumpLog function seems not working. Does anyone knows if there is a way to do it?
Edit:
I'm using DumpLog like:
Section "Uninstall"
;ADD YOUR OWN FILES HERE...
LogSet On
DetailPrint "this is an uninstall test"
Delete "$INSTDIR\Uninstall.exe"
DeleteRegKey /ifempty HKCU "Software\Test"
DetailPrint "dumplog section"
StrCpy $0 "$INSTDIR\install.log"
Push $0
Call un.DumpLog
SectionEnd
Function un.DumpLog
Exch $5
Push $0
Push $1
Push $2
Push $3
Push $4
Push $6
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $0 $0 1016
StrCmp $0 0 exit
FileOpen $5 $5 a
StrCmp $5 "" exit
SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
System::Alloc ${NSIS_MAX_STRLEN}
Pop $3
StrCpy $2 0
System::Call "*(i, i, i, i, i, i, i, i, i) i \
(0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
loop: StrCmp $2 $6 done
System::Call "User32::SendMessageA(i, i, i, i) i \
($0, ${LVM_GETITEMTEXT}, $2, r1)"
System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
FileWrite $5 "$4$\r$\n"
IntOp $2 $2 + 1
Goto loop
done:
FileClose $5
System::Free $1
System::Free $3
exit:
Pop $6
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
Exch $5
FunctionEnd
More Edit:
Things are getting more complex.
I put the structure like:
-InstDir
-UnInstDir
-Uninstaller.exe
When I run uninstaller or use execwait $InstDir\UnInstDir\Uninstall.exe, LogSet On works and a new install.log was created in UnInstDir.
However, when I use execwait $InstDir\UnInstDir\Uninstall.exe _?=$InstDir, LogSet On doesn't work.
Anyone has any clue on it?
LogSet requires that you use the logging build of NSIS. DumpLog only writes the same info as you see on the InstFiles page.
Another alternative is to track the files as you install them.
The final option is to use !system to execute a script (batch file etc.) that generates two .nsh files (one for the installer, one for the uninstaller) with File and Delete instructions based on the output of dir /s.

NSIS install path validation

I want to validate the installation path selected by the user. I can't figure out how to check that so it will look like this:
You can't select a path with spaces (except Program Files)
When you click "Install" then it will prompt the error saying that you have to change the installation directory
For now I have this:
Function StrStr
Exch $1 ; st=haystack,old$1, $1=needle
Exch ; st=old$1,haystack
Exch $2 ; st=old$1,old$2, $2=haystack
Push $3
Push $4
Push $5
StrLen $3 $1
StrCpy $4 0
; $1=needle
; $2=haystack
; $3=len(needle)
; $4=cnt
; $5=tmp
loop:
StrCpy $5 $2 $3 $4
StrCmp $5 $1 done
StrCmp $5 "" done
IntOp $4 $4 + 1
Goto loop
done:
StrCpy $1 $2 "" $4
Pop $5
Pop $4
Pop $3
Pop $2
Exch $1
FunctionEnd
Function .onVerifyInstDir
Push "$INSTDIR"
Push " "
Call StrStr
Pop $0
StrCpy $0 $0 1
StrCmp $0 " " 0 +2
Abort
FunctionEnd
It refuses to install while there is any space in the path. I need to modify this so Program Files will be the only exception for that rule. Also, printing error message would be helpful
This restriction makes no sense to me. Some legacy applications can't handle spaces in the path but that of course also includes the Program Files folder (although the progra~1 hack can be used as a workaround if short name generation is active).
NSIS does not have a specific way to display a error/warning message directly on the page but you can change existing text in the UI and/or display a balloon.
!include WinMessages.nsh
!define /IfNDef EM_SHOWBALLOONTIP 0x1503
!define /IfNDef EM_HIDEBALLOONTIP 0x1504
!define DIRPAGE_CHANGETEXT ; Remove this line to disable the text change
!define DIRPAGE_BALLOON ; Remove this line to disable the balloon
Function .onVerifyInstDir
FindWindow $9 "#32770" "" $HWNDPARENT
!ifdef DIRPAGE_CHANGETEXT
GetDlgItem $3 $9 1006 ; IDC_INTROTEXT
LockWindow on
!endif
StrCpy $1 0
loop:
StrCpy $2 $InstDir 1 $1
StrCmp $2 '' valid ; End of string
StrCmp $2 ' ' found_space
IntOp $1 $1 + 1
Goto loop
valid:
!ifdef DIRPAGE_CHANGETEXT
SetCtlColors $3 SYSCLR:18 SYSCLR:15
SendMessage $3 ${WM_SETTEXT} "" "STR:$(^DirText)"
LockWindow off
!endif
!ifdef DIRPAGE_BALLOON
GetDlgItem $3 $9 1019
SendMessage $3 ${EM_HIDEBALLOONTIP} "" "" ; Not required?
!endif
Return
found_space:
StrLen $1 "$ProgramFiles\"
StrCpy $2 "$InstDir\" $1
StrCmp $2 "$ProgramFiles\" valid
!ifdef DIRPAGE_CHANGETEXT
SetCtlColors $3 ff0000 transparent
SendMessage $3 ${WM_SETTEXT} "" "STR:Paths with spaces are not allowed, except for $ProgramFiles for some reason!"
LockWindow off
!endif
!ifdef DIRPAGE_BALLOON
GetDlgItem $3 $9 1019
System::Call '*(&l${NSIS_PTR_SIZE},w "Bad path!", w "Spaced not allowed in path!",p 3)p.r2'
SendMessage $3 ${EM_SHOWBALLOONTIP} "" $2 ; This will only work on XP and later (and you must use "XPStyle on")
System::Free $2
!endif
Abort
FunctionEnd
XPStyle on
Page Directory
The Next button is disabled when Abort is called inside .onVerifyInstDir. If you want to display a MessageBox when the user clicks next then you can't call Abort in .onVerifyInstDir, you will have to use the page leave function callback (where you have to verify the path again and maybe call MessageBox+Abort).

NSIS FileRead dont work with Variables

I have minor problem in my NSIS-Script,
im calling this Function:
Function ReadAllDesc
Var /global j
${foreach} $j 0 $secCount + 1
SectionGetText $h $4
${StrContains} $5 "++" $4
${ifnot} $5 == ""
StrCpy $5 $4 "" 2
${else}
StrCpy $5 $4
${endif}
!insertmacro DESC_READ $4 $lang $5
${next}
FunctionEnd
in descriptionInit Function
The Macro that i insert is the following:
!macro DESC_READ addonText lang addonVar
FileOpen $6 "$TEMP\addonInstallerPreFolder\5.1\${addonText}_${lang}.txt" r
${if} ${addonText} == proFile
FileRead $6 $proFileDesc
${else}
${if} ${addonText} == "ExtensionsFrame"
FileRead $6 $extensions
${else}
FileRead $6 $${addonVar}
${endIf}
${endIf}
FileClose $6
!macroend
at compile time i get an error in the macroline FileRead $6 $${addonVar} that the syntax is false. But when i change the macro call to a fix example like:
!insertmacro DESC_READ "ExtensionsFrame" $lang "extensions"
it works correctly. I need this because of i´m reading an Variable count on descriptions and don´t want to write fix code in this case.

How do I redirect the output of commands to file in silent mode in NSIS?

In GUI mode, commands like CopyFiles , Delete , etc. output their data to GUI (may be using DetailPrint) and their is a function available on NSIS forums to copy that data (at the end of section) to a file.
Queries:
If the installer is being run in silent mode, how do I get the same data (which was being directed to GUI in non-silent mode) to the file?
In GUI mode, since I am directing custom logs through DetailPrint to the log file with the help of function so that all the logs are received in order. Here the issue is that line breaks are removed from the custom logs. May be DetailPrint removes it. How shall I avoid this?
Example:
DetailPrint "This is a custom log1"
DetailPrint "$\r$\nThis is a custom log2"
/*
Dumped these logs using function mentioned above
Output in logs(with no line breaks):
This is a custom log1
This is a custom log2
Required output:
This is a custom log1
This is a custom log2
*/
Your Second query is Solved.
!include "MUI2.nsh"
section
StrCpy $0 "$EXEDIR\install.log"
Push $0
DetailPrint "This is a custom log1"
DetailPrint "This is a custom log2"
Call DumpLog
sectionend
;!define LVM_GETITEMCOUNT 0x1004
!define LVM_GETITEMTEXT 0x102D
Function DumpLog
Exch $5
Push $0
Push $1
Push $2
Push $3
Push $4
Push $6
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $0 $0 1016
StrCmp $0 0 exit
FileOpen $5 $5 "w"
StrCmp $5 "" exit
SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
System::Alloc ${NSIS_MAX_STRLEN}
Pop $3
StrCpy $2 0
System::Call "*(i, i, i, i, i, i, i, i, i) i \
(0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
loop: StrCmp $2 $6 done
System::Call "User32::SendMessageA(i, i, i, i) i \
($0, ${LVM_GETITEMTEXT}, $2, r1)"
System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
FileWrite $5 "$4$\r$\n"
FileWrite $5 "$\r$\n"
IntOp $2 $2 + 1
Goto loop
done:
FileClose $5
System::Free $1
System::Free $3
exit:
Pop $6
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
Exch $5
FunctionEnd
Your sample code is works for me. Its gives me output as your requirement.
Dont put "$\r$\n" in Detailprint. Add FileWrite $5 "$\r$\n" in DumpLog function as i did. By this you will not have to put $\r$\n in each detail print.

Product version string from an exe - nsis

I want to read the product version (optional string) from a given executable (actually from the installer I'm trying to create if it makes any difference), if it is possible at the run-time. This string will be further used to download files from a link.
Thank you very much !
NSIS does not have native support for reading anything other than VS_FIXEDFILEINFO->dwFileVersion so you have to call the Windows API directly:
; Add some version information so we have something to test
VIProductVersion 1.2.3.4
VIAddVersionKey "ProductVersion" "One Two Three Four"
VIAddVersionKey "FileVersion" "Whatever"
VIAddVersionKey "FileDescription" "Whatever"
VIAddVersionKey "LegalCopyright" "(C) Whatever"
!include LogicLib.nsh
Function GetFileVerFirstLangProductVersion
System::Store S
pop $3
push "" ;failed ret
System::Call 'version::GetFileVersionInfoSize(t"$3",i.r2)i.r0'
${If} $0 <> 0
System::Alloc $0
System::Call 'version::GetFileVersionInfo(t"$3",ir2,ir0,isr1)i.r0 ? e'
pop $2
${If} $0 <> 0
${AndIf} $2 = 0 ;a user comment on MSDN said you should check GLE to avoid crash
System::Call 'version::VerQueryValue(i r1,t "\VarFileInfo\Translation",*i0r2,*i0)i.r0'
${If} $0 <> 0
System::Call '*$2(&i2.r2,&i2.r3)'
IntFmt $2 %04x $2
IntFmt $3 %04x $3
System::Call 'version::VerQueryValue(i r1,t "\StringFileInfo\$2$3\ProductVersion",*i0r2,*i0r3)i.r0'
${If} $0 <> 0
pop $0
System::Call *$2(&t$3.s)
${EndIf}
${EndIf}
${EndIf}
System::Free $1
${EndIf}
System::Store L
FunctionEnd
Section
Push "$ExePath" ; Read our own version information in this example
Call GetFileVerFirstLangProductVersion
Pop $0
DetailPrint "ProductVersion=$0"
SectionEnd

Resources