NSIS push, pop and URLEncode - nsis

I'm trying to encode with URLEncode a strings in NSIS. I'm using a NSIS plugin called URLEncode. The problem is that I try encode 2 vars, but the first encoded var lost the value after I encoded the second var.
Push "${AFF_NAME}"
Call URLEncode
Pop $3
;at this point the messagebox show the result good.
MessageBox MB_OK $3
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ProductName"
Push $0
Call URLEncode
Pop $0
;now after second var encoded the result of first var $3 lost the value
MessageBox MB_OK $3
Please Help I'm very new using NSIS and I dont know how do it good. I searching info but without success.
Very thanks !

I'm not aware of a URLEncode plug-in but there is a helper function on the NSIS wiki called URLEncode and it fails to preserve the registers.
You can fix it by modifying the start and end of the function so it looks like this:
; Start
Function URLEncode
System::Store S ; Save registers
Pop $0 ;param
...
Done:
Push $9
System::Store L ; Restore registers
FunctionEnd
; End

Related

How to use System::Call and MessageBox when calling the C++ dll method from the NSIS script

My requirement is I need to test "If the device is present before we try to disable the Native Power" from the system.
For that I need to call the below function that is there in testutil.dll
BOOL IsTherePower()
Below is the NSIS script to call this function:
Name "PowerTest"
OutFile "PowerTest.exe"
InstallDir $PROGRAMFILES\PowerTest
Section "PowerTest(required)"
SectionIn RO
DetailPrint "PowerTest"
; Set output path to the installation directory. Here is the path C:\Program Files\PowerTest
SetOutPath $INSTDIR
; Give the dll path
File E:\Code\Source\Validatepower.exe
File E:\Code\Source\testutil.dll
File E:\Code\Source\ntutil.dll
File E:\Code\Source\dlgdll.dll
System::Call "$INSTDIR\testutil.dll::IsTherePower() i.r0"
Pop $0
MessageBox MB_OK "Return value = $R0, lasterr = $0"
IntCmp $R0 1 OkToInstall CancelInstall
CancelInstall:
Abort "Not allowed to install"
OkToInstall:
Do the install
With the above code when i run the application i am getting "Return value=, lasterr = error". I am not sure why i am getting the "Return value" blank (null). Did I miss anything here?
I have written "System::Call" and "MessageBox" but not sure what they are doing.
Here I want to know what is "i.r0" from System::Call
And also what is "Pop $0"?
You are using the wrong register. r0 in System syntax is $0, not $R0 (R0 and r10 is $R0). System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0" puts the INT32 return value in $0 and then you overwrite $0 with the Pop and your stack happened to be empty.
If you need to call GetLastError() then you must append the ?e option:
System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0 ?e" ; Pushes error code on top of the stack
Pop $1 ; Get error code
DetailPrint "Return=$0 LastError=$1"
?e pushes the last error on the stack and Pop extracts the top item on the stack.
I can confirm that my code works, I tested in on a dummy .DLL. If it does not work for you then System::Call is unable to load the .DLL or find the exported function. The most likely issue is that you have not exported the function correctly in your .DLL.
Inspect your .DLL with Dependency Walker, it is supposed to look like this:
not
You can also try do verify it manually in NSIS:
!include LogicLib.nsh
Section
SetOutPath $InstDir
File drvutil.dll
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop $7
${If} $8 P<> 0
MessageBox MB_OK 'Successfully loaded "$InstDir\drvutil.dll" # $8'
System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
Pop $7
${If} $9 P<> 0
MessageBox MB_OK 'Successfully found "IsUPSPresent" # $9'
${Else}
MessageBox MB_ICONSTOP 'Unable to find "IsUPSPresent", error $7'
${EndIf}
System::Call 'KERNEL32::FreeLibrary(pr8)'
${Else}
MessageBox MB_ICONSTOP 'Unable to load "$InstDir\drvutil.dll", error $7'
${EndIf}

NSIS write to a file on APPDATA inside a subdir

I'm trying to append 1 line of text into a file on the $APPDATA folder which is inside of a folder that's generated randomly, so I don't know it's full path like:
C:\Users\MyUser\AppData\Roaming\MyApp\RANDOM_CRAP\config.json
While RANDOM_CRAP looks like some random string for a folder, like G4F6Hh3L.
What are my options here? Do I need to use either Search For a File or Search for a File or Directory (Alternative) ? It's a given that the only subfolder of MyApp folder is the RANDOM_CRAP folder, that contains the file I want to edit.
If there's no other way to access this file without searching for it, I've tried doing so but couldn't get this to work. (I'm very new to NSIS)
This is what I've tried (With the alternative approach):
Push "config.json"
Push "$APPDATA"
Push $0
GetFunctionAddress $0 "myCallback"
Exch $0
Push "1" ; include subfolders because my desired file is in the random folder
Push "0" ; no need the . option
Call SearchFile
Than I've copied the SearchFile code from this post and put a callback:
Function myCallback
Exch 3
Pop $R4
MessageBox MB_OK "Callback executing!"
MessageBox MB_OK "File is at : $R4"
FunctionEnd
I know that SearchFile is running (I've put a MessageBox inside) but myCallback isn't seemed to be called.
Many thanks.
If you are looking for a known file and only one directory in the path is unknown then you can probably just do a basic FindFirst search:
Section
; Create "random" folders:
CreateDirectory "$temp\MyApp\foo"
System::Call kernel32::GetTickCount()i.r1 ; random enough
CreateDirectory "$temp\MyApp\bar$1"
FileOpen $0 "$temp\MyApp\bar$1\config.json" a
FileWrite $0 '{bogus:"data"}$\n'
FileClose $0
CreateDirectory "$temp\MyApp\baz"
!include LogicLib.nsh
; Do the actual search:
StrCpy $9 "$temp\MyApp" ; The folder we are going to search in
FindFirst $0 $1 "$temp\MyApp\*"
loop:
StrCmp $1 "" done
${If} ${FileExists} "$9\$1\config.json"
DetailPrint "Found: $9\$1\config.json"
${EndIf}
FindNext $0 $1
Goto loop
done:
FindClose $0
SectionEnd

why need in Locate plugin find section the following line?

Section
${Locate} "C:\ftp" "/L=F /M=RPC DCOM.rar /S=1K" "Example1"
; 'RPC DCOM.rar' file in 'C:\ftp' with size 1 Kb or more
IfErrors 0 +2
MessageBox MB_OK "Error" IDOK +2
MessageBox MB_OK "$$R0=$R0"
SectionEnd
Function Example1
StrCpy $R0 $R9
; $R0="C:\ftp\files\RPC DCOM.rar"
MessageBox MB_YESNO '$R0$\n$\nFind next?' IDYES +2
** StrCpy $0 StopLocate ** -> why needs this line?
Push $0
FunctionEnd
Thx for the help!
${Locate} has a loop that looks for files that matches your input and when it finds one it calls your callback-function (Example1 in this case). It searches subdirectories by default so there could be more than one "RPC DCOM.rar" file.
If you only care about the first file then you can stop it from searching other subdirectories by pushing the string "StopLocate" to the stack. Pushing anything else will continue the search...

Find a string pattern in a file from an NSIS script

In an NSIS installer script, I'm trying to check if a given httpd.conf file contains the following line :
Include "c:\xxx\yyy.conf"
If so, then my installer script would not append it to the file, otherwise, it would append it.
I've come through {LineFind} but not sure this really makes what i'm trying to achieve.
What could be the simplest way to do a kind of "grep" on a text file from an NSIS script ?
Thank you !
Here is a sample for searching for a given line into a file, using the LogicLib for ease of syntax. The search is stopped as soon as the line is found. This sample works on the sample script itself:
# find.nsi : sample for LineFind from TextFunc.nsh
!include "textfunc.nsh"
!include "logiclib.nsh"
OutFile "find.exe"
!define lookfor `Section` ;will find
;!define lookfor `Sectionn` ;will not find
Var found
Section
StrCpy $found 0
${LineFind} "find.nsi" "/NUL" "1:-1" "GrepFunc"
${if} $found = 1
MessageBox MB_OK "string found"
${else}
MessageBox MB_OK "string NOT found"
${endIf}
SectionEnd
Function GrepFunc
${TrimNewLines} '$R9' $R9
DetailPrint "test for line $R8 `$R9`"
${if} $R9 == "${lookfor}"
StrCpy $found 1 ;set flag
Push "StopLineFind" ;stop find
${else}
Push 0 ;ignore -> continue
${endIf}
FunctionEnd

Reading a text file into a text box using nsdialog? NSIS

I am new to NSIS scripting installer. I need to create a TextBox with Multiline support, in Custom page. Need to read a text file and set the text content to TextBox. Please find my code block below:
StrCpy $3 ""
FileOpen $4 "C:\Users\Surya\Desktop\Installer\License.txt" r
loop:
FileRead $4 $1
StrCpy $3 "$3$1" ; append the line and copy it to another variable
IfErrors +1 loop
FileClose $4
${NSD_SetText} $ctrlTextBox "$3"
The above code able to read only 8119 characters only, but my file contains 30,000+ characters.
Please help me to read the large file and set the content to TextBox.
Thank You
You can fill a textbox with a little bit of text at the time (inside your loop) if you use EM_SETSEL (twice) to move the caret to the end and then use EM_REPLACESEL to append text.
If you can use a rich edit box instead then use some code I wrote a long time ago, you can find the forum thread here...
Edit:
As long as the textbox is empty when you begin you don't have to deal with the caret:
function custcreate
nsDialogs::Create 1018
Pop $0
nsDialogs::CreateControl ${__NSD_Text_CLASS} ${__NSD_Text_STYLE}|${ES_MULTILINE}|${WS_VSCROLL}|${ES_READONLY} ${__NSD_Text_EXSTYLE} 0 0 100% 50u ""
Pop $0
FileOpen $4 ${__FILE__}" r
loop:
FileRead $4 $1
SendMessage $0 ${EM_REPLACESEL} 0 "STR:$1"
IfErrors +1 loop
FileClose $4
nsDialogs::Show
functionend

Resources