There is a long-standing error in the drag and drop function of Windows regarding file paths containing & or ^ but not containing <space> .
If the file path contains at least one <space> , then Windows automatically encloses the path in quotation marks so that it is parsed correctly. Windows should do the same if the file path contains & or ^ , but it doesnโt.
If you create the following simple batch file and drag and drop files onto it, you may see the problem.
@echo off setlocal enableDelayedExpansion echo cmd=!cmdcmdline! echo %%1="%~1" pause exit
The! cmdcmdline! the variable contains the actual command that launched the batch file. The batch file prints the command line and the first parameter.
If you drag a file named "a.txt", you will get
cmd=cmd /c ""C:\test\drag.bat" C:\test\a.txt" %1=C:\test\a.txt Press any key to continue . . .
If you ignore quotes around the entire command, you see that there are no quotes in the file argument. There are no special characters, so no problem.
Now drag "b.txt" and you get
cmd=cmd /c ""C:\test\drag.bat" "C:\test\a b.txt"" %1="C:\test\a b.txt" Press any key to continue . . .
You can see how Windows detects a space in the name and encloses the file in quotation marks. Again no problem.
Now drag "a & b.txt" and you will get
cmd=cmd /c ""C:\test\drag.bat" C:\test\a&b.txt" %1=C:\test\a Press any key to continue . . .
Windows does not find a space in the name, so it does not enclose it in quotation marks. A big problem! Windows passes "C: \ test \ a" to the batch file and treats "b.txt" as the second file that will be executed after the batch file completes. The hard EXIT command in the batch file prevents any split file names from being executed after the batch. Of course, b.txt will never be able to execute. But if the file was named "a & b.bat" and "b.bat", then this can be a problem if the hard EXIT was not in the batch file.
You can drag and drop multiple files into a batch file, and each of them should be passed as a parameter.
The! cmdcmdline! is the only way to reliably access drag and drop arguments. But this will not work if the files are transferred as normal arguments during a normal call to a batch file.
The following is a batch file that can determine if it was called using drag and drop compared to a regular call. (This is not bulletproof, but I think it should work in most situations). It will process each file argument, one at a time, regardless of the type of call. (The process simply renames the file name, but you can replace any necessary processing.) If the package is called using drag and drop, then it will make a hard exit to protect against split file names.
@echo off setlocal disableDelayedExpansion :: :: first assume normal call, get args from %* set args=%* set "dragDrop=" :: :: Now check if drag&drop situation by looking for %0 in !cmdcmdline! :: if found then set drag&drop flag and get args from !cmdcmdline! setlocal enableDelayedExpansion set "cmd=!cmdcmdline!" set "cmd2=!cmd:*%~f0=!" if "!cmd2!" neq "!cmd!" ( set dragDrop=1 set "args=!cmd2:~0,-1! " set "args=!args:* =!" ) :: :: Process the args for %%F in (!args!) do ( if "!!"=="" endlocal & set "dragDrop=%dragDrop%" rem
It looks like your existing batch is only for processing a single file. I canโt say if you need to make changes to calls to support multiple files. I modified the above batch to handle only the first argument, and replaced your process with an argument processing loop. This is not tested, but I think it should work for you.
@echo off setlocal disableDelayedExpansion :: :: first assume normal call, get args from %* set args=%* set "dragDrop=" :: :: Now check if drag&drop situation by looking for %0 in !cmdcmdline! :: if found then set drag&drop flag and get args from !cmdcmdline! setlocal enableDelayedExpansion set "cmd=!cmdcmdline!" set "cmd2=!cmd:*%~f0=!" if "!cmd2!" neq "!cmd!" ( set dragDrop=1 set "args=!cmd2:~0,-1! " set "args=!args:* =!" ) :: :: Process the first argument only for %%F in (!args!) do ( if "!!"=="" endlocal & set "dragDrop=%dragDrop%" rem