2

I have a Windows .bat script which needs to be run from a NSIS installer at runtime.

The script is invoked as follows:

   ; Debug Messages to check values set correctly
   MessageBox MB_OK "Script ${INSTDIR}\script\settingsLocation.bat"
   MessageBox MB_OK "INSTDIR $INSTDIR "
   MessageBox MB_OK "SettingsDirType $SettingsDirType"
   MessageBox MB_OK "SettingsDirName $SettingsDirName"
   MessageBox MB_OK "Calling script ${INSTDIR}\script\settingsLocation.bat $INSTDIR $SettingsDirType $SettingsDirName"

   nsExec::ExecToStack 'CMD.exe /C ""${INSTDIR}\script\settingsLocation.bat"" ""${INSTDIR}"" $SettingsDirType $SettingsDirName'

   ; Check result status and output
   Pop $0
   MessageBox mb_ok "CMDout 0=$0"
   Pop $0
   MessageBox mb_ok "CMD Out 1=$0"

Using the above, the variable $INSTDIR is not expanded, so not surprising the command fails to find the script.

$INSDIR is "C:\Program Files (x86)\Prog Name" (three spaces).

But I use the following (replace the "" with "):

nsExec::ExecToStack 'CMD.exe /C "${INSTDIR}\script\settingsLocation.bat" "${INSTDIR}" $SettingsDirType $SettingsDirName'

I get :

'C:\Program' is not recognized as an internal command, operable program or batch file.

Clearly I'm falling between the 2 stools of non expansion and full expanion ignoring quotes.

How can I preserve the quotes such that the command would run as if it were typed manually as follows:

"C:\Program Files (x86)\Prog Name\script\settingsLocation.bat" "C:\Program Files (x86)\Prog Name" DTYPE DNAME

Update 1 (following Anders's reply):

I tried the following mod:

   nsExec::ExecToStack 'CMD.exe /C "$INSTDIR\script\settingsLocation.bat" "$INSTDIR" $SettingsDirType $SettingsDirName'

i.e change ${INSTDIR} to $INSTDIR

This gives :

'C:\Program' is not recognized as a internal or external command

Update 2

Tried escaping the inner double quotes as follows:

   nsExec::ExecToStack 'CMD.exe /C \"$INSTDIR\script\settingsLocation.bat\" \"$INSTDIR\" $SettingsDirType $SettingsDirName'

But this gave:

'\"C:\Program Files\....\" is not a recognised as an internal; or external command,

Update 3 (Resolved!!)

Following further help from Anders below, adding the if 1==1 bit finally got it working:

   nsExec::ExecToStack 'CMD.exe /C if 1==1 "$INSTDIR\script\settingsLocation.bat" "$INSTDIR" $SettingsDirType $SettingsDirName'
TenG
  • 3,843
  • 2
  • 25
  • 42

1 Answers1

3

Instdir is a variable, not a define, so you must use $InstDir, not ${InstDir}.

CMD.exe has crazy quote handling and will sometimes remove your quotes but there is a little workaround for that:

nsExec::ExecToStack 'CMD.exe /C if 1==1 "c:\path with spaces\app.exe" param1 "par am 2"'
Anders
  • 97,548
  • 12
  • 110
  • 164
  • Thanks. I changed to `nsExec::ExecToStack 'CMD.exe /C "$INSTDIR\script\settingsLocation.bat" "$INSTDIR" $SettingsDirType $SettingsDirName'` . But still get the `'C:\Program' is not recognised as a internal or external command`. – TenG Jun 23 '18 at 12:56
  • "'C:\Program' is not recognised as a internal or external command" is a quoting issue. – Anders Jun 23 '18 at 13:41
  • 2
    Thanks @Anders, `if 1==1` saved me. The quote handling of cmd.exe is insane. – Florian Sesser Sep 02 '19 at 16:31
  • Does anyone happen to know where this quotation behavior is documented? I think I understand it at a fairly high level that it forces literal interpretation of the quotes to prevent messing with the requirements of other commands that may be called from here (e.g. PowerShell). I'd feel more comfortable knowing exactly what this concept is called and why Windows Batch does this. – daniel.caspers Jan 22 '21 at 23:39
  • @daniel I think cmd.exe /? explains some of it. The if just makes it not start and end with a quote and that disables the insane behavior. – Anders Jan 23 '21 at 01:02