這是阿貴在網路上不小心看到的文章, 詳細說明如何用 Visual Lisp 擷取 Windows Script Host 資訊的方法, 喜歡看原文的請連上面的網址; 看不懂英文, 請勉強看阿貴的翻譯版本 ( Part 1 ) :
Scripting Objects - Part 1 by Stig Madsen
http://www.afralisp.net/archive/lisp/script1.htm =======================================================
Windows Script Host (WSH) Windows提供了幾個腳本引擎JScript,VBScript和PERL,其中大部分是主要針對Web開發。 WSH本身提供了擷取各種管理對象和服務,如網絡驅動器,註冊表和印表機的連接。 我們只看 WSH 的一個特定的對象,並且只擷取了一些有限的信息。 隨時了解更多關於 WSH 和它能做什麼(尤其是 Shell 對象可能是有用的)。 腳本的另一部分是腳本運行時庫 ( Script Runtime Library ) , 這對於 Windows 中的任何腳本或正在運行的應用程序提供了一些有用的服務。 它包含 3 個主要物件,我們將使用其中一個通過 Visual Lisp 語言來檢索有關磁碟驅動器的信息。 該物件被稱為 FileSystemObject。 它提供了一種方式,不僅賦予信息,還提供了標準的文件操作擷取該文件系統。
AutoCAD 用 Visual Lisp 擷取外部物件的最困難的事情,是不使用 VLAX- 或 VLA- 功能。 如果你從來沒有讀過有關如何從 Visual Lisp 取得 Excel 的任何事情,你會知道使用類名是 “Excel.Application”? 或者說, 類型庫導入將是 “EXCEL9.OLB”?大概不會。
開啟 VBAIDE 是一個比較容易的作法,在 [ 工具 ] - > [ 參考 ] 找到參考,並檢查路徑。 (實際上,在 VBA 中對物件做任何事情是比較容易的,但不要告訴任何人)
對於像取得 WSH 或腳本運行時庫 ( Script Runtime Library ) 這樣簡單的事情,我們不會導入任何類型庫 ( type libraries ) - 它太亂了。 我們只需要動態創建物件,並使用通用的 VLAX-INVOKE-METHOD 和 VLAX-GET-PROPERTY 函數來取得它們。 要創建擺在首位的物件,我們將使用 VLAX-CREATE-OBJECT。
讓我們通過擷取 Windows 腳本宿主 ( Windows Script Host ) 來啟動它。 這只能運行在 Windows 98 或更高的作業系統版本,當然你正在運行的至少是 Windows NT 或 2000!
因為我們感興趣的是 WSH 物件的類名 ( The class name ) 是 “WScript.Network”。 因此,讓我們給一個變數到此物件:
(setq wscript (vlax-create-object "WScript.Network")) #<VLA-OBJECT IWshNetwork2 0018ed40>
Command: (vlax-dump-object wscript T) ; IWshNetwork2: Network Object ; No properties ; Methods supported: ; AddWindowsPrinterConnection (3) T
它說,該物件沒有屬性,這是不正確的。 其實,這裡有一個傳回 WshNetwork 物件的屬性。 (再次在 VBAIDE 使用物件瀏覽器可以顯示比 Visual Lisp 的這些東西要好得多): - ComputerName - UserDomain - UserName
該方法主要用於映射網路驅動器和連接到網路印表機。 隨意看看他們(只要在互聯網上搜尋 WshNetwork )。 在這裡,我們將簡單地抓取三個屬性信息內容。
(cond ((setq wscript (vlax-create-object "WScript.Network")) (setq pcname (vlax-get-property wscript "ComputerName") pcdom (vlax-get-property wscript "UserDomain") pcuser (vlax-get-property wscript "UserName")) )
讓我們嘗試取得 FileSystemObject ,看看我們可以用它來幹什麼。 用類名 “Scripting.FileSystemObject” 來取得它們
(setq fso (vlax-create-object "Scripting.FilesystemObject")) #<VLA-OBJECT IFileSystem3 0cf17148>
Visual Lisp 有一些模糊的理由不轉儲傳回 WshNetwork 對象的全部屬性/方法,從 FileSystemObject 獲取信息是沒有問題的:
Command: (vlax-dump-object fso T) ; IFileSystem3: FileSystemObject ; Property values: ; Drives (RO) = #<VLA-OBJECT IDriveCollection 0cf009c8> ; Methods supported: ; BuildPath (2) ; CopyFile (3) ; CopyFolder (3) ; CreateFolder (1) ; CreateTextFile (3) ; DeleteFile (2) ; DeleteFolder (2) ; DriveExists (1) ; FileExists (1) ; FolderExists (1) ; GetAbsolutePathName (1) ; GetBaseName (1) ; GetDrive (1) ; GetDriveName (1) ; GetExtensionName (1) ; GetFile (1) ; GetFileName (1) ; GetFileVersion (1) ; GetFolder (1) ; GetParentFolderName (1) ; GetSpecialFolder (1) ; GetStandardStream (2) ; GetTempName () ; MoveFile (2) ; MoveFolder (2) ; OpenTextFile (4) T
該物件僅包含一個屬性不是一個錯誤。該驅動器屬性是在持有連接到電腦的每一個磁碟驅動器的信息的集合物件。
以下是 FileSystemObject 指令和 visual lisp 內建的相同指令的對照:
(vlax-invoke-method fso 'CreateFolder "C:\\newdir") (vl-mkdir "C:\\newdir)
(vlax-invoke-method fso 'GetBaseName "C:\\autoexec.bat") (vl-filename-base "C:\\autoexec.bat")
(vlax-invoke-method fso 'CopyFile "C:\\somefile.txt" "C:\\somecopy.txt" :vlax-true) (vl-file-copy "C:\\somefile.txt" "C:\\somecopy.txt")
等等。當然,一些在 FileSystemObject 的方法不可用在 Visual Lisp 。
為了我們的目的,我們不會使用任何方法。我們將只有建立一個程序,以獲取有關連接到 PC 上的每個驅動器的信息。 為此,我們需要 Drives 集合:
(setq drives (vlax-get-property fso 'Drives)) #<VLA-OBJECT IDriveCollection 09529930>
(vlax-dump-object drives T) ; IDriveCollection: Drive Collection Interface ; Property values: ; Count (RO) = 12 ; Item (RO) = ...Indexed contents not shown... ; No methods T
作為一個集合物件,人們所期望的至少一個項目的方法。 但轉儲說,沒有方法。 相反的,我們可以使用 Item 屬性檢索每個驅動器:
(vlax-get-property drives 'Item "C:") #<VLA-OBJECT IDrive 0956a138>
那是什麼,你問。一個參數的屬性?是的,是簡答題(對於廣義的回答,請拿起一些Visual Basic)。 該參數是驅動器磁碟機代號,帶或不帶冒號,或驅動器的根文件夾(如 “C:\\” )。 但是,如果我們不知道連接的驅動器的所有磁碟機代號? 那麼,因為是一個集合,我們可以使用 VLAX-FOR:
(vlax-for n drives (princ (vlax-get-property n 'driveLetter)) (princ " ") ) A C D E F G H I O P Q R " "
哇賽!很酷的東西。 現在我們知道了 Drive 物件的至少一個特性,即通過 Drives 集合所持有的類型的物件。 讓我們來看看一個驅動物件的所有屬性和方法:
(setq myDrive (vlax-get-property drives 'Item "C:")) #<VLA-OBJECT IDrive 0956a138>
(vlax-dump-object myDrive T) ; IDrive: Drive Interface ; Property values: ; AvailableSpace (RO) = 2118037504 ; DriveLetter (RO) = "C" ; DriveType (RO) = 2 ; FileSystem (RO) = "NTFS" ; FreeSpace (RO) = 2118037504 ; IsReady (RO) = -1 ; Path (RO) = "C:" ; RootFolder (RO) = #<VLA-OBJECT IFolder 09558648> ; SerialNumber (RO) = -922880035 ; ShareName (RO) = "" ; TotalSize (RO) = 6.98326e+009 ; VolumeName = "" ; No methods T
好了,沒有方法(FileSystemObject 的方法實際上是足夠充足的操作文件,文件夾和驅動器),但也有大量的屬性。 只有一個屬性,它是可讀寫的 - 那就是通過 Windows 資源管理器可以自由設置的標籤 - 其他的都是只讀的。 雖然,有一個屬性,可以用來遍歷整個磁盤,因此可以在定制的文件操作對話框中使用,例如打開或保存。 這個屬性是 RootFolder 它可以訪問所有其他文件夾 - 從而文件 - 在磁碟上。 我們不會在意如何做到這一點,因為它是由本身的話題(周圍有很多網站可以顯示遞歸 filesearch 技術)。 但在有很多障礙要處理之前,我們可以建立一個例行,呈現所有的這個美好的信息在一個合適的方式。
正如你所熟悉了,使用的 ActiveX 的數據類型在 Visual Lisp 工作,是不那麼有吸引力。 用於磁碟驅動器顯示屬性需要被 “翻譯”,他們可以表現出來,也就是說,一個對話框之前,至少有三種數據類型。 它們是 variants, Boolean 和 enumerated values.
後者是真的沒有麻煩 - 他們只是返回的整數 - 但我們沒有辦法擷取的 ActiveX 常數(除非我們導入類型庫,他們可以定義), 所以我們必須發明一種方式來呈現他們在清晰的文字。 FileSystemObject 在許多網站都有解釋(做物件的公司不在少數),所以常數是不難得到的。 您也可以進入 VBA 中,連接到 Microsoft Scripting Runtime ,在物件瀏覽器中檢視範例。
0 = UnknownType 1 = Removable 2 = Fixed 3 = Remote 4 = CDRom 5 = RAMDisk
為了轉換 DriveType 屬性返回的整數,我們可以簡單地從列表中檢索 textstring(其中 n 是整數):
(nth n '("Unknown" "Removable" "Fixed" "Network drive" "CD-Rom" "RAM disk"))
另外,更多的問題類型,是由 AvailableSpace,FreeSpace 和 TotalSize 傳回的的變數值。嘗試擷取的屬性之一,看看它的回傳:
(setq free (vlax-get-property myDrive 'FreeSpace)) #<variant 3 2117771264>
好了,它不再是問題。類型 3 表明,它是一個 Long。我們只需使用 VLAX-VARIANT-VALUE 提取值:
(vlax-variant-value free) 2117771264
當然,它顯示在原始字節,可能不是一個好主意,通常用 1024 除它得到 KB 或 1024 的 3 次方除它得到 GB。 在 Visual Lisp , IsReady 的 Boolean 值傳回 :vlax-true 或 :vlax-false。 我們可以使用 VL-PRINC-TO-STRING 直接列印其值,但是這不是一個很好的方式來呈現它。
相反,我們可以使用一個非常簡單的“交互轉換”(其中 n 是 Boolean):
(cond ((= n :vlax-true) "Yes") ((= n :vlax-false) "No") )
幸運的是,文字串傳回的值為文字串,所以我們也就懶得對他們做任何事。