Product version string from an exe - nsis - 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

Related

Disable empty SectionGroup (NSIS)

In my script I have the conditional header inside a SectionGroup where sections are created at compile time.
If sections are not created SectionGroup exists and not checkable. How can I disable it if sections are not exist?
Set the name to empty to hide a section and/or group.
!include Sections.nsh
!include LogicLib.nsh
Page Components
Page InstFiles
Function HideEmptyGroup
Exch $3
Push $0
Push $1
Push $2
StrCpy $0 $3
StrCpy $2 ""
ClearErrors
loop:
SectionGetFlags $0 $1
IfErrors done
${If} $1 & ${SF_SECGRPEND}
${If} $2 = 1
SectionSetText $3 ""
${EndIf}
IntOp $2 $2 - 1
${ElseIf} $1 & ${SF_SECGRP}
IntOp $2 $2 + 1
${Else}
Goto done
${EndIf}
IntOp $0 $0 + 1
Goto loop
done:
Pop $2
Pop $1
Pop $0
Pop $3
FunctionEnd
SectionGroup /e "My Group" SID_MYGROUP
!if 0 ; Set to 1 to show section and group
Section "Thing"
SectionEnd
!endif
SectionGroupEnd
Function .onInit ; Note: This must come after the sections!
Push ${SID_MYGROUP}
Call HideEmptyGroup
FunctionEnd

How to Use the NSIS Unzip Plugin properly?

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

NSIS window disappear

I have tried a lot of possibility with this code but it doesn't work. I need to check a VPN connection. If I run the code firs time it works, but if I don't restart the program and push the button secondly then the program just disappear. Any idea how to fix it? thanks.
Function VpnLoginWindow
${Do}
!insertmacro VpnLoginWindow
StrCpy $4 0
${If} $3 == 1
${Do}
!insertmacro VpnLoginWindow
StrCpy $4 1
StrCmp $3 "0" 0 +2
${ExitDo}
${Loop}
${EndIf}
${If} $4 == 1
${ExitDo}
${EndIf}
${Loop}
FunctionEnd
!macro VpnLoginWindow
StrCpy $5 $1
System::Get "(i.r1) iss"
Pop $R0
System::Call "user32::EnumWindows(k R0, i) i.s"
${Do}
Pop $0
StrCmp $0 "1" 0 +2
${ExitDo}
System::Call "user32::GetWindowText(ir1,t.r2,i ${NSIS_MAX_STRLEN})"
StrCpy $2 $2 7
StrCpy $3 0
${If} $2 == "SSL VPN"
StrCpy $3 1
${ExitDo}
${EndIf}
Push 1 # callback's return value
System::Call "$R0"
${Loop}
System::Free $R0
StrCpy $1 $5
!macroend
Callbacks are tricky to get right and the plug-in is a little buggy. Also, you should not use relative jumps to jump over macros like ${ExitDo}!
!include LogicLib.nsh
!macro FindVpnLoginWindow
Push "" ; Result: Window not found
System::Store S
System::Get '(p.r1, p)ir0r0'
Pop $9
System::Call 'USER32::EnumWindows(k r9, p 0)'
${Do}
${IfThen} $0 != "callback1" ${|} ${ExitDo} ${|} ; <-- adjust the callback# if required
StrCpy $0 1 ; Set callback return value, continue search
System::Call "USER32::GetWindowText(pr1, t.r2, i ${NSIS_MAX_STRLEN})"
StrCpy $2 $2 7
${If} $2 == "SSL VPN"
Pop $2 ; Throw away old result
Push $1 ; Result: HWND
StrCpy $0 0 ; Set callback return value, stop enum with 0
${EndIf}
System::Call $9 ; Return from callback function
${Loop}
System::Free $9
System::Store L
!macroend
Function BackgroundFindWindow
!insertmacro FindVpnLoginWindow
Pop $0
DetailPrint "Result:$0"
FunctionEnd
...
GetFunctionAddress $0 BackgroundFindWindow
BgWorker::CallAndWait
GetFunctionAddress $0 BackgroundFindWindow
BgWorker::CallAndWait

NSIS GetVolumeInformation Results

Ok I found this code from another question asked and I'm a newbie for NSIS. Question Below
!define FILE_SUPPORTS_ENCRYPTION 0x00020000
!define FILE_READ_ONLY_VOLUME 0x00080000
!define FILE_VOLUME_QUOTAS 0x00000020
!macro MakeBitFlagYesNo flags bit outvar
IntOp ${outvar} ${flags} & ${bit}
${IfThen} ${outvar} <> 0 ${|} StrCpy ${outvar} "Yes" ${|}
${IfThen} ${outvar} == 0 ${|} StrCpy ${outvar} "No" ${|}
!macroend
StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
!insertmacro MakeBitFlagYesNo $1 ${FILE_SUPPORTS_ENCRYPTION} $2
!insertmacro MakeBitFlagYesNo $1 ${FILE_READ_ONLY_VOLUME} $3
!insertmacro MakeBitFlagYesNo $1 ${FILE_VOLUME_QUOTAS} $4
MessageBox mb_ok "flags=$1 $\nFILE_SUPPORTS_ENCRYPTION=$2$\nFILE_READ_ONLY_VOLUME=$3$\nFILE_VOLUME_QUOTAS=$4"
${EndIf}
Here is what I need to get:
Drive Volume Label:
File System: (Fat32, NTFS, exFat, ...)
Disk Capacity: (7.27TB, 5.59TB, ...)
Free Space: (4.62TB , 632GB, ...)
Allocation Unit Size: (4096b, 16kb, 32kb, ...)
and then I need to use that info in a if then statement
Just not sure how to turn the above code and results into code list below.
I have tried searching google about NSIS and GetVolumeInformation, and with the GetVolumeInformation I could not find out how to get and read results anywhere.
${If} $File_System <> "NTFS"
${EndIf}
${If} $Disk_Capacity < "1.86TB"
${EndIf}
${If} $Free_Space < "1.25TB"
${EndIf}
${If} $Allocation_Unit_Size <> "4096 bytes"
${EndIf}
MessageBox mb_ok "$Drive_Volume_Label$\n$File_System$\n$Disk_Capacity$\n$Free_Space$\n$Allocation_Unit_Size"
And if you could post the answer code for me and then point me where you got the info (the explanation of the) code. This help me learn the code faster if I know what its doing for what I need.
Thanks,
Albert
The code in the answer you found does actually return the name of the file system and then it goes on to tell you that that is probably not the best way to do things. You should use the file system flags if possible. Case in point, Microsofts new file system ReFS supports some of the NTFS features and adds some new reliability features.
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$9",t.r3,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t.r2,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
IntFmt $1 "%#.8x" $1
MessageBox MB_OK " FileSystemFlags=$1 $\n FileSystemName=$2 $\n VolumeName=$3"
${If} $2 == "NTFS"
MessageBox MB_OK "$9 is NTFS"
${Else}
MessageBox MB_OK "$9 is $2 and not NTFS but hopefully you don't care"
${EndIf}
${EndIf}
Your other properties are not exposed by this function which would be obvious if you looked at its documentation on MSDN.
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetDiskFreeSpaceEx(t "$9", *l.r1, *l.r2, *l.r3)i.r0' ; This function does not work on Windows 95
${If} $0 <> 0
MessageBox MB_OK " FreeBytesAvailable=$1 $\n TotalNumberOfBytes=$2 $\n TotalNumberOfFreeBytes=$3"
System::Call 'ShLwApi::StrFormatByteSizeW(l $1, w.r4, i ${NSIS_MAX_STRLEN})'
MessageBox MB_OK "Friendly FreeBytesAvailable: $4" ; For display in UI only!
!define /math MYSIZE 0x100000 * 666 ; 666 MiB
${If} $1 L>= ${MYSIZE}
MessageBox MB_OK "Disk quota on $9 allows you to write at least ${MYSIZE} bytes on this volume"
${Else}
MessageBox MB_OK|MB_ICONSTOP "Not enough space on volume, ${MYSIZE} bytes required!"
Quit
${EndIf}
${EndIf}
NSIS already provides a directory page that checks the disk space, use that if possible. Note: You cannot compare numbers of different scales (TB vs GB etc.), you must compare a 64-bit count of bytes.
By allocation unit I assume you are talking about the cluster size?
!include LogicLib.nsh
StrCpy $9 "c:\"
System::Call 'Kernel32::GetDiskFreeSpace(t "$9", *i.r1, *i.r2, *i, *i)i.r0'
${If} $0 <> 0
IntOp $1 $1 * $2
System::Call 'ShLwApi::StrFormatByteSizeW(l $1, w.r3, i ${NSIS_MAX_STRLEN})'
MessageBox MB_OK "Cluster size: $3 ($1 bytes)"
${If} 4096 <> $1
; ...
${EndIf}
${EndIf}
(The reported cluster size is probably the logical size, not the physical size)

nsis refresh environment during setup

During my setup i install redistributables. After installing my program i want to execute the program during the setup. For that the redistributables are needed. But the environment is not refreshed during setup, so i can't start the program. Can i refresh the environtment during the setup, or reread the environment? Or read the system environment which has changed after the redistributable installation?
I need the environment changes made during the installation of the redistributables during the setup.
Thanks for your help.
I had your same issue, that I solved with a workaround, but I came across this solution and I would like to share with you.
This should reload environment variables during setup:
!include LogicLib.nsh
!include WinCore.nsh
!ifndef NSIS_CHAR_SIZE
!define NSIS_CHAR_SIZE 1
!define SYSTYP_PTR i
!else
!define SYSTYP_PTR p
!endif
!ifndef ERROR_MORE_DATA
!define ERROR_MORE_DATA 234
!endif
/*!ifndef KEY_READ
!define KEY_READ 0x20019
!endif*/
Function RegReadExpandStringAlloc
System::Store S
Pop $R2 ; reg value
Pop $R3 ; reg path
Pop $R4 ; reg hkey
System::Alloc 1 ; mem
StrCpy $3 0 ; size
loop:
System::Call 'SHLWAPI::SHGetValue(${SYSTYP_PTR}R4,tR3,tR2,i0,${SYSTYP_PTR}sr2,*ir3r3)i.r0' ; NOTE: Requires SHLWAPI 4.70 (IE 3.01+ / Win95OSR2+)
${If} $0 = 0
Push $2
Push $0
${Else}
System::Free $2
${If} $0 = ${ERROR_MORE_DATA}
IntOp $3 $3 + ${NSIS_CHAR_SIZE} ; Make sure there is room for SHGetValue to \0 terminate
System::Alloc $3
Goto loop
${Else}
Push $0
${EndIf}
${EndIf}
System::Store L
FunctionEnd
Function RefreshProcessEnvironmentPath
System::Store S
Push ${HKEY_CURRENT_USER}
Push "Environment"
Push "Path"
Call RegReadExpandStringAlloc
Pop $0
${IfThen} $0 <> 0 ${|} System::Call *(i0)${SYSTYP_PTR}.s ${|}
Pop $1
Push ${HKEY_LOCAL_MACHINE}
Push "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
Push "Path"
Call RegReadExpandStringAlloc
Pop $0
${IfThen} $0 <> 0 ${|} System::Call *(i0)${SYSTYP_PTR}.s ${|}
Pop $2
System::Call 'KERNEL32::lstrlen(t)(${SYSTYP_PTR}r1)i.R1'
System::Call 'KERNEL32::lstrlen(t)(${SYSTYP_PTR}r2)i.R2'
System::Call '*(&t$R2 "",&t$R1 "",i)${SYSTYP_PTR}.r0' ; The i is 4 bytes, enough for a ';' separator and a '\0' terminator (Unicode)
StrCpy $3 ""
${If} $R1 <> 0
${AndIf} $R2 <> 0
StrCpy $3 ";"
${EndIf}
System::Call 'USER32::wsprintf(${SYSTYP_PTR}r0,t"%s%s%s",${SYSTYP_PTR}r2,tr3,${SYSTYP_PTR}r1)?c'
System::Free $1
System::Free $2
System::Call 'KERNEL32::SetEnvironmentVariable(t"PATH",${SYSTYP_PTR}r0)'
System::Free $0
System::Store L
FunctionEnd
Section
Call RefreshProcessEnvironmentPath
SectionEnd
Source: http://forums.winamp.com/showpost.php?p=3028153&postcount=12

Resources