Detect if bat file is running via double click or from cmd window

Less code, more robust:

Build upon the other answers, I find the most robust approach to:

  1. Replace quotes with x to enable text comparison without breaking the IF statement.
  2. Recreate the expected cmdcmdline exactly (well, with '"' replaced by x).
  3. Test for case-insensitive equality.

The result is:

set "dclickcmdx=%comspec% /c xx%~0x x"
set "actualcmdx=%cmdcmdline:"=x%"

set isdoubleclicked=0
if /I "%dclickcmdx%" EQU "%actualcmdx%" (
    set isdoubleclicked=1
)

This adds more robustness against general cmd /c calls, since Explorer adds an awkward extra space before the last quote/x (in our favor). If cmdcmdline isn't found, it correctly renders isdoubleclicked=0.

Addendum:

Similarly to the above method, the following one-liner will pause a script if it was double-clicked from explorer. I add it to the end of my scripts to keep the command-line window open:

(Edit 2022-01-12, fixed quote mismatching from this discussion)

if /i "%comspec% /c ``%~0` `" equ "%cmdcmdline:"=`%" pause
if /i "%comspec% /c %~0 " equ "%cmdcmdline:"=%" pause

%cmdcmdline% gives the exact command line used to start the current Cmd.exe.

  • When launched from a command console, this var is "%SystemRoot%\system32\cmd.exe".
  • When launched from explorer this var is cmd /c ""{full_path_to_the_bat_file}" ";
    this implicates that you might also check the %0 variable in your bat file, for in this case it is always the full path to the bat file, and always enclosed in double quotes.

Personally, I would go for the %cmdcmdline% approach (not %O), but be aware that both start commands can be overridden in the registry…


mousio's solution is nice but I did not manage to make it work in an "IF" statement because of the double quotes in the value of %cmdcmdline% (with or without double quotes around %cmdcmdline%).

In constrast, the solution using %0 works fine. I used the following block statement and it works like a charm:

IF %0 == "%~0"  pause

The following solution, which expands %~0 to a fully qualified path, might also work if the previous does not (cf. Alex Essilfie's comment):

IF %0 EQU "%~dpnx0" PAUSE

However, note that this solution with %~dpnx0 fails when

  1. the .bat file is located somewhere in the %USERPROFILE% directory, and
  2. your %USERNAME% contains one or more uppercase characters

because... wait for it... the d in %~dpnx0 forces your %USERPROFILE% username to lowercase, while plain %0 does not. So they're never equal if your username contains an uppercase character. ¯\_(ツ)_/¯

[Edit 18 June 2021 - thanks to JasonXA]

You can solve this lowercase issue with case-insensitive comparison (magic /I):

IF /I %0 EQU "%~dpnx0" PAUSE

This might be the best solution of all!


A consolidated answer, derived from much of the information found on this page:

:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
  1. The variable "testl" gets the full line of the cmd processor call (as per mousio), stripping out all of the pesky double quotes.
  2. The variable "testr" takes "testl" and further strips outs the name of the current batch file name if present (which it will be if the batch file was invoked with a double-click).
  3. The if statement sees if "testl" and "testr" are different. If yes, batch was double-clicked, so pause; if no, batch was typed in on command line, go on.

Naturally, if you want to do something else if you detect a double-click, you can change the pause.

Thanks everyone.

Tags:

Windows

Cmd