NSIS Get file version of EXE that is UPX Compressed - nsis

I have been using a little NSIS script for a few years that grabs the version of the EXE so I can display it in the installers welcome text.
I got the script here: http://nsis.sourceforge.net/Invoking_NSIS_run-time_commands_on_compile-time
!define File "C:\MyFile.exe"
OutFile "GetVersion.exe"
SilentInstall silent
Section
## Get file version
GetDllVersion "${File}" $R0 $R1
IntOp $R2 $R0 / 0x00010000
IntOp $R3 $R0 & 0x0000FFFF
IntOp $R4 $R1 / 0x00010000
IntOp $R5 $R1 & 0x0000FFFF
StrCpy $R1 "$R2.$R3.$R4.$R5"
## Write it to a !define for use in main script
FileOpen $R0 "$EXEDIR\Version.txt" w
FileWrite $R0 '!define Version "$R1"'
FileClose $R0
SectionEnd
Recently I started using UPX to compress the EXE of the application.
Now that it is UPX compressed, the file version script no longer works, I'm guessing due to non standard header layout.
How can I read the file version from a UPX compressed EXE?
UPDATE: This is closed now but I discovered later this is likely to do with some kind of elevated permissions issue and running the command over a mapped drive.

Even when using UPX --ultra-brute test.exe the version information block did not get compressed when I tried. Are you using special UPX switches? Have you tried --keep-resource=%resourceid%?
If you are using NSIS v3 you can use !getdllversion to get the version at compile-time without having to use !system.

Related

read persian text file with using inetc plugin in nsis

I have many text file with persian text: "سلام"
now I want to read the text file and write to the variable directly
i use from the inetc plugin sample this:
Unicode true
Section
;test_Unicode_BE_BOM.txt:
inetc::get /NOCANCEL /TOSTACK /SILENT "http://update.nodmarket.com/Persian_Text_Files/test_Unicode_BE_BOM.txt" /END
Pop $R0
Pop $R1
MessageBox MB_OK "$R1"
;test_Utf8_BOM.txt
inetc::get /NOCANCEL /TOSTACK /SILENT "http://update.nodmarket.com/Persian_Text_Files/test_Utf8_BOM.txt" /END
Pop $R0
Pop $R1
MessageBox MB_OK "$R1"
;test_Unicode_LE_BOM.txt
inetc::get /NOCANCEL /TOSTACK /SILENT "http://update.nodmarket.com/Persian_Text_Files/test_Unicode_LE_BOM.txt" /END
Pop $R0
Pop $R1
MessageBox MB_OK "$R1"
SectionEnd
but after show i see this text in messagebox:
inetc plugin and source page:
what is the problem?
why i see the broken persian text after read from inetc plugin?
when i use the code
Unicode true
Section
MessageBox MB_OK|MB_RIGHT|MB_RTLREADING "سلام"
SectionEnd
i see "سلام" in messagebox successful
but i think inetc plugin Ruins Persian words!
INetC does not really support Unicode conversion on the fly.
If you need full control you have to download the file to a temporary directory and then read it with NSIS file instructions.
InitPluginsDir
inetc::get /NOCANCEL /SILENT "http://update.nodmarket.com/Persian_Text_Files/test_Unicode_LE_BOM.txt" "$PluginsDir\test.txt" /END
Pop $0
${If} $0 == "OK"
FileOpen $1 "$PluginsDir\test.txt" r
FileReadUTF16LE $1 $2
FileClose $1
MessageBox mb_ok $2
${EndIf}
I uploaded a new version of INetC to the wiki for you with limited UTF-8 and UTF-16LE support (BOM required).
inetc::get /NOCANCEL /TOSTACKCONV /SILENT "http://update.nodmarket.com/Persian_Text_Files/test_Utf8_BOM.txt" /END ; v1.0.5.3+ required for /TOSTACKCONV to support BOM detection.
Pop $R0
Pop $R1
MessageBox MB_OK "$R0:$R1"
Putting Unicode text in a .nsi file works because the NSIS compiler supports Unicode but text returned by a plug-in has its text handling inside the plug-in and it might not support Unicode.

nsis - remove pinned icon from taskbar on uninstall

I'm working on an app for a company and they requested that if the app is pinned to the taskbar, when uninstalling the app should be unpinned. If I just delete the icon from quicklaunch\user pinned\taskbar then it leaves a blank icon on the taskbar.
I need to somehow actually unpin it. The only thing I've come across is installing winshell plugin (http://nsis.sourceforge.net/WinShell_plug-in) and then calling IStartMenuPinnedList::RemoveFromList (https://msdn.microsoft.com/en-us/library/windows/desktop/bb774817(v=vs.85).aspx)
I'd rather not install a plugin if I don't need to. Does anyone have any suggestions?
NSIS does not have native support for this interface so you have to use a plug-in. If you want to avoid that 3rd-party plug-in (written by me) then you can use the System plug-in instead:
!include "LogicLib.nsh"
!include "Win\COM.nsh" ; NSIS v3+
!macro UnpinShortcut lnkpath
Push $0
Push $1
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_StartMenuPin} ${IID_IStartMenuPinnedList} r0 ""
${If} $0 P<> 0
System::Call 'SHELL32::SHCreateItemFromParsingName(ws, p0, g "${IID_IShellItem}", *p0r1)' "${lnkpath}"
${If} $1 P<> 0
${IStartMenuPinnedList::RemoveFromList} $0 '(r1)'
${IUnknown::Release} $1 ""
${EndIf}
${IUnknown::Release} $0 ""
${EndIf}
Pop $1
Pop $0
!macroend
Section Uninstall
!insertmacro UnpinShortcut "$SMPrograms\MyApp.lnk"
Delete "$SMPrograms\MyApp.lnk"
SectionEnd

Can i detect 32 or 64 bit OS without plugin somehow?

now i use the x64.nsh for this, but i can detect it without this plugin?
${If} ${RunningX64}
MessageBox MB_OK "running on 64 bit"
File /r ${64BIT_OPENVPN_INSTALL}
Execwait ${64BIT_OPENVPN_INSTALL}
${Else}
MessageBox MB_OK "running on 32 bit"
File /r ${32BIT_OPENVPN_INSTALL}
Execwait ${32BIT_OPENVPN_INSTALL}
${EndIf}
x64.nsh does not implies specific external plugin usage (apart the system plugin): it is just an included file that defines 3 macros based on kernel calls (i.e kernel32::GetCurrentProcess() and kernel32::IsWow64Process()) through the system plugin, that can be conveniently used with LogicLib.nsh
There are probably many ways to detect the native bitness by just looking at files and registry keys but there is always the risk that some 32-bit systems have somehow ended up with a SysWOW64 folder in %WinDir% etc.
The SetRegView test should be pretty safe but there is a small window where some other app could change the registry at just the wrong time giving you the wrong result.
The correct way to detect this is of course to call the IsWow64Process function and the x64.nsh header already does that for you.
!include LogicLib.nsh
Section
!if "${NSIS_PTR_SIZE}" > 4
DetailPrint "64-bit NSIS, this must be a 64-bit system"
!endif
${If} ${FileExists} "$WinDir\SysWOW64\kernel32.dll"
DetailPrint "Probably not a native 32-bit system"
${EndIf}
${If} ${FileExists} "$WinDir\SysNative\kernel32.dll"
DetailPrint "Probably a 32-bit app on a native 64-bit system (Vista+ only)"
${EndIf}
SetRegView 64
ReadRegStr $6 HKLM "Software\Microsoft\Windows\CurrentVersion" "ProgramFilesDir"
SetRegView lastused
SetRegView 32
ReadRegStr $3 HKLM "Software\Microsoft\Windows\CurrentVersion" "ProgramFilesDir"
SetRegView lastused
${If} $3 != $6
DetailPrint "Probably a 32-bit app on a native 64-bit system"
${EndIf}
; ReadEnvStr on ProgramW6432 or PROCESSOR_ARCHITEW6432 etc
SectionEnd

how can i make my installer to check for invalid folder installation?

.Actually i have installed different version of the software in the same computer so want to check the folder for both the version when user proceed for third version of installation. i am trying to use loop but the the installer is not working.Thanks in advance.
I have already 2 versions of same software installed in the same computer .I want when i will install the third version the script should check the path and it should not allow user to install in the same path in which previous two versions are already installed
Function .onVerifyInstDir
nsArray::Set array 1.6
nsArray::Set array 1.7
nsArray::Set array 1.8
nsArray::Length array
Pop $R0
;DetailPrint `array length: $R0`
StrCpy $R1 0
${DoWhile} $R1 < $R0
nsArray::Get array $R1
Pop $R2
StrCpy $tempregistry "$(^Name)_$R2"
;DetailPrint `MyArray2[$R1] is $R2`
ReadRegStr $path HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstal\$tempregistry""InstallLocation" ;fetching installed location
${If} $path == ""
${Else}
strCmp $path $INSTDIR 0 pathGood
;Abort
IntOp $R1 $R1 + 1
${EndIf}
${Loop}
PathGood:
FunctionEnd
Here are the steps
Store ur product name or ur registry entry in a variable.
Store the path to be installed in a variable eg $path
Inside a loop check for the registry entry.
ReadRegStr $pdt HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\productname
If found,retrieve the value of the installed location and store it in a variable;
eg $path1
ReadRegStr $path1 $pdt "installed location"
else proceed
${if} $path == $path1
messagebox mb_ok "Another version already installed in the path"
${else}
proceed
${endif}

NSISdl could not open file during download

I'm using NSIS to create an installer which will install files from a web server. I'm using the NSISdl plugin to download the files but they are not downloading, it just says Download Failed: failed to open file.
This is the section which is doing the download, could I be missed something here.
Section "Aquiva"
; Set output path to the installation directory.
SetOutPath $INSTDIR
;Include files from this location, and copy that to the current
;out path
NSISdl::download http://41.78.239.158/Aquiva.exe
Pop $R0 ;Get the return value
StrCmp $R0 "success" +3
MessageBox MB_OK "Download failed: $R0"
Quit
SectionEnd ; end the section
You should use inetc for this purpose:
inetc::get "http://41.78.239.158/Aquiva.exe" "$EXEDIR\Aquiva.exe"
pop $R0
DetailPrint "Result: $R0"
You can get it here
If you insist on using NSISdl, your problem is probably due to not specifying the destination file, try this:
NSISdl::download http://41.78.239.158/Aquiva.exe "$INSTDIR\Aquiva.exe"
pop $R0
...

Resources