VBS字串的內部實現
語法系統管理
取得命令列參數
轉碼
VBS字串實字
VBS字串的內部實現
直譯器資訊

VBS 是基於微軟的 ActiveX/COM 技術實現的,而 COM 對象為了做到支持任何語言,定義了一系列通用的數據類型,微軟稱之為自動化對像類型(Automation data types),其中之一就是基本字串,簡稱 BSTR。

VBS 在內部是以 BSTR 來表示字串的,BSTR 在 WTypes.h 中定義如下碼:

typedef wchar_t WCHAR;
typedef WCHAR OLECHAR;
typedef OLECHAR *BSTR;

從定義可以看出,BSTR 是指向 wchar_t 類型的指針,但是 BSTR 並不是普通的 wchar_t 指針。wchar_t 是 C 的寬字元型別,寬字元指大於 1 位元組之字元資料,Windows API 中,wchar_t 是以 UTF-16 LE 編碼。BSTR 指向一個有長度前綴和 NUL 結束符的 wchar_t 陣列。BSTR 的前 4 位元組是一個表示字串長度之前綴,長度值是字串的位元組數,且不包括 NUL 結束符。如下碼:

str = "Hello" & Chr(0) & "world"

這句 VBS 程式碼初始化了一個 BSTR 變數:

BSTR str = SysAllocStringLen(L"Hello\0world", 11);

為了更清楚地了解 BSTR 的結構,我們換一種寫法:

/* BSTR 包含長度前綴,但是卻實際指向第一個字符*/

wchar_t arr[] = {22,0,'H','e','l','l','o','\0','w','o','r','l','d' ,'\0'};
BSTR str = &arr[2];

這個 BSTR 在記憶體中的結構為:

00000000 16 00 00 00 48 00 65 00 6C 00 6C 00 6F 00 00 00
00000010 77 00 6F 00 72 00 6C 00 64 00 00 00

前 4 個位元組是長度標首,第 5 至 8 位元組表示 BSTR 指針的當前指向位址 0 ,首行最未2字元表示字串中的Chr(0) 字符,次行最未2字元表表示BSTR 的結束字符NUL(該字符是SysAllocStringLen 函數加上去的,因為是Unicode,所以要佔 2 個位元組)。

若不考慮前面 4 個位元組,BSTR 就是 C 語言中的 null-terminated string。

VBS 字串在內部是以Unicode 的形式來保存的,然而在外部,VBS 腳本文件的編碼卻不一定是Unicode,本文主要探討一下VBS 文件編碼與Unicode的關係。

一般是用 ANSI 編碼來保存 VBS 腳本文件,但是 ANSI 編碼並不兼容某些 Unicode 字符,比如版權符號“c”。

常用的 Unicode 編碼方式有Unicode Little Endian、Unicode Big Endian 和 UTF-8,

而每種編碼方式又可以分為帶 BOM 和不帶 BOM,將下列程式碼:

MsgBox "Copyright c 2011 Demon"

分別保存為 Unicode Little Endian、Unicode Big Endian 和 UTF-8,帶 BOM 的和不帶 BOM 的,測試結果如下:

Unicode Little Endian With BOM	    Copyright c 2011 Demon
Unicode Little Endian Without BOM	Copyright c 2011 Demon
Unicode Big Endian With BOM	        Error: Invalid character
Unicode Big Endian Without BOM	    Error: Invalid character
UTF-8 With BOM	                    Error: Invalid character
UTF-8 Without BOM	                Copyright 漏 2011 Demon

由結果可知,只能保存為 Unicode Little Endian 編碼,帶不帶BOM 都可以。

為什麼保存為不帶 BOM 的 UTF-8 會顯示 “Copyright 漏2011 Demon”:不帶 BOM 的話 VBScript 引擎會按照 ANSI 編碼來解析 VBS 文件,“c”符號保存為UTF-8 後是 C2A9,正好對於 ANSI 中的“漏”,所以就出現了上面的結果。

當然,你也可以使用 Windows 腳本文件(*.wsf)來支持 UTF-8 編碼,或者在 ANSI 編碼中使用 ChrW 函數來獲取 Unicode 字符。

準確的說 ANSI 並不是一種編碼,ANSI 實際對應的編碼跟系統設置的程式碼頁有關,在簡體中文系統中程式碼頁默認是936,對應GB2312 編碼。在本文中 ANSI 代表 GB2312。