VBScript 编程
VBScript,是 Visual Basic Scripting Edition 的简称,是微软提供的类似于 Visual Basic 和 Visual Basic for Applications 的脚本语言。 它可以通过 Windows Script Host (WSH) 作为 Windows 脚本语言使用。 此外,它可以作为网页中的客户端脚本语言代替 JavaScript 使用,但此类页面只能在 Internet Explorer 中使用。 此外,它可以作为 Active Server Pages (ASP) 的一部分用于服务器端网页脚本,以及在其他环境中使用。 本书重点介绍通过 WSH 使用该语言。
要与 WSH 一起使用的脚本通常是带有 .vbs 扩展名的纯文本文件。 默认情况下,Windows 将该扩展名与该语言的解释器关联,因此,在 Windows 批处理命令行中输入脚本名称会导致脚本执行,尽管不会等待脚本完成。 此外,脚本可以从桌面或 Windows 文件资源管理器运行,通常通过双击运行。
VBScript 可以访问通过 Microsoft COM 接口提供的对象,包括 Microsoft Office 的对象。 因此,Microsoft Office 不仅可以从嵌入在诸如电子表格之类的 Office 文件中的 Visual Basic for Applications (VBA) 中进行脚本化,还可以从 VBScript 脚本中进行脚本化,以语法相似但略有不同的方式进行。
有两个命令可用于让 WSH 执行脚本:wscript 和 cscript。 wscript 用于通过简单的弹出窗口进行交互,而 cscript 用于通过文本控制台进行命令行交互。 默认情况下,.vbs 扩展名与 wscript 相关联。
VBScript 在关键字和标识符方面大多不区分大小写。 因此,“End If” 等效于“end if”,而 “FSO.CreateTextFile( ...)” 等效于 “fso.createtextfile( ...”。
与 VBA 不同,变量不能被定义为仅限于特定数据类型的值,例如 String。 相反,它们都是 Variant 数据类型。
但是,每个变量仍然有一个底层数据类型,这取决于你分配给该变量的值。 你可以使用 TypeName 函数(返回字符串)和 VarType 函数(返回整数)来了解变量内容的当前底层数据类型。
链接
- VBScript 数据类型,Microsoft Docs
- TypeName,ss64.com
- VarType 函数,docs.microsoft.com
- VBScript 内置函数,ss64.com
各种数据类型字面量的示例
a = 3 'Integer: signed 16-bit integer
b = 2147483647 'Long: signed 32-bit integer
c = 3.5 'Double floating-point number
d = 1.7E-10 'Double floating-point number
e = &H7FFFFFFF 'Long; hexadecimal literal
f = &HFFFFFFFF 'Integer, whyever; value -1; arguably a bug or a trap
g = CLng("&HFFFFFFFF") 'Long -1
h = &H8000& 'Long via the final &; 32768
h = &HFFFFFFFF& 'Integer; the final & did not help make this Long; value -1; arguably a bug or a trap
i = &O666 'Integer; octal literal
i = &O177777 'Integer; -1
i = &O177777& 'Long via final &; 65535
i = &O37777777777 'Integer; -1; a bug or a trap
i = &O37777777777& 'Integer; -1; a bug or a trap
i = &666 'Integer; octal literal without O after &
j = "Hello" 'String
k = True 'Boolean; -1 when converted to an integer
l = #1-Jan-2020# 'Date
m = #Jan-2-2020# 'Date, month first
n = #1-2-2020# 'Date, month first: Jan 2, 2020
n = #2020-02-01# 'Date, ISO format
o = #Jan-2-2020 2:20:13 PM# 'Date, with time
p = #Jan-2-2020 14:20:13# 'Date, with time
不是字面量但具有相同用途的示例
a = CCur(922337203685477) + CCur(5807) / 10000 'Currency: 64-bit fixed-point real number with 4 decimal places
b = CCur(-922337203685477) - CCur(5808) / 10000 'Currency
c = CByte(255) 'Byte; unsigned 8-bit integer
'c = CByte(-1) 'Error
d = CLng(5) 'Long
e = CSng(1.5) 'Single precision floating point
f = Array(1, 2.5, "s", Array(3, 4)) 'Array
VBScript 通过 Scripting.Dictionary 对象支持字典,也称为关联数组。 键可以是除数组之外的任何类型; 因此,字符串、整数、浮点数、日期等都是支持的。
示例
Set Dict = CreateObject("Scripting.Dictionary")
Dict.Add "Key", "Value"
Value = Dict.Item("Key")
If Dict.Exists("Key") Then
WScript.Echo "Key exists"
End If
Dict.Remove "Key"
Dict.Add "DE", "Germany"
Dict.Add "USA", "United States"
Dict.Item("USA") = "The United States" 'Member rewrite
Keys = Dict.Keys 'An array, not a collection
For Idx = 0 To Dict.Count - 1 'For each key
WScript.Echo "Key " & Keys(Idx)
WScript.Echo "Value " & Dict.Item(Keys(Idx))
Next
链接
- Dictionary 对象,docs.microsoft.com
对于用户交互的输入和输出,Windows 脚本宿主中的 VBScript 提供了一个简单的弹出消息框和一个简单的弹出输入框,它们适用于通过 wscript(默认值)和 cscript 两种方式进行脚本调用。 文本控制台输入和输出在通过 wscript 运行的脚本中不受支持; 需要通过 cscript 运行。
通过 WScript 对象进行输入的示例,主要是通过文本控制台
WScript.Echo "Hello" 'Works both via wscript (makes a popup window)
'and cscript (outputs to a console).
WScript.Echo "Multiple items and types:", 4, 3.5, #1-Jan-2020#
' ^ The items separated by commas are output space-separated.
If InStr(1, WScript.FullName, "cscript", vbTextCompare) Then
' ^ Tests whether we are running via cscript, not wscript.
WScript.StdOut.Write "Enter an integer:" 'Only works via cscript, not wscript.
' ^ Outputs to text console. Writes no newline.
str = WScript.StdIn.ReadLine() 'User input from console
WScript.StdOut.WriteLine "Entered " & str 'Writes a newline.
WScript.StdErr.WriteLine "Test error message" 'Standard error stream is available.
Else
WScript.Echo "Not running via cscript. Some examples are skipped."
End If
通过弹出窗口进行输入和输出的示例,适用于 wscript 和 cscript
MsgBox "Hello"
MsgBox "Hello 2", 0, "Window Title"
str = InputBox("Enter an integer")
int1 = CInt(str) 'Converts string to int
MsgBox int1 + 1
有关从文本文件读取和写入文本文件的信息,请参阅 #文件操作。
获取命令行参数的示例
i1 = WScript.Arguments.Item(0)
i2 = WScript.Arguments.Item(1)
WScript.Echo CInt(i1) + CInt(i2)
获取环境变量的示例
Set Shell = CreateObject("WScript.Shell")
HomeDrive = Shell.ExpandEnvironmentStrings("%HOMEDRIVE%")
HomePath = Shell.ExpandEnvironmentStrings("%HOMEPATH%")
WScript.Echo HomeDrive & HomePath
链接
- .Echo,ss64.com
- StdOut.Write,ss64.com
- .StdOut.ReadLine ,ss64.com
- MsgBox,ss64.com
- InputBox,ss64.com
- 如何:有用的 WScript 属性列表,ss64.com
- 如何:VBScript 命令行参数,ss64.com
- .ExpandEnvironmentStrings,ss64.com
与 VBA 不同,文件操作不是语言内置核心的一部分,而是可以从 FileSystemObject 访问。
从文本文件读取
FileName = "MyFile.txt"
Set FSO = CreateObject("Scripting.FileSystemObject")
Set File = FSO.OpenTextFile(FileName)
While Not File.AtEndOfStream
Line = file.Readline() 'Line has no newline.
'Process Line
WScript.StdOut.WriteLine Line 'Works only via cscript
Wend
File.Close
写入文本文件
FileName = "MyFile.txt"
Set FSO = CreateObject("Scripting.FileSystemObject")
Set File = FSO.CreateTextFile(FileName, True)
File.Write "Hello, there." & vbCrLf
File.Close
MsgBox "File " & FileName & " written."
获取当前目录
Set FSO = CreateObject("Scripting.FileSystemObject")
CurrentDirectory = FSO.GetAbsolutePathName(".")
MsgBox CurrentDirectory
使用 ADODB.Stream 从二进制文件读取字节
Bytes = ReadBytes("MyFile.bin")
For Each Byte_ in Bytes
WScript.Echo Byte_
Next
Function ReadBytes(FileName)
'Read bytes into variant array of bytes
Dim OutBytes()
'SetLocale "ja" 'Uncomment to test locale independence
Set Stream = CreateObject("ADODB.Stream")
Stream.Open
Stream.Type = 1 'Binary mode
Stream.LoadFromFile FileName
ReDim OutBytes(Stream.Size - 1)
'Stream.Position = 10 'Skip first 10 bytes if you wish
J = 0
While Not Stream.EOS
Bytes = Stream.Read(1000) 'Read a block of up to 1000 bytes
'Bytes = Stream.Read() 'Or read them all: we would not need the while loop
'VarType(Bytes) = 8209 'Byte array, not variant array
For I = 0 To UBound(Bytes)
Byte_ = AscB(MidB(Bytes, I + 1, 1)) 'vartype(Byte_) = 17, which is Byte
OutBytes(J) = Byte_
J = J + 1
Next
Wend
Stream.Close
ReadBytes = OutBytes
End Function
使用 ADODB.Stream 将字节写入二进制文件
Set Stream = WScript.CreateObject("ADODB.Stream")
Stream.Type = 2 'Text mode
Stream.Charset = "iso-8859-1"
Stream.Open
'Write test bytes from 0 to 255
For I = 0 to 255
Stream.WriteText ChrW(I)
Next
Stream.SaveToFile "MyFile.bin", 2 '2=Overwrite file
Stream.Close
上面,诀窍是使用 iso-8859-1 以及 ChrW。 一个需要注意的是,iso-8859-1 没有定义控制代码,因此它们从 Unicode 到 iso-8859-1 的映射在形式上是未定义的,但在 ADODB.Stream 中选择了一个实现定义的映射,因此它无论如何都能正常工作。 以上不能通过将 Chr(num) 写入文本文件来使用 FileSystemObject 可靠地实现,因为这只能在某些区域设置中工作,而不能在其他区域设置中工作。
链接
- FileSystemObject,ss64.com
- FileSystemObject,Microsoft Docs
- Stream 对象 (ADO),docs.microsoft.com
- 二进制文件和文件系统对象不兼容,blogs.msdn.microsoft.com
- ISO-8859-1 是 Unicode 字符集吗?,stackoverflow.com
- ISO/IEC_8859-1,wikipedia.rog
字节数组与字节的变体数组形成对比。 在 VBScript 中,所有声明的数组都是变体数组,并且它没有直接和简单的方法来创建字节数组。 尽管如此,字节数组仍然可以创建,即使是以更冗长的方式,并且依赖于 ADODB.Stream。
填充字节数组,然后读取迭代它
'Populate byte array
Set Stream = CreateObject("ADODB.Stream")
Stream.Type = 2 'Text mode
Stream.Charset = "iso-8859-1"
Stream.Open
'Write test bytes from 0 to 255
For I = 0 to 255
Stream.WriteText ChrW(I)
Next
Stream.Position = 0
Set Stream2 = CreateObject("ADODB.Stream")
Stream2.Type = 1 'Binary mode
Stream2.Open
Stream.CopyTo Stream2
Stream2.Position = 0
ByteArray = Stream2.Read() 'VarType(ByteArray) = 8209 'Byte array, not variant array
Stream2.Close
Stream.Close
'Read-iterate byte array
For i = 0 To UBound(ByteArray)
Byte_ = AscB(MidB(ByteArray, i+1, 1))
WScript.Echo Byte_
Next
上面,填充字节数组使用的是将 Unicode 代码点写入 0-255 范围内的 iso-8859-1 编码的文本流,将文本流复制到二进制流,然后从二进制流读取字节。 读取迭代字节数组很简短,使用的是组合 MidB 和 AscB 的技巧,而不是数组索引访问。
算术运算符包括 +、-、*、/(真除法)、\(整数除法)、^(指数)和 mod(模运算)。 整数除法向零截断,就像在 C 语言中一样:-3 \ 2 = -1。 整数除法在执行除法之前将操作数转换为整数类型(对其进行舍入):3.6 \ 2 = 2(Long)。 模运算是在向零截断的整数除法后的余数,因此,-3 mod 2 = -1,就像 C 的 -3 % 2,而不是像 Python 的 -3 % 2 == 1。
比较运算符包括 =、<>、<、>、<=、>= 和 Is。
位运算符包括 And、Or、Xor、Not、Imp 和 Eqv。这些运算符在整数类型(Byte、Integer、Long)上作为位运算符操作。当对负整数进行操作时,它们的行为符合有符号整数的二进制补码内部表示。没有位移和位旋转运算符,但它们可以被模拟。
布尔逻辑运算符与位运算符相同。当对布尔值(包括布尔表达式)进行操作时,位运算符充当布尔逻辑运算符,没有短路计算,True 为 -1。因此,True and 14 产生 14,因为 -1 作为 Integer(16 位)为 0xFFFF。
数学函数包括 Abs、Atn、Cos、Exp、Fix、Int、Log、Randomize、Rnd、Round、Sgn、Sin、Sqr 和 Tan。
字符串连接运算符为 &(推荐)和 +(不推荐)。
在另一本维基教科书中,参见 Active Server Pages/附录 A:语言参考。
链接
- 运算符 (VBScript),docs.microsoft.com
- VBScript 功能,docs.microsoft.com
- 如何操作:VB 脚本运算符,ss64.com
- VBScript 内置函数,ss64.com
Excel 可以使用 VBScript 通过访问 Excel.Application 对象进行脚本化。与 VBA 不同,VBScript 不支持对方法使用命名参数传递,只支持位置参数传递。此外,从 VBA 中看起来是全局的函数在 Excel 中需要作为 Excel 对象的方法调用。此外,Excel 的特定常量,如 xlAnd,不可用;您需要自己定义常量或使用数字代替。
一个例子
Set FSO = CreateObject("Scripting.FileSystemObject")
CurrentDirectory = FSO.GetAbsolutePathName(".")
Set Excel = CreateObject("Excel.Application")
Set Workbook = Excel.Workbooks.Open(CurrentDirectory & "\" & "MyFile.xlsx")
Workbook.Sheets(1).Cells(1, 1).Value = "Hey"
Workbook.Save
Workbook.Close
链接
- Microsoft Excel 常量,Microsoft Docs
有多个内置常量,以 vb 开头。例如,vbOKCancel 用于与 MsgBox 结合使用。
应用程序特定的常量(例如 Excel 的 xlAnd)不可用。
链接
- VBScript 内置常量,ss64.com
- Microsoft Excel 常量,Microsoft Docs
- Microsoft Outlook 常量,Microsoft Docs
- Word 枚举常量,Microsoft Docs
VBScript 不支持 VBA 的 MSForms.DataObject 来访问剪贴板。
有一些变通方法
- 要写入剪贴板,您可以运行 Windows 7 中提供的 clip.exe。
- 要从剪贴板读取,您可以通过 COM 访问 Internet Explorer,并让它从剪贴板读取。
链接
- VBScript,将文本复制到剪贴板,以便粘贴到任何字段,stackoverflow.com
您可以使用 WScript.Shell 的 Run 方法运行外部进程
Set Shell = WScript.CreateObject ("WScript.Shell")
Shell.Run "tasklist /v", 0, True
您也可以使用 WScript.Shell 的 Exec 方法。
Set MyShell = CreateObject("WScript.Shell")
Set ExecObject = MyShell.Exec("tasklist /v")
' AllText = ExecObject.StdOut.ReadAll
Do While Not ExecObject.StdOut.AtEndOfStream
Line = ExecObject.StdOut.ReadLine()
If InStr(Line, "AcroRd32.exe") > 0 Then
'Do something
End If
Loop
关键字:外部命令,运行程序。
在另一本维基教科书中:Excel VBA#命令输出。
链接
- 运行程序 在 Microsoft Windows 2000 脚本指南中,TechNet 存档,Microsoft Docs
- .Run,ss64.com
- wscript.Shell + Shell.Application 对象,ss64.com
您可以使用 RexExp 对象使用正则表达式
Set RegExp = New RegExp
RegExp.Pattern = "[0-9][0-9]*"
If RegExp.Test("354647") Then
MsgBox "Test passed."
End If
或者,您可以通过 Set RegExp = CreateObject("VBScript.RegExp") 创建正则表达式对象,但在 VBScript 中,这是不必要的。
链接
- Microsoft 使用正则表达式增强 VBScript,docs.microsoft.com
- VBScript 的正则表达式支持,regular-expressions.info
在支持 Unicode 的平台上,VBScript 与 WSH 结合使用,对 16 位 Unicode 有以下支持
- 脚本源代码可以存储在 UTF-16 LE(小端)中,然后,字符串文字可以是 Unicode。变量名和过程名不能是 Unicode。UTF-16 BE(大端)和 UTF-8 不受支持。具有 BOM 的 UTF-8 脚本将无法运行。没有 BOM 的 UTF-8 脚本可能运行,但字符串文字中超过 127 的字符在通过 MsgBox 和其他接口输出时将被乱码。
- UCase 和 LCase 支持 Unicode,MsgBox 也支持。
- 可以通过将代码点编号传递给 ChrW 函数来输入 Unicode 字符。ChrW(127) = Chr(127),而 ChrW(128) <> Chr(128)。
- 可以通过 AscW 获取字符的 Unicode 代码点编号。
- FileSystemObject 方法 OpenTextFile 和 CreateTextFile 支持读取和写入 UTF-16 LE Unicode,方法是在可选参数中指示这样做。
- ADODB.Stream 对象支持将 Unicode 写入文件,并通过将 Stream.Charset 设置为 "utf-8" 从 UTF-8 文件中读取,以及以其他编码(如 "ascii" 或 "iso-8859-1")读取。您可以通过 cmd.exe 命令行从 "reg query HKEY_CLASSES_ROOT\MIME\Database\Charset" 获取编码列表,或通过 PowerShell 从 "dir Registry::HKEY_CLASSES_ROOT\MIME\Database\Charset" 获取编码列表。
链接
- Stream 对象 (ADO),docs.microsoft.com
- 将 UTF-8 文件转换为 Vbscript 中的 UTF-16 BE 文件,stackoverflow.com
- ActiveX 数据对象,wikipedia.org
- FileSystemObject,ss64.com
- FileSystemObject,Microsoft Docs
VBScript 具有预期的保留关键字,例如 Dim 或 While;这些关键字不能用作变量名。但是,它还有一些保留关键字来自 VBA,VBScript 语法没有使用,例如 Byte 和 Long。
VBScript 版本包括 5.1(Win 2000)、5.6(XP)、5.7(Vista)和 5.8(Win 7、Win 10)。
链接的 Microsoft 文档中每个版本添加的功能表显示 2000 年以后没有添加任何功能。
脚本主机版本应与脚本引擎版本区分开来。
要了解引擎版本和 Windows 脚本主机版本
VBScriptVersion = ScriptEngineMajorVersion & "." & ScriptEngineMinorVersion
WSHVersion = WScript.Version
WSHBuildVersion = WScript.BuildVersion
运行没有 //nologo 开关的 cscript 将输出脚本主机版本。
链接
- VBScript 版本信息,Microsoft Docs
- Windows 脚本主机#版本历史,wikipedia.org
VBScript 中缺少而 VBA 中存在的功能
- 对函数和方法使用命名参数传递
- 应用程序特定的命名常量(例如 Excel 的 xlAnd)不可用;您必须自己设置它们或传递数字代替
- 内置文件 I/O;VBScript 可以使用 FileSystemObject
- 通过 new Collection 创建自定义集合
- 使用特定数据类型对变量进行维度化
- 等等。
链接
- VBScript 中没有的 Visual Basic for Applications 功能,Microsoft Docs
- VBScript 是否允许在函数调用中使用命名参数?,stackoverflow.com
限制
- #与 VBA 的比较中描述的限制适用。特别是,无法创建自定义集合,因此不支持许多编程语言中已知的可轻松扩展列表;解决方法包括根据需要重新调整动态数组的大小或将索引存储为字典中的数字键。
- 一般来说,与基于 .NET 的 PowerShell 或 Python 相比,作为库提供的功能很少;相反,上面提到的两种脚本技术拥有非常多的库来支持各种任务。
- 没有交互式 shell 来逐个执行 VBS 命令,这与基于 .NET 的 PowerShell 或 Python 不同。
- 对于通过 wscript 运行的脚本,没有从控制台读取和写入,只有通过 cscript 运行的脚本。
- 对数组操作的支持有限,例如没有排序函数。用户只能编写自己的排序函数。
- 没有直接的方法将其他 .vbs 脚本作为库包含进来;间接方法是通过 WSF XML 文件。
- 没有按位左移和右移运算符,但可以轻松实现。
- 无法从 .vbs 脚本中进行一般的 GUI 编程;另一种方法是在 HTML 中将 VBS 嵌入为 HTML 应用程序 (HTA)。无需 HTA,可以直接支持简单的消息框和输入框。
- 没有任意精度的整数运算。
- 没有集合类型(数学集合)。
- 还有更多。
Windows 脚本宿主中的 VBScript 曾是 Windows 管理员的热门选择。截至 2022 年,它的使用早已减少,并被 PowerShell 远远超过。VBScript 引擎自 2001 年以来就没有进行过重大更新,微软已将 PowerShell 定位为 Windows 管理的首选脚本技术。经典 ASP 中的 VBScript 早已被 ASP.NET 中的 VB.NET 和 C# 超越。与 VBScript 不同,VBA 仍在广泛使用。
链接
- VBScript、PowerShell、Visual Basic for Applications、COBOL,trends.google.com
- VBScript、PowerShell、VBA、COBOL 在 Google Ngram Viewer 中,google.com
- vbscript、vba、powershell 在 Stack Overflow 趋势中,stackoverflow.com
- TIOBE 指数,tiobe.com
在 WSH 中,经常将 COM 组件与 VBScript 配合使用。
- WScript.Shell
- WScript.Network
- Scripting.FileSystemObject
- Scripting.Dictionary
- Shell.Application
- Excel.Application
- Word.Application
- Outlook.Application
- InternetExplorer.Application
链接
- Windows 脚本宿主对象模型,Microsoft Docs
- Active Server Pages
- Active Server Pages/附录 A:语言参考 -- 单页概述
- Visual Basic
- Excel VBA
- Visual Basic for Applications
- VBScript 语言参考,Microsoft Docs
- VBScript 语言参考,标识为 vs.85,docs.microsoft.com
- VBScript 功能,docs.microsoft.com -- 按类别分组的关键字索引
- WSH 简介,TechNet 档案,Microsoft Docs
- 编程中的奇妙冒险,一个博客,microsoft.com
- VBScript 命令,ss64.com
- VBScript 操作指南和示例,ss64.com
- VBScript,wikipedia.org
- Windows 脚本宿主,wikipedia.org
- 类别:VBScript,rosettacode.org
- JavaScript 和 VBScript 代码比较,harding.edu -- 单页备忘单