System::Call to external .dll during NSIS uninstall - nsis

During the installation of my application I install a library used to export various functions to $INSTDIR. During uninstallation I want to call a function in this library to perform a task and return. Based on what I've tried so far it seems that the call to the function fails and I always get back 'error' as $0.
This is what I'm running in my uninstallation script:
SetPluginUnload alwaysoff
SetOutPath $INSTDIR
System::Call "myutils::uninstalling() i.r0"
DetailPrint 'RETURN CODE: "$0"'
SetPluginUnload manual
The few examples I've found copied the .dll to a temp directory and then ran System:Call but the library is already in $INSTDIR. Thoughts?

Wasn't an issue with the NSIS code, the function needed to be exported in the .def file so NSIS could resolve it sans decoration.

Related

Delete command after execwait is not working

I'm creating one installer. I need VC++2013 runtime for my applicaiton. So i'm checking and if not found VC++ runtime i'm installing it from my installer.
To do that, I'm copying VC++ runtime exe into programfiles/myapplication and running it using
ExecWait '"$INSTDIR\vc.exe" /passive /norestart' $0
Delete "$INSTDIR\vc.exe"
But the problem is vc.exe is not getting deleted. It remains in programfiles/myapplication folder.
I use IfErrors command and found that error occurs.
Please suggest me how to solve this
ExecWait always waits until the child process ends but just because the process has ended does not mean you can delete the .EXE file. It should ideally mean that but in some cases Explorer or Anti-Virus will keep files locked for a couple of seconds. Without more information it is hard to say why it can't be deleted, Process Monitor will probably provide some clues.
You could try
ExecWait '"$INSTDIR\vc.exe" /passive /norestart' $0
Sleep 2500
Delete "$INSTDIR\vc.exe"
but since you are just going to delete it anyway, I would suggest extracting it somewhere else that NSIS will try to clean up for you instead:
Section
InitPluginsDir
File "/oname=$PLUGINSDIR\vc.exe" "c:\myredistfiles\vc.exe"
ExecWait '"$PLUGINSDIR\vc.exe" /passive /norestart' $0
SectionEnd

How can I create a single NSIS script which will generate different installers based on an input parameter?

I have an application which has development, testing and live versions. I have a command procedure which currently creates 3 different versions of the installer, which can be installed on 3 separate computers.
What I would like to do would be to have one NSIS script which I pass in a parameter to, which will create one of the versions of the installer changing the name of the product and the installation folder. This will allow me to install all 3 versions on the same computer.
What I have tried so far is;
Function .onInit
Var /GLOBAL INSTALL_TYPE
${GetOptions} $CMDLINE "/t" $INSTALL_TYPE
${if} $INSTALL_TYPE == ""
StrCpy $INSTALL_TYPE "Live"
ReadEnvStr $R0 SYSTEMDRIVE
StrCpy $INSTDIR "$LOCALAPPDATA\Programs\MyComp\MyApp$INSTALL_TYPE\"
FunctionEnd
!define MUI_PRODUCT "FCDS-RECAP$INSTALL_TYPE"
OutFile "MyApp-$INSTALL_TYPEinstaller.exe"
One of the main errors I get has to do with MUI_PRODUCT and look similar to;
warning 6000: unknown variable/constant "INSTALL_TYPE.lnk" detected, ignoring (FullDeploymentUser.nsi:121)
warning 6000: unknown variable/constant "INSTALL_TYPE" detected, ignoring (FullDeploymentUser.nsi:124)
Two types of comments would be useful;
This is what you are doing wrong...
This is what you should be doing...
As always any help is appreciated.
MUI_PRODUCT is technically not an official NSIS define, some guy just invented it and used it in a guide.
All instructions starting with ! are preprocessor instructions, those and OutFile and File cannot be controlled by ${GetOptions} because they happen at compile time on your developer machine.
I don't really recommend this 3 in 1 installer solution, it is a bit complicated. It is much better to just create 3 different installers:
!ifndef APPTYPE
!error "APPTYPE not defined"
!endif
Name "MyApp ${APPTYPE}"
OutFile "MyApp ${APPTYPE} setup.exe"
InstallDir "$ProgramFiles\MyApp ${APPTYPE}"
Page Directory
Page InstFiles
Section
SetOutPath $InstDir
File /r "c:\myfiles\MyApp\${APPTYPE}\*"
SectionEnd
and then just generate them with makensis -DAPPTYPE=Beta myapp.nsi etc.
If you really want this 3 in 1 style then you need to use the macros in Sections.nsh to manipulate the sections so that only one of them is visible and active. You also need to mark the install somehow (.ini file?) so that your uninstaller also knows which install type it is uninstalling.

NSIS: Install a folder based on 32/64 bits

I'm working on a installer script that needs to install one of two folders based on the OS bits. The selection occurs fine so far but for some reason I only see one folder within the resulting installer.
The relevant sections are below:
;Windows 32 or 64 bit version
!include "x64.nsh"
Section "JRE 64 Bit" Section5
SectionIn RO
;Use the right java version
DetailPrint "JRE extraction..."
SetOutPath "$INSTDIR\${APPDIR}\jre"
File /a /r "${SrcDir}\..\..\jre\jre_64\jre\*.*"
DetailPrint "JRE extraction complete!"
SectionEnd
Section "JRE 32 Bit" Section6
SectionIn RO
;Use the right java version
DetailPrint "JRE extraction..."
SetOutPath "$INSTDIR\${APPDIR}\jre"
File /a /r "${SrcDir}\..\..\jre\jre_32\jre\*.*"
DetailPrint "JRE extraction complete!"
SectionEnd
Function .onInit
#Determine the bitness of the OS and enable the correct section
IntOp $0 ${SF_SELECTED} | ${SF_RO}
${If} ${RunningX64}
SectionSetFlags ${Section5} $0
SectionSetFlags ${Section6} ${SECTION_OFF}
${Else}
SectionSetFlags ${Section5} ${SECTION_OFF}
SectionSetFlags ${Section6} $0
${EndIf}
FunctionEnd
Both folders exists as there is no warning. But instead of seeing two folders (jre_64 and jre_32) I just see one jre folder within the installer.
Is this expected behavior? I'm using NSIS 2.51. The resulting instaler can be found here.
You can see the full script here.
I guess it's because of the delta compression, as the two jre directories should have quite similar contents. The structure when viewing using 7-Zip doesn't necessarily represent the internal structure of the installer, which seems to be quite opaque.
I tried to find a tool to "properly" unpack the installer (like innounp for Inno Setup), but without success. This confirms the NSIS installer structure should be really opaque.
Did you do some manual testing to determine if the installer works as expected in both cases?
The path used in File instructions are not stored in the installer (except for the last path component if it is a folder), it is used to find the files on your development system. As you probably know, SetOutPath sets the destination directory and decompilers can only display parts of that path (they cannot resolve custom variables) and you used just "jre" for both the 32-bit and 64-bit folders.
7-zip is not a full decompiler, it only does what is needed to find the destination path names and it does not understand that there are really two different jre folders selected by your if statements.
NSIS will only store identical files once, add SetDatablockOptimize off to the top of your script and your installer will probably double in size.

Not able to Delete file using NSIS

I have a question related to NSIS.
I have an installer created by NSIS in ("c:/Installer/Installer.exe" folder).
When I run the installer it creates a log file("c:/Installer/installlog.txt") in the installation folder. After I successfully run Installer.exe I want only the installlog.txt to be deleted from "c:/Installer" .
I have the following function
Function .onInstSuccess
call cleanUp
ifSilent 0 +2
${LogText} "INFO :: Application has been installed"
CopyFiles "$EXEDIR\${INSTALL_LOG}" "$Dir\LogFiles\"
IfFileExists "$Dir\LogFiles\{INSTALL_LOG}" DoNothing CopyAgain
CopyAgain:
CopyFiles "$DIR\${INSTALL_LOG}" "$Dir\LogFiles\"
Delete "$DIR\${INSTALL_LOG}"
goto DoNothing
DoNothing:
SetOutPath $EXEDIR
Delete "$EXEDIR\*.log" ;....................**but the file does not get deleted**
FunctionEnd
can some one please tell me how can I make this work.
I need to fix this as soon as possible, help on this is greatly appreciated
I assume you are using these logging macros. You should call ${LogSetOff} after the last call to ${LogText} so the file handle is closed, you should then be able to delete the file.
Also, using Delete "$EXEDIR\*.log" is not a good idea, you already know the filename...

Execute files which are generated while runtime

Still in progress with NSIS Setup.
The thing is now I´m executing NSIS executables during my "main" setup. Those other setups, which I´m executing, generate uninstaller for themselve. When I´m performing the uninstaller in the main setup I would like to call those generated uninstaller files.
I´m doing the execution with nsExec::ExecToLog but if a executable is not from the decompressed from the .exe you won´t be able to execute it. Am I right? Is there any solution to solve this problem?
I´m very grateful for every answer!
You can use nsExec::ExecToLog with whatever you like.
It could be extracted:
SetOutPath $INSTDIR
File foo.exe
nsExec::ExecToLog $INSTDIR\foo.exe
It could be a path already known:
nsExec::ExecToLog $WINDIR\bar.exe
It could be calculated:
ReadINIStr $0 $INSTDIR\uninstaller-paths.ini UninstallerPaths baz
nsExec::ExecToLog $0
It really doesn't matter. As far as the script is concerned, it's purely a command string to execute.

Resources