В функции перетаскивания Windows существует давняя ошибка, касающаяся путей к файлам, которые содержат &
или ^
, но не содержат <space>
.
Если путь к файлу содержитхотя бы один <space>
, тогда Windows автоматически заключает путь в кавычки, чтобы он был правильно проанализирован.Windows должна сделать то же самое, если путь к файлу содержит &
или ^
, но это не так.
Если вы создадите следующий простой пакетный файл и перетащите в него файлы, вы увидите проблему.
@echo off
setlocal enableDelayedExpansion
echo cmd=!cmdcmdline!
echo %%1="%~1"
pause
exit
! Cmdcmdline!переменная содержит фактическую команду, которая запустила командный файл.Пакетный файл печатает командную строку и первый параметр.
Если вы перетащите файл с именем "a.txt", вы получите
cmd=cmd /c ""C:\test\drag.bat" C:\test\a.txt"
%1=C:\test\a.txt
Press any key to continue . . .
Если вы проигнорируете кавычки вокругвсю команду вы видите, что вокруг аргумента файла нет кавычек.Здесь нет специальных символов, поэтому проблем нет.
Теперь перетащите «a b.txt», и вы получите
cmd=cmd /c ""C:\test\drag.bat" "C:\test\a b.txt""
%1="C:\test\a b.txt"
Press any key to continue . . .
. Вы можете увидеть, как Windows обнаруживает пространство вимя и заключает файл в кавычки.Опять нет проблем.
Теперь перетащите «a & b.txt», и вы получите
cmd=cmd /c ""C:\test\drag.bat" C:\test\a&b.txt"
%1=C:\test\a
Press any key to continue . . .
Windows не находит пробел в имени, поэтому он не заключает егов кавычках.Большая проблема!Windows передает «C: \ test \ a» в пакетный файл и рассматривает «b.txt» как второй файл, который будет выполнен после завершения пакетного файла.Жесткая команда EXIT в пакетном файле предотвращает выполнение любых разделенных имен файлов после пакета.Конечно, b.txt никогда не сможет выполнить.Но если бы файл назывался «a & b.bat» и «b.bat» существовал, это могло бы быть проблемой, если бы жесткого EXIT не было в командном файле.
Возможно перетащить несколько файлов накомандный файл, и каждый из них должен быть передан в качестве параметра.
! cmdcmdline!это единственный способ надежного доступа к аргументам перетаскивания.Но это не сработает, если файлы передаются как обычные аргументы при обычном обращении к пакетному файлу.
Ниже приведен пакетный файл, который может определить, был ли он вызван с помощью перетаскивания и обычного вызова.(Это не является пуленепробиваемым, но я думаю, что это должно работать в большинстве ситуаций). Он будет обрабатывать каждый аргумент файла, по одному за раз, независимо от типа вызова.(Процесс просто выводит имя файла, но вы можете заменить любую обработку, какую захотите.) Если пакет был вызван с помощью перетаскивания, он выполнит жесткий выход для защиты от разделения имен файлов.
@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 ------------------------------------------------
rem - Your file processing starts here.
rem - Each file will be processed one at a time
rem - The file path will be in %%F
rem -
echo Process file "%%~F"
rem -
rem - Your file processing ends here
rem -------------------------------------------------
)
::
:: If drag&drop then must do a hard exit to prevent unwanted execution
:: of any split drag&drop filename argument
if defined dragDrop (
pause
exit
)
Похоже, ваш существующий пакет предназначен только для обработки одного файла.Я не могу сказать, если вам нужно внести изменения в вызовы для поддержки нескольких файлов.Я изменил вышеупомянутый пакет, чтобы обработать только первый аргумент, и подставил ваш процесс в цикл обработки аргументов.Это не проверено, но я думаю, что оно должно работать для вас.
@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 ------------------------------------------------
rem - Your file processing starts here.
rem - Use %%F wherever you would normally use %1
rem
rem Change to drive and directory of input file
%%~dF
cd %%~pF
rem ffmpeg: mix to one channel, double the volume
%HOMEDRIVE%%HOMEPATH%\ffmpeg.exe -i "%%~nxF" -ac 1 -vol 1024 "%%~nF fixed%%~xF"
rem
rem - Your file processing ends here
rem -------------------------------------------------
goto :continue
)
:continue
if defined dragDrop (
pause
exit
)