这是一个很晚的答案,实际上我不知道这个老问题,并准备了一个答案
this
类似的一个例子是讨论如何处理带有特殊字符的文件名,因为资源管理器只引用包含空格的文件名。然后,在对那个问题的评论中,我看到了这个线索的参考,在那之后,而不是我的担保人,我意识到
jeb
已经把这件事讲得很清楚了,这是他所期望的。
因此,在没有任何进一步解释的情况下,我将以主要的焦点贡献我的解决方案,以涵盖文件名中更特殊的情况。
,;!^
并提供一种机制
猜测
如果批处理文件是否由资源管理器直接启动,那么在所有情况下都可以使用处理批处理文件参数的旧逻辑。
@echo off
setlocal DisableDelayedExpansion
if "%~1" EQU "/DontCheckDrapDrop" (
shift
) else (
call :IsDragDrop && (
call "%~f0" /DontCheckDrapDrop %%@*%%
exit
)
)
:: Process batch file arguments as you normally do
setlocal EnableDelayedExpansion
echo cmdcmdline=!cmdcmdline!
endlocal
echo,
echo %%*=%*
echo,
if defined @* echo @*=%@*%
echo,
echo %%1="%~1"
echo %%2="%~2"
echo %%3="%~3"
echo %%4="%~4"
echo %%5="%~5"
echo %%6="%~6"
echo %%7="%~7"
echo %%8="%~8"
echo %%9="%~9"
pause
exit /b
:: IsDragDrop routine
:: Checks if the batch file is directly lanched through Windows Explorer
:: then Processes batch file arguments which are passed by Drag'n'Drop,
:: rebuilds a safe variant of the arguments list suitable to be passed and processed
:: in a batch script and returns the processed args in the environment variable
:: that is specified by the caller or uses @* as default variable if non is specified.
:: ErrorLevel: 0 - If launched through explorer. 1 - Otherwise (Will not parse arguments)
:IsDragDrop [retVar=@*]
setlocal
set "Esc="
set "ParentDelayIsOff=!"
setlocal DisableDelayedExpansion
if "%~1"=="" (set "ret=@*") else set "ret=%~1"
set "Args="
set "qsub=?"
:: Used for emphasis purposes
set "SPACE= "
setlocal EnableDelayedExpansion
set "cmdline=!cmdcmdline!"
set ^"ExplorerCheck=!cmdline:%SystemRoot%\system32\cmd.exe /c ^""%~f0"=!^"
if "!cmdline!"=="!ExplorerCheck!" (
set ^"ExplorerCheck=!cmdline:"%SystemRoot%\system32\cmd.exe" /c ^""%~f0"=!^"
if "!cmdline!"=="!ExplorerCheck!" exit /b 1
)
set "ExplorerCheck="
set ^"cmdline=!cmdline:*"%~f0"=!^"
set "cmdline=!cmdline:~0,-1!"
if defined cmdline (
if not defined ParentDelayIsOff (
if "!cmdline!" NEQ "!cmdline:*!=!" set "Esc=1"
)
set ^"cmdline=!cmdline:"=%qsub%!"
)
(
endlocal & set "Esc=%Esc%"
for /F "tokens=*" %%A in ("%SPACE% %cmdline%") do (
set "cmdline=%%A"
)
)
if not defined cmdline endlocal & endlocal & set "%ret%=" & exit /b 0
:IsDragDrop.ParseArgs
if "%cmdline:~0,1%"=="%qsub%" (set "dlm=%qsub%") else set "dlm= "
:: Using '%%?' as FOR /F variable to not mess with the file names that contain '%'
for /F "delims=%dlm%" %%? in ("%cmdline%") do (
set ^"Args=%Args% "%%?"^"
setlocal EnableDelayedExpansion
set "cmdline=!cmdline:*%dlm: =%%%?%dlm: =%=!"
)
(
endlocal
for /F "tokens=*" %%A in ("%SPACE% %cmdline%") do (
set "cmdline=%%A"
)
)
if defined cmdline goto :IsDragDrop.ParseArgs
if defined Esc (
set ^"Args=%Args:^=^^%^"
)
if defined Esc (
set ^"Args=%Args:!=^!%^"
)
(
endlocal & endlocal
set ^"%ret%=%Args%^"
exit /b 0
)
将示例文件拖放到批处理文件中时的输出:
cmdcmdline=C:\Windows\system32\cmd.exe /c ""Q:\DragDrop\DragDrop.cmd" Q:\DragDrop\ab.txt "Q:\DragDrop\c d.txt" Q:\DragDrop\!ab!c.txt "Q:\DragDrop\a b.txt" Q:\DragDrop\a!b.txt Q:\DragDrop\a&b.txt Q:\DragDrop\a(b&^)).txt Q:\DragDrop\a,b;c!d&e^f!!.txt Q:\DragDrop\a;b.txt"
%*=/DontCheckDrapDrop "Q:\DragDrop\ab.txt" "Q:\DragDrop\c d.txt" "Q:\DragDrop\!ab!c.txt" "Q:\DragDrop\a b.txt" "Q:\DragDrop\a!b.txt" "Q:\DragDrop\a&b.txt" "Q:\DragDrop\a(b&^)).txt" "Q:\DragDrop\a,b;c!d&e^f!!.txt" "Q:\DragDrop\a;b.txt"
@*= "Q:\DragDrop\ab.txt" "Q:\DragDrop\c d.txt" "Q:\DragDrop\!ab!c.txt" "Q:\DragDrop\a b.txt" "Q:\DragDrop\a!b.txt" "Q:\DragDrop\a&b.txt" "Q:\DragDrop\a(b&^)).txt" "Q:\DragDrop\a,b;c!d&e^f!!.txt" "Q:\DragDrop\a;b.txt"
%1="Q:\DragDrop\ab.txt"
%2="Q:\DragDrop\c d.txt"
%3="Q:\DragDrop\!ab!c.txt"
%4="Q:\DragDrop\a b.txt"
%5="Q:\DragDrop\a!b.txt"
%6="Q:\DragDrop\a&b.txt"
%7="Q:\DragDrop\a(b&^)).txt"
%8="Q:\DragDrop\a,b;c!d&e^f!!.txt"
%9="Q:\DragDrop\a;b.txt"
在
:IsDragDrop
例行程序我特别尝试最小化关于命令行格式和参数之间间距的假设。Explorer启动的检测(猜测)基于此命令行签名
%SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments"
因此,很有可能欺骗代码,使其认为它是通过从资源管理器双击或通过拖放启动的,这不是问题,批处理文件将正常工作。
但是有了这个特殊的签名,就不可能以这种方式有意启动批处理文件:
%SystemRoot%\system32\cmd.exe /c ""FullPathToBatchFile" Arguments & SomeOtherCommand"
并期望
SomeOtherCommand
要执行,它将被合并到批处理文件参数中。