NSIS conditional statement - nsis

I am writing a script code which installs 3 drivers. Every time that a driver is installed I get a return code of '256' or '1' if the installation was successful, or a different return code if the installation failed. I need to check that all installations finished sucessfully, so I use the following code:
${If} "$2" == "1"
${OrIf} "$1" == "256"
${AndIf} "$2" == "256"
${OrIf} "$2" == "1"
${AndIf} "$3" == "256"
${OrIf} "$3" == "1"
MessageBox MB_OK "Installation was successful!"
${Else}
MessageBox MB_OK "Sorry, an error occurred during installation."
${EndIf}
Even if a driver installation fails I receive the message "Installation was successful!". Could someone help me find the mistake in the above code?

In your example code the first ${If} is using $2 when it should probably check $1.
I don't think you should use OrIf and AndIf in the same if block like this, the results are probably undefined.
It is also possible to write your own custom LogicLib operators:
!include LogicLib.nsh
!macro _MyCheckExitcodeSuccess _a _b _t _f
!if `${_f}` == ``
!undef _f
!define _f +2
!endif
IntCmp ${_b} 1 +2
IntCmp ${_b} 256 `${_t}` `${_f}` `${_f}`
!if `${_t}` != ``
Goto `${_t}`
!endif
!macroend
!define MyCheckExitcodeSuccess `"" MyCheckExitcodeSuccess`
StrCpy $1 1
StrCpy $2 256
${If} ${MyCheckExitcodeSuccess} $1
${AndIf} ${MyCheckExitcodeSuccess} $2
MessageBox mb_ok "All OK"
${Else}
MessageBox mb_ok "Something failed"
${EndIf}

A slightly slimpler way would be to do something like
; 1_256_1_256 is defined if we are good
!define $1_256_$2_256
!define $1_256_1_$2
!define 1_$1_1_$2
!define 1_$1_$2_256
!ifdef 1_256_1_256
message mb_ok "All good"
!else
message mb_ok "Failure detected"
!endif

Related

How can I use the following script?

I want to delete all files except the Bookmarks file from the Default folder. But the following code does not work. I know I should use the Batch file, but is there a way to use the code below? Thank you for any help
ExecWait '"$SYSDIR\cmd.exe" /c "SET "sourcedir=$LOCALAPPDATA\Google\Default" & SET "keepfile=Bookmarks" & FOR %a IN ("%sourcedir%*") DO IF /i NOT "%~nxa"=="%keepfile%" DEL "%a""'
Section "Prepare example"
SetOutPath "$LOCALAPPDATA\Google\Default"
SetOverwrite off
File "/oname=$outdir\Bookmarks" "${__FILE__}"
File "/oname=$outdir\Blah" "${__FILE__}"
File "/oname=$outdir\Footmarks" "${__FILE__}"
SectionEnd
!include LogicLib.nsh
Section
StrCpy $2 "$LOCALAPPDATA\Google\Default"
FindFirst $0 $1 "$2\*"
loop:
StrCmp $1 "" done
StrCmp $1 . next
StrCmp $1 .. next
${If} $1 != "Bookmarks"
Delete "$2\$1"
${EndIf}
next:
FindNext $0 $1
Goto loop
done:
FindClose $0
SectionEnd

Read And Update JSON File Using nsJSON Plugin (NSIS)

I am trying to update one data on JSON file using nsJson Plugin.
My JSON data on File
{ "header_left_lebel": "LEFT LEBEL",
"header_center_label": "CENTER LEBEL",
"base_path": "E:\Workspace\my-demo-app"
}
I want to edit the base path during installation of the application.
My Code to Read and Update the Value
Section "Installation Section"
SetOutPath "$INSTDIR"
GetFullPathName $0 ..
StrCpy $installationPath "$0\${applicationName}";This Holds the installation path
nsJSON::Set /file `$installationPath/config/settings.json`
nsJSON::Set `base_path` /value `"$installationPath"`
nsJSON::Serialize /file `$installationPath/config/settings.json`
WriteUninstaller "$INSTDIR\Uninstall.exe"
SectionEnd
The above code updates the JSON file but it only keeps base_path
I want to keep all the data and only to update base_path
Any help or links will be appreciated.
Your code works correctly for me when using NSIS v3.04 and JSON plug-in v1.1.1.0 (November 2017):
Unicode True
!macro DumpTxtFile file
Push "${file}"
Call DumpTxtFile
!macroend
Function DumpTxtFile
Exch $0
Push $1
FileOpen $0 $0 r
loop:
ClearErrors
FileRead $0 $1
IfErrors done
DetailPrint $1
Goto loop
done:
FileClose $0
Pop $1
Pop $0
FunctionEnd
!include LogicLib.nsh
Section
FileOpen $0 "$temp\NSIStest.json" w
FileWrite $0 '{ "header_left_lebel": "LEFT LEBEL",$\r$\n'
FileWrite $0 ' "header_center_label": "CENTER LEBEL",$\r$\n'
FileWrite $0 ' "base_path": "E:\Workspace\my-demo-app"$\r$\n'
FileWrite $0 '}'
FileClose $0
!insertmacro DumpTxtFile "$temp\NSIStest.json"
Var /Global installationPath
StrCpy $installationPath "c:\dummy\path"
ClearErrors
nsJSON::Set /file `$temp\NSIStest.json`
nsJSON::Set `base_path` /value `"$installationPath"`
nsJSON::Serialize /format /file `$temp\NSIStest.json`
${If} ${Errors}
Abort "Unable to update JSON file!"
${EndIf}
!insertmacro DumpTxtFile "$temp\NSIStest.json"
SectionEnd

NSIS Inetc get: can I make the downloaded file a variable?

The code is working when I have File_1234.exe added there. But the file name changes and download.php redirects to the exe. So instead of having a fixed file name there, I would like to have a code where i don't need to specify file name.
Is it possible to replace the first File_1234.exe with code to download whatever file the URL gives, and therefore to replace the second File_1234.exe with code that would run (ExecShell) this downloaded file?? Thanks
The code itself is here:
Section "File"
inetc::get "http://example.com/download.php" "$pluginsdir\File_1234.exe"
Pop $0
DetailPrint "Result: $R0"
ExecShell "" '"$pluginsdir\File_1234.exe"'
SectionEnd
INetC does not have a flag that passes the INTERNET_FLAG_NO_AUTO_REDIRECT flag to WinInet so there is no way to do a head request and find the location when the server returns a 30x redirection code.
If you can modify download.php to just return the final URL as a small text file when a special parameter is present then you can make two GET requests, the first to get the name and the second to do the main download:
Section
InitPluginsDir
StrCpy $0 "http://example.com/download.php?fileid=1234"
inetc::get /SILENT "$0&locationonly=1" "$PluginsDir\location.txt" /END
FileOpen $1 "$PluginsDir\location.txt" R
FileRead $1 $2
FileClose $1
StrLen $1 $2
loop:
IntOp $1 $1 - 1
StrCpy $3 $2 1 $1
StrCmp $3 '/' 0 +4
IntOp $1 $1 + 1
StrCpy $3 $2 "" $1
Goto +2
StrCmp $3 "" 0 loop
StrCmp $3 "" nofilename
inetc::get "$0" "$PluginsDir\$3" /END
Goto done
nofilename:
MessageBox mb_iconstop "Unable to parse filename from $2"
done:
SectionEnd
This example assumes that http://example.com/download.php?fileid=1234 would download the file but http://example.com/download.php?fileid=1234&&locationonly=1 would only return a URL like http://example.com/myfiles/whatever.exe
This is a 5 year later answer to help who ever might want to know how to get inetc::get output into a variable ;)
Obviously you found a solution since then... anyway:
inetc::get has a nice option /TOSTACK that does this.
Here's how on your example:
!include LogicLib.nsh
Section "File"
inetc::get /TOSTACK "http://example.com/download.php" ""
Pop $0
DetailPrint "Result: $0"
${If} $0 == 'OK'
Pop $0
StrCpy $filename $0
inetc::get /TOSTACK "http://example.com/$filename" "$PluginsDir\$filename"
Pop $0
${If} $0 == 'OK'
ExecShell "" '"$pluginsdir\$filename"'
${Else}
MessageBox MB_OK "Cannot download file $filename"
${EndIf}
${Else}
MessageBox MB_OK "Cannot fetch filename to download"
${EndIf}
SectionEnd
This is possible if your "http://example.com/download.php" returns URL of file to download.
What I mean: download.php returns URL as text ("http://example.com/file_12345.exe").
1) This text is downloaded with inetc to some local file and read into variable.
2) Use Inetc to download the file from URL (specified in variable) again as a resulting .exe file.
Is this acceptable for you?

Why is temporary file not deleted in NSIS?

I have compared two files and stored mismatched values in the temporary file. I have referred to this link. After that read the values from temporary file and replaced in original file. Finally I have tried to delete temporary file. All the process working fine except temporary file deletion.
I have used following code:
page custom twofilecompare
page custom originalwrite
Function twofilecompare
FileOpen $0 "$INSTDIR\backup.properties" "r"
FileOpen $1 "$INSTDIR\orginal.properties" "r"
#IfFileExists "$INSTDIR\temp.properties" 0 +1
#Delete /REBOOTOK "$INSTDIR\temp.properties"
FileOpen $R0 "$INSTDIR\temp.properties" "w"
ClearErrors
loop:
FileRead $0 $2
${If} $2 == "$\r$\n"
Goto loop
${EndIf}
FindClose $0
FileRead $1 $3
IfErrors done
strcmp $2 $3 loop here
here:
FileWrite $R0 $2
Goto loop
done:
FileClose $0
FileClose $1
FileClose $R0
FunctionEnd
Function originalwrite
IfFileExists "$INSTDIR\temp.properties" 0 filenotfound
FileOpen $0 "$INSTDIR\temp.properties" "r"
loop:
FileRead $0 $1
IfErrors done
//do some stuff
done:
**IfFileExists "$INSTDIR\resource\temp.properties" 0 filenotfound
Delete /REBOOTOK "$INSTDIR\temp.properties"**
filenotfound:
MessageBox MB_OK "file not found"
FunctionEnd
Even I cant able modify these three files[temp,backup,original] manually also.If i modify and click save prompt message displayed as "please check if this file opened another program"
I have also used file closed after file usage as completed.
Even i have tried this code also
Function .onInstSuccess
IfFileExists "$INSTDIR\temp.properties" notfound
MessageBox MB_OK "file exists"
Delete /REBOOTOK $INSTDIR\temp.properties
Goto done
notfound:
MessageBox MB_OK "file not found"
Done:
MessageBox MB_OK "file deleted"
FunctionEnd
But the temporary file is not deleted. How to delete temporary this file?
Can someone help me?
Thanks in advance
The originalwrite function is missing FileClose
Are you requesting admin rights in your script?
RequestExecutionLevel admin
Some applications like Notepad++ will display a "please check if this file opened another program" message if you try to edit a file that needs admin rights to edit (such as a text file in C:\Program Files).

How can I make Array of Structure in NSIS

I have an XML file....Now I want to Parse it and store data into Array of structure as per my requirement in NSIS SCRIPT.
This is my XML:-
<?xml version="1.0" ?>
- <request>
- <software>
<id>1</id>
<name>software</name>
<description>is a file archiver with a high compression ratio.</description>
<download_url>http://surfnet.dl.sourceforge.net/project/sevenzip/7-Zip/9.20/7z920.exe</download_url>
<image_url>http://assets.airinstaller.com/graphics/software/7zip/left_side.bmp</image_url>
</software>
- <offers>
- <offer>
<rank>1</rank>
- <options>
- <option>
<text>Install Facemoods1</text>
<value>/TOOLBAR</value>
<required>true</required>
</option>
- <option>
<text>Set Facemoods as my default search provider1</text>
<value>/DEFAULTSEARCH</value>
<required>false</required>
</option>
</options>
<install_location>{pf}/IssPro c.dll</install_location>
<name>1</name>
<tagline>The Ringtone Maker</tagline>
<description>makes creating ringtones really easy.</description>
<exe_cmd />
<download_url>http://174.36.153.163/silent-ringtonejunkiez-installer.exe</download_url>
<conversion_url>http://api.airinstaller.com/get/installed.php?session=9649922a0d879d92752f3925e07153c3&app=2&aff=1&off=1</conversion_url>
<image_url>http://assets.airinstaller.com/graphics/offers/ringtonejunkiez/logo.bmp</image_url>
<privacy_url>http://www.google.com/intl/en/privacy/privacy-policy.html</privacy_url>
<terms_url>http://www.google.com/accounts/TOS</terms_url>
</offer>
- <offer>
<rank>2</rank>
- <options>
- <option>
<text>Install Facemoods</text>
<value>/TOOLBAR</value>
<required>true</required>
</option>
- <option>
<text>Set Facemoods as my default search provider</text>
<value>/DEFAULTSEARCH</value>
<required>false</required>
</option>
- <option>
<text>Set Facemoods as my default home and new tab page</text>
<value>/DEFAULTSTART</value>
<required>false</required>
</option>
</options>
<name>Ringtone 2</name>
<tagline>The Ringtone Maker</tagline>
<description>makes creating ringtones really easy.</description>
<exe_cmd />
<download_url>http://174.36.153.163/silent-ringtonejunkiez-installer.exe</download_url>
<conversion_url>http://api.airinstaller.com/get/installed.php?session=9649922a0d879d92752f3925e07153c3&app=2&aff=1&off=1</conversion_url>
<image_url>http://assets.airinstaller.com/graphics/offers/ringtonejunkiez/logo.bmp</image_url>
<privacy_url>http://www.google.com/intl/en/privacy/privacy-policy.html</privacy_url>
<terms_url>http://www.google.com/accounts/TOS</terms_url>
</offer>
- <offer>
<rank>3</rank>
<id>13</id>
<install_location>{pf}/Real/RealPlayer/f ixrjb.exe</install_location>
<name>3</name>
<description>makes creating ringtones really easy.</description>
<exe_cmd />
<download_url>http://174.36.153.163/silent-ringtonejunkiez-installer.exe</download_url>
<conversion_url>http://api.airinstaller.com/get/installed.php?session=9649922a0d879d92752f3925e07153c3&app=2&aff=1&off=1</conversion_url>
<image_url>http://assets.airinstaller.com/graphics/offers/ringtonejunkiez/logo.bmp</image_url>
<privacy_url>http://www.google.com/intl/en/privacy/privacy-policy.html</privacy_url>
<terms_url>http://www.google.com/accounts/TOS</terms_url>
</offer>
</offers>
</request>
Please Anyone help me to Parse it and Store into array of Structures in NSIS Script...
I am badly stucked here....
Thanks for reply but I did not get this.......
I have parsed the XML with this method
${XML::GotoPath} "/request/software" $0
${XML::NextSiblingElement} "" $0 $1
DetailPrint "Next Sibling Element of Root Element=$0" ; SIBLING OF SOFTWARE (SECOND CHILD OF ROOT)
${XML::XPathString} "count(//offer)" $0 $1
StrCpy $ccount_offer $0
;${If} $0 != ""
; IntOp $count_offer $count_offer + 1
; DetailPrint "Count= $0 and $count_offer"
;Goto for
;${Else}
;Goto next
;${EndIf}
${For} $R1 1 $ccount_offer
${If} $R1 == 1
${XML::FirstChildElement} "" $0 $1
DetailPrint "Element in Offers=$0" ; FIRST ElEMENT IN OFFERS
${xml::ElementPath} $0
StrCpy $ccurrent_path $0
${Else}
${XML::NextSiblingElement} "" $0 $1
DetailPrint "Element in offer=$0"
${xml::ElementPath} $0
StrCpy $ccurrent_path $0
${EndIf}
${XML::XPathString} "count(child::*)" $0 $1
;DetailPrint "count======$0"
StrCpy $ccount_offer_child $0
${XML::FirstChildElement} "" $0 $1 ;first child of offer
DetailPrint "Element in Offer=$0"
${XML::GetText} $0 $1
DetailPrint "Text in it=$0"
IntOp $ccount_offer_child $ccount_offer_child - 1
${For} $R2 1 $ccount_offer_child
;${If} $R2 == 1
;${Else}
${XML::NextSiblingElement} "" $0 $1
DetailPrint "Element in Offer=$0"
${If} $0 == "options" ; options for loops
${xml::ElementPath} $0
StrCpy $llast_current_path $0
${XML::XPathString} "count(child::*)" $0 $1
StrCpy $ccount_options $0
${If} $0 != 0
${For} $R3 1 $ccount_options
${If} $R3 == 1
${XML::FirstChildElement} "" $0 $1
DetailPrint "Element in Options=$0"
${xml::ElementPath} $0
StrCpy $llast_last_current_path $0
${XML::XPathString} "count(child::*)" $0 $1
StrCpy $ccount_options_option $0
${For} $R4 1 $ccount_options_option
${If} $R4 == 1
${XML::FirstChildElement} "" $0 $1
DetailPrint "Element in Option=$0"
${XML::GetText} $0 $1
DetailPrint "Text in it=$0"
${Else}
${XML::NextSiblingElement} "" $0 $1
DetailPrint "Element in Option=$0"
${XML::GetText} $0 $1
DetailPrint "Text in it=$0"
${EndIf}
${Next}
${XML::GotoPath} $llast_last_current_path $0
${Else}
${XML::GotoPath} $llast_last_current_path $0
${XML::NextSiblingElement} "" $0 $1
DetailPrint "Element in Options=$0"
${XML::XPathString} "count(child::*)" $0 $1
StrCpy $ccount_options_option $0
${For} $R4 1 $ccount_options_option
${If} $R4 == 1
${XML::FirstChildElement} "" $0 $1
DetailPrint "Element in Option=$0"
${XML::GetText} $0 $1
DetailPrint "Text in it=$0"
${Else}
${XML::NextSiblingElement} "" $0 $1
DetailPrint "Element in Option=$0"
${XML::GetText} $0 $1
DetailPrint "Text in it=$0"
${EndIf}
${Next}
${EndIf}
${Next}
${EndIf}
${XML::GotoPath} $llast_current_path $0 ;end of options for loops
${ElseIf} $0 == "exe_cmd"
${Else}
${XML::GetText} $0 $1
DetailPrint "Text in it=$0"
${EndIf}
; ${EndIf}
${Next}
${XML::GotoPath} "$ccurrent_path" $0
${Next}
Now I want the data to be stored into Array of structure not in simply array.......because the XML is dynamic and the size(tags) can be increased so I think to store data into array of structure(not alone array) will be better aproach.....
NSIS does not have native support for arrays but you can use one of the alternatives listed here.
At first you need to parse the data from XML with some XML plug-in (like this: http://nsis.sourceforge.net/XML_plug-in).
Then save your data in array with some http://nsis.sourceforge.net/Arrays_in_NSIS plug-in (nsArray plug-in is recommended).
Do you want to save whole tree in array? I suppose this is really tough task because there are many possibilities: do you want to save all elements or only non empty ones?
Or you simply want to read some values?
Please be more specific how the array should look like.
Edit: (Example)
Simply traverse your loaded tree in a loop and save data:
IntOp $R1 0 + 0 ; Set $R1 to zero at beginning
${While} End_Of_XML_Tree
; Fill $your_value with the data you want (element name, value or even whole node path)
nsArray::Set your_array /key=$R1 $your_value ; Save value to your_array at key = $R1
IntOp $R1 $R1 + 1 ; Increase $R1 (next key)
${EndWhile}
nsArray::Set adds value at key, replacing any existing value with that key.

Resources