Windows 拖动调用的vbscript中的当前工作目录&;下降操作
当我试图为我的批处理脚本获得更高的权限时,我发现了两个相关的SO问题Windows 拖动调用的vbscript中的当前工作目录&;下降操作,windows,batch-file,vbscript,drag-and-drop,working-directory,Windows,Batch File,Vbscript,Drag And Drop,Working Directory,当我试图为我的批处理脚本获得更高的权限时,我发现了两个相关的SO问题 …这导致了部分有效的答案。出于某种原因,我在命令行传递VBS脚本中包含空格的文件路径参数时遇到问题,因此我尝试将解决方案分为三部分,并将重点放在内部(VBS)步骤上,然后通过调用无法找到的VBS批处理来添加最后一步,尽管该批处理与VBS脚本位于同一文件夹中。我发现拖放并不“那么容易”,当使用.vbs而不是.bat或.exe作为拖放目标时,情况就不同了 这是我的实际问题: 如果我拖动一个文件并将其放到可执行文件(exe)
.vbs
而不是.bat
或.exe
作为拖放目标时,情况就不同了
这是我的实际问题:
如果我拖动一个文件并将其放到可执行文件(exe)或批处理文件(bat、cmd)上,则当前工作目录由拖动项的源决定。它的目录被设置为处理它的程序或脚本的工作目录
如果我把一个文件放到VBS脚本上,它就不同了。在Windows 8.1 x64上,我观察到它是C:\Windows\System32
,即使参数与VBS位于同一文件夹中
我可以像这样简单地使用批处理文件(作为拖放中继)
my.vbs %*
为了获得“正常的”.bat
行为(drop source指示CWD),但我也想了解它
它是一个bug还是一个特性?它在所有Windows版本上都是一致的吗
编辑:为问题添加了背景(在顶部),显示我是如何到达那里的(+轻微更正)
c:\windows\system32\CScript.exe
或c:\windows\system32\Wscript.exe
是运行vbscript的程序。如您所见,它们位于system32
中
Windows使用ShellExecuteEx启动程序-请参阅MSDN上的规则:ShellExecuteEx使用CreateProcess(CreateProcessEx)实际启动程序 编辑 CMD不会将注册表用于它自己的东西。这些注册表项用于CMD以外的程序 CMD的主要目标是兼容MS Dos 5,同时增强它,它将正确运行大多数Dos批处理文件。它是由在OS/2而不是Windows上工作的IBM工程师编写的 编辑2 问题的核心是,您试图编写程序,就好像您是一个用户在操作计算机一样 作为一名程序员,你不会做出假设。不采用假设的最简单方法是指定所需内容的完整路径。批处理文件不应该关心当前目录是什么。例如,在CMD中,每个驱动器都有一个与MSDos 5兼容的当前目录(控制台中的程序倾向于共享它们,但不一定要共享)。在Windows中,每个程序有一个当前目录。默认的当前目录已更改多年 只有在编写供用户使用的批处理文件时,才应使用当前目录。例如,如果您键入
dir
它会显示当前目录,则表示为常规命令的批处理文件应以相同的方式工作。该属性包含脚本上删除的所有项目的完整路径,因此您可以确定每个删除项目的目录,如下所示:
Set fso = CreateObject("Scripting.FileSystemObject")
For Each item In WScript.Arguments
WScript.Echo fso.GetParentFolderName(item)
Next
Set fso = CreateObject("Scripting.FileSystemObject")
Set sh = CreateObject("WScript.Shell")
For Each item In WScript.Arguments
sh.CurrentDirectory = fso.GetParentFolderName(item)
'working directory is now the parent folder of the current item
'...
Next
假设工作目录将由放在脚本上的内容定义是一种错误的方法。如果您需要该逻辑,您可以自己在脚本中实现,例如:
Set fso = CreateObject("Scripting.FileSystemObject")
For Each item In WScript.Arguments
WScript.Echo fso.GetParentFolderName(item)
Next
Set fso = CreateObject("Scripting.FileSystemObject")
Set sh = CreateObject("WScript.Shell")
For Each item In WScript.Arguments
sh.CurrentDirectory = fso.GetParentFolderName(item)
'working directory is now the parent folder of the current item
'...
Next
如果需要将工作目录作为VBScript文件的父目录,可以从以下属性派生:
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetParentFolderName(WScript.ScriptFullName)
如果我在Windows注册表中查找文件类型,我会在其
Shell\Open\Command
值中看到以下内容:
- batfile:
%1%*
- cmdfile:
%1%*
- exefile:
%1%*
- VBS文件:
%SystemRoot%\System32\WScript.exe“%1”%*
bat
、cmd
、exe
本身被视为可执行文件,可能是出于历史原因,而VBS被认为是一个普通的脚本,它只是可执行的,因为它的扩展名注册了一些可执行文件来调用以解释它。与Python或Perl非常相似
[Update]事实上,我证明了Python脚本显示的行为与我的VBS脚本完全相同:从提供参数的命令行调用它会保留CWD,在其上删除文件会导致CWD
C:\Windows\System32
。所以我的问题似乎有点错误,但最终它帮助人们为我指出了进一步研究的正确方向…在一些API监控之后,我看到了这一点
将文件放到.exe
文件上时,explorer.exe
使用API函数启动进程,将可执行文件作为lpApplicationName
传递,将可执行文件和删除的文件作为lpCommandLine
传递。调用方进程在函数调用中将lpCurrentDirectory
设置为包含删除文件[1]的文件夹
将文件放到.cmd
文件上时,explorer.exe
也使用API,但在这种情况下,lpApplicationName
为null
,lplCommandLine
包含批处理文件和删除的文件lpCurrentDirectory
也设置为删除文件[1]的父文件夹
当您将文件放到.vbs
文件上时,将使用该文件,并且结构的lpDirectory
字段为null
,因此,创建的进程将继承父进程的当前active directory。默认情况下,explorer.exe
进程的当前active directory是%systemroot%\system32
,但是可以使用不同的当前active directory启动explorer
实例