如果我的 VBScript 由批处理脚本而不是人打开,为什么它的功能会有所不同?

Why does my VBScript function differently if it is opened by a batch script rather than a person?

简单地说,我有一个名为“tyrian_soundtest.vbs”的 VBScript,它播放一个名为“tyrian_soundtest.mp3”的 .mp3 文件

VBScript 代码如下

Set Sound = CreateObject("WMPlayer.OCX.7")
Sound.URL = "tyrian_soundtest.mp3"
Sound.Controls.play
do while Sound.currentmedia.duration = 0
wscript.sleep 1
loop
wscript.sleep (int(Sound.currentmedia.duration)+1)*1000

打开后,播放 .mp3。够简单了。

当我 运行 一个名为“tyrian_soundtest.bat”的批处理脚本时,问题就来了。相对于它,.vbs 和 .mp3 位于名为 sfx 的文件夹中。这是该文件的一个迭代包含的内容。

@echo off
start %cd%\sfx\tyrian_soundtest.vbs
exit /b

结果是一个错误,指出 Windows 找不到文件路径,可能是因为它包含 space。 .bat 的其他尝试是用

替换第 2 行
start .\sfx\tyrian_soundtest.vbs

start "%cd%\sfx\tyrian_soundtest.vbs"

我所做的任何尝试都给出了三种结果之一。选项 1:没有错误,但音频根本无法播放。选项2:抛出文件目录未找到的错误。选项 3:该文件路径在新的 cmd window 中打开,但 .vbs 永远不会 运行.

有什么方法可以格式化 .bat 以将 .vbs 转换为 运行 而不会导致错误?

主要问题是在批处理文件和VB脚本文件中使用了当前目录路径。开始%SystemRoot%\System32\cmd.exe处理批处理文件的当前目录可以是任何目录。

Windows 资源管理器将批处理文件的目录设置为双击批处理文件时的当前目录,导致 cmd.exeexplorer.exe 处理双击的批处理文件在选项 /c 之后将哪个完整限定文件名作为附加参数传递给 cmd.exe。但是,如果批处理文件存储在使用 UNC 路径访问的网络资源上,Windows 命令处理器会将当前目录从网络资源更改为 %SystemRoot%(Windows 目录)并且批处理文件无法启动 Windows 脚本宿主来处理 VBS 文件。另见:CMD does not support UNC paths as current directories.

批处理文件也可以通过右键单击它并使用运行作为管理员来启动。这可能导致目录 %SystemRoot%\System32(Windows 系统目录)成为当前目录。另见:Why does 'Run as administrator' change (sometimes) batch file's current directory?

这只是当前目录与包含批处理文件的目录不同的许多示例中的两个。因此,如果批处理文件引用存储在与批处理文件本身相同的目录或批处理文件目录的子目录中的其他文件,建议使用批处理文件的完整路径而不是使用相对于当前目录的路径来引用这些文件.

示例:

使用过的文件存放在目录C:\Temp\Development & Test如下:

  • sfx
    • tyrian_soundtest.vbs
    • tyrian_soundtest.mp3
  • tyrian_soundtest.bat

用户打开 command prompt window,这通常会导致 %USERPROFILE%%HOMEDRIVE%%HOMEPATH% 引用的目录成为当前目录。用户在命令提示符下执行 window:

"C:\Temp\Development & Test\tyrian_soundtest.bat"

所以当前目录肯定不是批处理文件所在的目录

批处理文件可以如下编码来启动 Windows Script Host 来处理 VBS 文件 tyrian_soundtest.vbs 并成功播放 MP3 文件 tyrian_soundtest.mp3 .

@start "" /D "%~dp0sfx" %SystemRoot%\System32\wscript.exe //NoLogo "%~dp0sfx\tyrian_soundtest.vbs"

%~dp0引用参数0的驱动器和路径,即当前处理的批处理文件的完整路径。用 %~dp0 引用的批处理文件路径总是以反斜杠结尾。出于这个原因,%~dp0 与 file/folder 名称或通配符模式的串联应该始终不使用额外的反斜杠,因为这将导致两个 \ 串联在完整的参数字符串中,并且Windows 文件管理需要通过在将参数字符串传递到文件系统之前将 \ 替换为 \ 来修复这个小错误。另请参阅有关 Naming Files, Paths, and Namespaces 的 Microsoft 文档,其中解释了在将 file/folder 字符串传递到文件系统之前通常会对其应用哪些自动更正。

cmd.exe 的内部命令 START 将第一个双引号参数字符串解释为控制台 window 的标题字符串,如在 运行在命令提示符下 window start /? 并阅读输出帮助。因此,仅使用:

是不够的
@start "%~dp0sfx\tyrian_soundtest.vbs"

这将导致使用自己的控制台 window 启动另一个命令进程,并使用 VBS 文件的完整限定文件名作为控制台的标题 window。

默认情况下在 Windows 上处理 VBS 文件的 Windows 脚本宿主有两个版本:

  1. %SystemRoot%\System32\cscript.execonsole版本。
  2. %SystemRoot%\System32\wscript.exeWwindows GUI 版本。

如果 parent 进程本身不是控制台应用程序,则控制台版本 cscript.exe 的使用通常会导致 parent 进程打开控制台 window =206=]已经打开控制台 window 就像执行由 %SystemRoot%\System32\cmd.exe 处理的批处理文件一样也是控制台应用程序。

Windows GUI 版本 wscript.exe 的使用导致默认情况下根本不会打开 window。处理后的脚本文件必须包含打开 window 的命令(如果需要的话)。

也可以在 运行ning 从命令提示符 window cscript /? 和下一个 wscript /? 中看到差异。第一个命令导致在已打开的命令提示符 window 中打印 Windows Script Host 命令行选项的帮助,而第二个命令导致 window 通过 [=40= 显示图形] 显示相同的用法帮助。

Windows Script Host 的使用帮助还解释了每个用户如何定义 Windows Script Host 的哪个版本是执行脚本的默认版本。因此,不建议在命令行中使用 start 仅指定 VBS 文件名和完整路径,让 cmd.exe 在 Windows 注册表中查找哪个版本的 Windows 脚本宿主 运行 处理 VBS 文件。最好显式 运行 Windows Script Host mo 的版本不适合播放 MP3 文件,在这种情况下 Windows GUI 版本 wscript.exe 默认打开 没有 window 在后台播放 MP3 文件。

所以可以使用:

@start "" %SystemRoot%\System32\wscript.exe //NoLogo "%~dp0sfx\tyrian_soundtest.vbs"

有一个用 "" 定义的空标题字符串,因为启动的可执行文件 wscript.exe 是一个 Windows GUI 应用程序,它根本没有打开任何控制台 window cmd.exe。所以标题字符串并不重要,可以是空字符串。

但是该命令行还有一个问题。 VB 脚本引用没有路径的 MP3 文件,这意味着具有相对于当前目录的路径。当前目录是 %USERPROFILE% 而不是包含 MP3 文件 tyrian_soundtest.mp3C:\Temp\Development & Test\sfx。因此 VB 脚本将无法找到要播放的 MP3 文件。

有两种解决方案可以解决此问题:

  1. 批处理文件中如下命令行的用法:

     @start "" /D "%~dp0sfx" %SystemRoot%\System32\wscript.exe //NoLogo "%~dp0sfx\tyrian_soundtest.vbs"
    

    命令 START 的选项 /D 用于显式设置批处理文件目录的子目录 sfx 在相应的当前目录中启动cmd.exe 开始使用 Windows 内核库函数 CreateProcess with an appropriate created structure STARTUPINFO.

    的进程 wscript.exe
  2. VBS 文件引用 MP3 文件 tyrian_soundtest.mp3 及其完整路径,VB 脚本文件根据其自身的完整限定文件名确定自身。这可以在 VB 脚本文件 tyrian_soundtest.vbs 中通过在第二行中使用来实现:

    Sound.URL = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) + "\tyrian_soundtest.mp3"
    

最好同时使用这两种可能的解决方案,因为在这种情况下,VB 脚本文件也可以通过与 cmd.exe 处理批处理文件 tyrian_soundtest.bat 不同的进程执行,并且只要启动 wscript.exe 是 运行ning,就不可能删除目录 %~dp0sfx,因为此目录是 运行ning Windows 脚本宿主的当前目录。

所以批处理文件和 VB 脚本文件现在都独立于哪个目录是当前目录,因为它们都引用由脚本本身根据其完整限定文件名确定的完整路径的文件.