current working directory in a vbscript invoked by a drag & drop operation

ε祈祈猫儿з 提交于 2019-12-06 10:24:26

After some API monitoring, this is what I see

When you drop a file over a .exe file the explorer.exe uses CreateProcess API function to start the process, passing the executable as lpApplicationName, and the executable and dropped file as lpCommandLine. The lpCurrentDirectory is set in the function call by the caller process to the folder containing the dropped file[1].

When you drop a file over a .cmd file the explorer.exe also uses CreateProcess API, but in this case the lpApplicationName is null and the lplCommandLine contains the batch file and the dropped file. lpCurrentDirectory is also set to the parent folder of the dropped file[1].

When you drop a file over a .vbs file, ShellExecuteEx is used and the lpDirectory field of the SHELLEXECUTEINFO structure is null, so, the process created inherits the current active directory of the parent process. By default the current active directory of the explorer.exe process is %systemroot%\system32, but it is possible to start a explorer instance with a different current active directory that will be inherited in this kind of drop operations.

[1] If we drop more than one file, the path of the file passed as first argument is used

note just for information: to test the active directory inherit the process followed was:

  • Open a cmd instance and change the current active directory to c:\temp
  • Kill all explorer.exe instances
  • From the cmd instance call explorer.exe. This explorer instance has the active directory in the cmd window as its current active directory.

The Arguments property holds the full paths to all items dropped on the script, so you can determine the directory of each dropped item like this:

Set fso = CreateObject("Scripting.FileSystemObject")
For Each item In WScript.Arguments
  WScript.Echo fso.GetParentFolderName(item)
Next

Assuming that the working directory would be defined by what is dropped onto a script is a misguided approach. If you require that logic you can implement it in the script yourself, though, e.g. like this:

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

If you need the working directory to be the parent directory of the VBScript file you can derive that from the ScriptFullName property:

Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetParentFolderName(WScript.ScriptFullName)

If I lookup the file types in the Windows registry, I see the following in their Shell\Open\Command values:

  • batfile: "%1" %*
  • cmdfile: "%1" %*
  • exefile: "%1" %*
  • VBSFile: "%SystemRoot%\System32\WScript.exe" "%1" %*

This seems to suggest that bat, cmd, exe are treated as executable on their own, maybe for historical reasons, whereas VBS is considered an ordinary script, that is only executable because its extension is registered with some executable to be called to interpret it. Pretty much the same as Python or Perl.

[Update] Indeed I proved that a Python script shows exactly the same behaviour as my VBS script: calling it from the command line providing arguments keeps the CWD, dropping a file on it causes the CWD to be C:\Windows\System32. So my question seems to be sort of wrong, but finally it helped people to point me into the right direction for further research...

c:\windows\system32\CScript.exe or c:\windows\system32\Wscript.exe are the programs that run vbscript. As you can see they are in system32.

Windows uses ShellExecuteEx to start programs - see it's rules at MSDN:
ShellExecuteEx function (Windows)

ShellExecuteEx uses CreateProcess (CreateProcessEx) to actually start a program. CreateProcess function (Windows)

Edit

CMD doesn't use the registry for it's own stuff. Those registry entries are for programs other than CMD.

CMD main goal is to be MS Dos 5 compatible while enhancing it, it will correctly run most DOS batch files. It was written by IBM engineers working on OS/2 NOT Windows.

Edit 2

The core of your problem is that you are attempting to write programs as if you are a user typing to operate a computer.

As a programmer you don't make assumptions. The easiest way to not take assumptions is to specify full paths to what you want. Your batch file shouldn't care what the current directory is. EG In CMD there is a current directory per drive for compatibility with MSDos 5 (and programs in a console tend to share them but don't have to). In Windows there is one current directory per program. The default current directory has changed over the years.

The only time you should work with the current directory is if you are writing a batchfile for a user to use. EG If you type dir it does the current directory, a batchfile meant to be a general command should work the same way.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!