Automaticalli ignore error during NSIS installer and log the error message - dll

I have an installer written in NSIS, and in one of it's part it tries to install some fonts, which fails:
The code part looks like this:
SetOverwrite ifnewer
File ".\target\fonts\*.*"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow (TrueType)" "arialn.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Bold (TrueType)" "arialnb.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Bold Italic (TrueType)" "arialnbi.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Italic (TrueType)" "arialni.ttf"
GetTempFileName $R0
File /oname=$R0 ".\target\additions\fonts.dll"
Push "arialn.ttf"
CallInstDLL $R0 registerFont
Push "arialnb.ttf"
CallInstDLL $R0 registerFont
Push "arialnbi.ttf"
CallInstDLL $R0 registerFont
Push "arialni.ttf"
CallInstDLL $R0 registerFont
SetOverwrite on
DetailPrint "Fonts Installed"
This error message is not a big problem for me, so I can always ignore it.
I am wondering, how could I automatically ignore the error message popup for these font installation parts BUT log (DetailPrint) the error message?

That dialog is controlled by SetOverwrite but there is no way to get exactly what you want out of the box.
You need to ditch the File * command and instead handle each file manually.
If you don't care if the new file is older then you can use SetOverwrite try:
!include LogicLib.nsh
!macro TryExtractWithDetailPrint file
SetOverwrite try
ClearErrors
File "${file}"
${If} ${Errors}
DetailPrint 'Could not extract "${file}", ignoring error...'
${EndIf}
SetOverwrite lastused
!macroend
Section
SetOutPath $Fonts
!insertmacro TryExtractWithDetailPrint "c:\myfonts\font1.ttf"
!insertmacro TryExtractWithDetailPrint "c:\myfonts\font2.ttf"
SectionEnd
If you want to take the date stamps into account then you need to extract the new file to a temporary location and then decide if you need to try to overwrite by comparing the new and old files:
!macro Make64 high low result
System::Int64Op "${high}" << 32
IntFmt ${result} "%#x" "${low}" ; Must reformat as hex because we don't want negative numbers to be sign extended
System::Int64Op ${result} |
Pop ${result}
!macroend
!macro CompareFilesLastWrite oldfile newfile result
Push "${newfile}"
Push "${oldfile}"
Call CompareFilesLastWrite
Pop ${result}
!macroend
Function CompareFilesLastWrite
System::Store S
Pop $1 ; oldpath
Pop $2 ; newpath
GetFileTime $2 $R2 $R1
IntOp $R1 $R1 & 0xfc000000 ; Chop off the bottom because of FAT
GetFileTime $1 $2 $1
IntOp $1 $1 & 0xfc000000 ; Chop off the bottom because of FAT
!insertmacro Make64 $2 $1 $1 ; old
!insertmacro Make64 $R2 $R1 $2 ; new
System::Call 'KERNEL32::CompareFileTime(*lr1,*lr2)i.s'
System::Store L
FunctionEnd
!macro TryExtractIfNewer src dst
InitPluginsDir
Push $0
SetDateSave on ; Must be on for this to work
File "/oname=$PluginsDir\temp.tmp" "${src}"
!insertmacro CompareFilesLastWrite "${dst}" "$PluginsDir\temp.tmp" $0
${If} $0 < 0
SetOverwrite try
ClearErrors
File "/oname=${dst}" "${src}"
${If} ${Errors}
DetailPrint 'Could not extract "${dst}", ignoring error...'
${EndIf}
SetOverwrite lastused
${Else}
DetailPrint "Existing file is newer, skipping"
${EndIf}
Pop $0
!macroend
Section
!insertmacro TryExtractIfNewer "myfiles\myfont.ttf" "$fonts\myfont.ttf"
SectionEnd

Related

NSIS FileRead conditional override

I should please need your help as I am not a programmer (please have mercy with me).
I should need to add in an existing NSIS script a function that does the following:
Checks the presence of a value called 169.254.1.1 into a INI file named myfile.ini and placed in
c:\mydirectory
Should it find this value into myfile.ini it should not do anything else (i.e. let the script do the next steps).
Should it NOT find this value into myfile.ini it should override the file
with another one by silently copying it from c:\dummyfile\myfile.ini
and then let the script do the next steps.
I do not know how to tell NSIS to do this, may I please ask for your help?
Thanks in advance for your expertise.
Meleena.
If your file is an actual .INI file with [sections] then you can just use the INI functions:
Section "Prepare INI example"
InitPluginsDir
WriteIniStr "$PluginsDir\MyFile.ini" ServerInfo ServerAddress "169.254.1.1"
WriteIniStr "$PluginsDir\Dummy.ini" ServerInfo ServerAddress "127.0.0.1"
SectionEnd
!include LogicLib.nsh
Section
ReadIniStr $0 "$PluginsDir\MyFile.ini" ServerInfo ServerAddress
ReadIniStr $1 "$PluginsDir\MyFile.ini" ServerInfo ServerAddressBck
${If} $0 != "169.254.1.1"
${AndIf} $1 != "169.254.1.1"
CopyFiles /SILENT /FILESONLY "$PluginsDir\Dummy.ini" "$PluginsDir\MyFile.ini"
${EndIf}
SectionEnd
If you don't have a real .INI file, just a file with name=value pairs then you have to parse manually:
Section "Prepare fake INI example"
InitPluginsDir
FileOpen $0 "$PluginsDir\MyFile.ini" w
FileWrite $0 'Foo$\r$\n'
FileWrite $0 'Bar$\r$\n'
FileWrite $0 'ServerAddress=169.254.1.1$\r$\n'
FileWrite $0 'Baz$\r$\n'
FileClose $0
WriteIniStr "$PluginsDir\Dummy.ini" ServerInfo ServerAddress "127.0.0.1"
SectionEnd
!include LogicLib.nsh
Function TrimTrailingNewlinesAndSpaces
Exch $1
Push $2
again:
StrCpy $2 $1 "" -1
StrCmp $2 " " +3
StrCmp $2 "$\r" +2
StrCmp $2 "$\n" +1 +3
StrCpy $1 $1 -1
Goto again
Pop $2
Exch $1
FunctionEnd
Section
StrCpy $2 "" ; Have not found the magic line
ClearErrors
FileOpen $0 "$PluginsDir\MyFile.ini" r
loop:
FileRead $0 $1
IfErrors done
Push $1
Call TrimTrailingNewlinesAndSpaces
Pop $1
${If} $1 == "ServerAddress=169.254.1.1"
${OrIf} $1 == "ServerAddressBck=169.254.1.1"
StrCpy $2 1
${Else}
Goto loop
${EndIf}
done:
FileClose $0
${If} $2 = 0
CopyFiles /SILENT /FILESONLY "$PluginsDir\Dummy.ini" "$PluginsDir\MyFile.ini"
${EndIf}
SectionEnd

GAWK Print string to STDOUT with -i inplace option

I would like to run a GNU AWK script that is editing files in-place (e.g. with the -i inplace option) and have it print the filenames it is working on to STDOUT. Is there a way to do this? The following just adds the filename as the first line in the modified file, rather than printing the filename on the command line:
BEGINFILE {
print FILENAME
}
Here is a workaround; drop -i inplace from the command line (not an obligatory though, see -e/-f) and place following at the very beginning of your script. Before starting to process a file's content, this will disable inplace temporarily and print FILENAME. Then inplace's BEGINFILE rule will enable itself again.
BEGINFILE {
if (inplace::filename != "") {
inplace::end(inplace::filename, inplace::suffix)
inplace::filename = ""
}
print FILENAME
}
#include "inplace"
See how inplace is implemented for a better understanding.

NSIS User input page

So I have a user input page using the code below and the text is being encrypted
How can I write this to a file
thae now can I read this from a file into a variable to decrypted it.
Then I want to display the decrypted message on screen in a Message box, but the \n\n needs to be converted to $\n before displaying so it displays correctly.
Example I enter in: (Note Control Enter gives you next line)
Hello World
It's a great day
When it decrypted is shows :
Hello World\n\nIt's a great day
ini File
[Settings]
NumFields=2
Title="Activation Code"
State=0
[Field 1]
Type=Text
Left=8
Right=-10
Top=12
Bottom=-15
flags=MULTILINE|VSCROLL
[Field 2]
Type=GroupBox
Left=0
Right=-1
Top=0
Bottom=-10
Text="Please enter in your Activation Code"
Code:
!include MUI.nsh
!include LogicLib.nsh
Page custom SetCustom ValidateCustom
Section Dummy
SectionEnd
Function SetCustom
ReserveFile ".\test.ini"
!insertmacro MUI_INSTALLOPTIONS_EXTRACT ".\test.ini"
!insertmacro MUI_INSTALLOPTIONS_DISPLAY ".\test.ini"
FunctionEnd
Function ValidateCustom
!insertmacro MUI_INSTALLOPTIONS_READ $R1 ".\test.ini" "Field 1" "State"
${If} $R1 == ""
Abort # Go back to page.
${Else}
Var /GLOBAL textencryt
blowfish::encrypt $R1 "1234password"
StrCpy $textencryt $8
MessageBox MB_OK "Encrypted string is:$\n $textencryt"
blowfish::decrypt $8 "1234password"
StrCpy $textencryt $8
MessageBox MB_OK "Decrypted string is:$\n $textencryt"
${EndIf}
FunctionEnd
New code: (With issues)
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "test.ini" "Field 1" "State"
${If} $R1 == ""
Abort # Go back to page.
${Else}
Var /GLOBAL textencryt
blowfish::decrypt $R1 "1234password"
StrCpy $textencryt $8
MessageBox MB_OK "Decrypted string is:$\n $textencryt"
!insertmacro MUI_INSTALLOPTIONS_READ $8 "test.ini" "Field 1" "HWND"
System::Call 'USER32::SendMessage(i $8, i ${WM_GETTEXT}, i ${NSIS_MAX_STRLEN}, t.R1)'
MessageBox MB_OK $R1
The original message was
Example:
test user
code
12months
after being encrypted and I try and decrypt and looking at the results using
"MessageBox MB_OK "Decrypted string is:$\n $textencryt" returns the decrypted message with the \n\n in there. (Example: test user\n\ncode\n\12months) it should come out like:
Example:
test user
code
12months
You have two options.
You can use the INSTALLOPTIONS_READ_CONVERT helper function:
...
!insertmacro INSTALLOPTIONS_FUNCTION_READ_CONVERT
Function ValidateCustom
!insertmacro INSTALLOPTIONS_READ_CONVERT $R1 "test.ini" "Field 1" "State"
MessageBox MB_OK $R1
FunctionEnd
Or you can read the text directly from the control:
...
!include WinMessages.nsh
Function ValidateCustom
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "test.ini" "Field 1" "HWND"
System::Call 'USER32::SendMessage(i $R1, i ${WM_GETTEXT}, i ${NSIS_MAX_STRLEN}, t.R1)'
MessageBox MB_OK $R1
FunctionEnd

Does NSIS have eval functionality?

For example, is there a way to do something along these lines?
Eval "MessageBox MB_OK 'Hello, World!'"
This is obviously a useless example, but I feel that such functionality would be useful.
The NSIS compiler (MakeNSIS) parses text files and writes out binary instructions into the generated setup. The setup application itself can only execute the instructions known at compile time.
Most instructions accept variables as their parameters so you can get different behavior. Here is a rather pointless example of that:
Page InstFiles
Function MaybeShowMessageBox
IntCmp $0 0 skip
MessageBox MB_OK "$1"
skip:
FunctionEnd
Section
StrCpy $0 1 ; Display it
StrCpy $1 "Hello World"
Call MaybeShowMessageBox
StrCpy $1 "Goodbye World"
Call MaybeShowMessageBox
StrCpy $0 0 ; Don't display it
Call MaybeShowMessageBox
StrCpy $0 0
StrCpy $2 "$WinDir" 1 ; Get the first character
StrCmp $2 "C" "" skipWinDirMessage
StrCpy $0 1
skipWinDirMessage:
StrCpy $1 "$WinDir is on drive C"
Call MaybeShowMessageBox
SectionEnd
You would ordinarily never write code like that. IntFmt is as close to Eval as you are going to get but it only operates on numbers:
ShowInstDetails show
Section
StrCpy $1 42
IntFmt $0 "%d" $1
DetailPrint "$1 as a number: $0"
IntFmt $0 "%#.4x" $1
DetailPrint "$1 as a hex number with a >= 4 width: $0"
IntFmt $0 "%c" $1
DetailPrint "$1 as a character: $0"
SectionEnd

NSIS script to install an exe which requires a Registration Name and Key to be set

Problem: I need to write a nsi for doing a series of tasks including creating a folder, some IE settings changes, Firewall changes and Installing an exe. The exe to be installed is a licensed copy and requires a Registration Name and Key which I have.
Scenario: I need to perform the same steps after installing the exe in more than 50 computers and I want to make the process free of manual errors.
I successfully wrote all steps but still to find how to install the exe, which prompts me for a Registration Name and Key.
Thanks
lazywizar
Can you explain how do you plan to handle the registration name and key, will you need a server to validate the installation ?
Anyway you have to make a custom page and create custom forms in this page. Something like :
Page custom CreatePage QuitPage
Where CreatePage is a function that creates the page ui
Example:
;;In the variables section
var regname_hdl
var regkey_hdl
Var regname_inpt_hdl
var regkey_inpt_hdl
var RegName
var RegKey
Function CreatePage
GetDlgItem $0 $hwndParent 3
EnableWindow $0 0
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 10u "Say something to user"
Pop $Label
${NSD_CreateLabel} 20u 20u 20% 20u "Enter Registration Name "
Pop $regname_inpt_hdl
${NSD_CreateLabel} 20u 40u 20% 20u "Enter Registration Key "
Pop $regkey_inpt_hdl
${NSD_CreateText} 30% 20u 30% 10u ""
Pop $regname_hdl
${NSD_CreatePassword} 30% 40u 30% 10u ""
Pop $regkey_hdl
nsDialogs::Show
FunctionEnd
Function QuitPage
${NSD_GetText} $reg_hdl $2
${NSD_GetText} $key_hdl $3
Push $3
Push $2
Pop $RegName
Pop $RegKey
${If} '$2' == ""
messageBox MB_ICONEXCLAMATION "Reg name is empty !"
Abort
${ElseIf} '$3' == ""
messageBox MB_ICONEXCLAMATION "Reg key is empty !"
Abort
${Else}
System::Alloc 9
Pop $4
;; Here you have to call some procedure to check if reg name and key are valid
;; let's say the procedure returns 1 for true and 0 for false and it stores the result in $1
${If} $1 == 0
messageBox MB_ICONEXCLAMATION "Installation denied !"
Abort
${EndIf}
${EndIf}
MessageBox MB_OK "Installation allowed !"
SetPluginUnload manual
System::Free 0
FunctionEnd