NSIS: Despite preproccsor get warning unknown variable/constant "test" detected - nsis

I use only use some code if the Flag is set. So I got the warning
Variable "test" not referenced or never set, wasting memory!
so I use the preprocessor commands
!if ${Flag} == 1
Var test
!endif
But I still get a warning
unknown variable/constant "test" detected, ignoring (macro:_==:1)
So why do I still get a warning and how could I disable the warning:
Maybe I could use !pragma to disable the warning. But this works only for nsis3. What could I do at nsis2?

You most likely messed up your !if guards around $test.
!define Flag 1
!if ${Flag} == 1
Var test
!endif
will print Variable "test" not referenced or never set, wasting memory! if you never access $test in a Section/Function.
On the other hand
Section
${If} $test == "something"
${EndIf}
SectionEnd
will print unknown variable/constant "test" detected, ignoring (macro:_==:1) if the code does not do Var test first.
And finally
Var test
Section
${If} $test == "something"
${EndIf}
SectionEnd
will also print Variable "test" not referenced or never set, wasting memory! for some reason but the warning goes away if you actually assign something to $test somewhere in your code:
Var test
Function .onInit
StrCpy $test ""
FunctionEnd
Section
${If} $test == "something"
${EndIf}
SectionEnd

Related

How to fix "CreateDirectory: Relative paths not supported" when using a variable?

As a newbiew, I am still in the stage of experimenting and building little prototypes. The idea is to build a silent installer that has all settings in multiple sections of a .INI and the users calls the setup with parameter /config={NameOfSection}.
My current situation:
FooBar-install.ini
[PROD]
FOOHOME=c:\FooBar
FooBar.nsi
!include FileFunc.nsh
!include LogicLib.nsh
!insertmacro GetParameters
!insertmacro GetOptions
var /GLOBAL config
var /GLOBAL cmdLineParams
var /global REGAPPKEY
var /global FOOHOME
!define TheName "FooBar"
!define OutFileSuffix "-Install."
!define IniFile "$EXEDIR\${TheName}${OutFileSuffix}ini"
Name "${TheName} ${PRODUCT_VERSION}" ; bei 2 Kunden geht's auch kd-spezifisch ;)
OutFile ${TheName}${OutFileSuffix}exe
RequestExecutionLevel admin
Icon "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
UninstallIcon "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
Section "-aInstaller Section"
ReadINIStr $FOOHOME ${IniFile} $config "FOOHOME"
MessageBox MB_OK "ini=${IniFile} , config=$config, FOOHOME=$FOOHOME"
CreateDirectory "SFOOHOME"
SectionEnd
function .onInit
UserInfo::GetAccountType
pop $0
${If} $0 != "admin" ;Require admin rights on NT4+
MessageBox mb_iconstop "Administrator rights required!"
SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
${Else}
MessageBox MB_OK "onInit"
${EndIf}
; Get parameters
${GetParameters} $cmdLineParams
; /? param (help)
ClearErrors
${GetOptions} $cmdLineParams '/?' $R0
IfErrors +3 0
MessageBox MB_OK "Befehlszeilenparameter /config={{name}} verweist auf einen Abschnitt aus ${TheName}${OutFileSuffix}ini mit div. Parametern zur Steuerung des Setup"
Abort
Call parseParameters
Pop $R0
FunctionEnd
Function parseParameters
; /config
${GetOptions} $cmdLineParams '/config=' $R0
${If} ${Errors}
StrCpy $config "errPROD"
${Else}
StrCpy $config $R0
${Endif}
FunctionEnd
Problem
If I try to compile this, I get the msg
CreateDirectory: Relative paths not supported
Usage: CreateDirectory directory_name
Questions
I do not understand why this error comes up at compile time. When using a variable (especially in this situation where the variable depends on user-input), it does not seem to make sense to complain about the argument when it is not known.
How can I avoid this probolem?
A little puzzle that messes me up is the syntax to refer to variables.The statement MessageBox MB_OK "ini=${IniFile} , config=$config, FOOHOME=$FOOHOME" shows that. I found that I needed to enclose IniFile in {} in order to display its value (I commented out the CreateDir-line to compile the installer and check my assumptions). When do I have to use {}?
If you see any other "unusual" things in my little script, I'd be happy to know ;)
You have a typo, change CreateDirectory "SFOOHOME" to CreateDirectory "$FOOHOME"
You might want to read the documentation again to learn the basics; ${define}, $(langstring) and $variable.

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}

Deregistering a font with NSIS

When I try to uninstall a font like that...
Section "un.Uninstall"
StrCpy $FONT_DIR $FONTS
!insertmacro RemoveTTFFont "$FONTS\Vani.ttf"
!insertmacro RemoveTTFFont "$FONTS\Vanib.ttf"
SendMessage ${HWND_BROADCAST} ${WM_FONTCHANGE} 0 0 /TIMEOUT=5000
SectionEnd
I get the following error message:
Error in macro GetFileNameCall on macroline 2
Error in macro RemoveTTFFont on macroline 9
(...) aborting process
In other words, there's something wrong with the following section in the FontReg.nsh file:
!ifmacrondef GetFileNameCall
!macro GetFileNameCall _PATHSTRING _RESULT
Push `${_PATHSTRING}`
Call GetFileName
Pop ${_RESULT}
!macroend
!endif
!ifndef GetFileName
!define GetFileName `!insertmacro GetFileNameCall`
Function GetFileName
Exch $0
Push $1
Push $2
StrCpy $2 $0 1 -1
StrCmp $2 '\' 0 +3
StrCpy $0 $0 -1
goto -3
StrCpy $1 0
IntOp $1 $1 - 1
StrCpy $2 $0 1 $1
StrCmp $2 '' end
StrCmp $2 '\' 0 -3
IntOp $1 $1 + 1
StrCpy $0 $0 '' $1
end:
Pop $2
Pop $1
Exch $0
FunctionEnd
!endif
Can someone, if not tell me how to fix the bug, at least point me in the right direction?
It would be useful for the community as many have had this problem but no one has solved it yet, like here - http://forums.winamp.com/showthread.php?t=245701
I haven't received any answers unfortunately, but I must share the solution I came up with, since I saw that lots of people have had the same problem.
There is a bug in macros to remove fonts, namely "RemoveTTF", "RemoveTTFFont" and similiar sounding ones in the following files : FontReg.nsh, FontRegAdv.nsh. All of them use the same function called "GetFileNameCall" which causes the error. The problem with this function is that it sees "FontName" and "FontFileName" as the same item! As a matter of fact, font file name differs from font name. I solved the problem by copying the needed code from FontRegAdv.nsh and replacing FontFileName and FontName variables with the actual font file names and font names.

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

NSIS Function with more than 1 parameters

Can a NSIS Function have more than one parameter?
Why wont this code compile? If I cant have more than 1 param for a function what are my other options(disregarding using a macro)?
Compile error:
Function expects 1 parameters, got 4. Usage: Function function_name
Outfile "test.exe"
Caption ""
Name ""
# Compile Error Here: "Function expects 1 parameters, got 4. Usage: Function function_name"
Function MyFunction p1 p2 p3
DetailPrint "$p1, $p2, $p3"
FunctionEnd
Section
DetailPrint "Hello World"
SectionEnd
You have to pass parameters in registers and/or on the stack:
Function onstack
pop $0
detailprint $0
FunctionEnd
Function reg0
detailprint $0
FunctionEnd
Section
push "Hello"
call onstack
strcpy $0 "World"
call reg0
SectionEnd

Resources