跳轉至內容

VBScript 程式設計

25% developed
來自華夏公益教科書,開放的書籍,為開放的世界

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 函式(返回整數)來了解變數內容的當前底層資料型別。

連結

字面量

[編輯 | 編輯原始碼]

各種資料型別字面量的示例

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

連結

輸入和輸出

[編輯 | 編輯原始碼]

對於使用者互動的輸入和輸出,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

連結

檔案操作

[編輯 | 編輯原始碼]

與 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 可靠地實現,因為這隻能在某些區域設定中工作,而不能在其他區域設定中工作。

連結

位元組陣列

[編輯 | 編輯原始碼]

位元組陣列與位元組的變體陣列形成對比。 在 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:語言參考

連結

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

連結

有多個內建常量,以 vb 開頭。例如,vbOKCancel 用於與 MsgBox 結合使用。

應用程式特定的常量(例如 Excel 的 xlAnd)不可用。

連結

剪貼簿

[編輯 | 編輯原始碼]

VBScript 不支援 VBA 的 MSForms.DataObject 來訪問剪貼簿。

有一些變通方法

  • 要寫入剪貼簿,您可以執行 Windows 7 中提供的 clip.exe。
  • 要從剪貼簿讀取,您可以透過 COM 訪問 Internet Explorer,並讓它從剪貼簿讀取。

連結

外部程序

[編輯 | 編輯原始碼]

您可以使用 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#命令輸出

連結

正則表示式

[編輯 | 編輯原始碼]

您可以使用 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 中,這是不必要的。

連結

在支援 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" 獲取編碼列表。

連結

保留關鍵字

[編輯 | 編輯原始碼]

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 將輸出指令碼主機版本。

連結

與 VBA 的比較

[編輯 | 編輯原始碼]

VBScript 中缺少而 VBA 中存在的功能

  • 對函式和方法使用命名引數傳遞
  • 應用程式特定的命名常量(例如 Excel 的 xlAnd)不可用;您必須自己設定它們或傳遞數字代替
  • 內建檔案 I/O;VBScript 可以使用 FileSystemObject
  • 透過 new Collection 建立自定義集合
  • 使用特定資料型別對變數進行維度化
  • 等等。

連結

限制

  • #與 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 仍在廣泛使用。

連結

COM 元件

[編輯 | 編輯原始碼]

在 WSH 中,經常將 COM 元件與 VBScript 配合使用。

  • WScript.Shell
  • WScript.Network
  • Scripting.FileSystemObject
  • Scripting.Dictionary
  • Shell.Application
  • Excel.Application
  • Word.Application
  • Outlook.Application
  • InternetExplorer.Application

連結

[編輯 | 編輯原始碼]
[編輯 | 編輯原始碼]
華夏公益教科書