共用方式為


嗨,Scripting Guy!搭乘特快車

Microsoft Scripting Guy

過去幾個月,有一位 Scripting Guy 在我們西雅圖地區經歷了新的體驗。那是一個目前在全美各城接受測試、名叫電子收費的程式。不過它在華盛頓州,稱為 Good to Go!(準備動身了!)。

它的運作方式如下:您付費取得一個裝在擋風玻璃上的電子裝置,並且開啟一個帳戶,在裡面匯入少許的錢。每當您通過高速公路其中一個監視裝置時,它就會從您的帳戶自動扣款。簡單說,就是不必停在收費站付費,就能夠在高速公路上開車 (高速公路 freeway 的 free 實在名不符實,應該改稱高速公路為 highway 了吧 ─ 不過有的路段最近都積了幾呎深的水,好像也不是那麼高速啦)。

目前有許多收費地區規定,只要多人共乘就不必付費。不過 Good to Go! 有意思的地方在於,它只用於共乘路段。這樣做有什麼意義呢?要努力找人共乘,還要付費,有誰願意做這種事呢?沒錯,的確沒人會做這種事。其實這個系統是向那些在共乘路段開車卻不共乘的人收費。想要在共乘路段開車,顯然是因為這條路段車子較少;有時候共乘路段甚至是車子動得了的唯一路段。

前面我們也提過,這個系統目前還在實驗階段,不過已有數千人為它聯名簽署了。西雅圖地區有很多人非常願意付錢搭乘這種特快車,飆到他們的目的地。

在本月份的專欄中,Scripting Guy 決定自己做一個小小的實驗。我們決定介紹一種名叫 Microsoft® Visual Basic® Express Edition 的特快車。先告訴您,這種特快車最棒的一點,就是它可以免費使用;無論您在哪裡使用這項資訊、有多少人使用,或者什麼時間使用,都不必付費。怎麼樣,不賴吧?當然嘍,您可能得意思意思付點代價,來學習一些新東西,不過這也是值得的。

在開始之前,我們要先提一下,我們知道介紹這些內容是有點越界。通常像 Visual Basic 和 Visual C#® 這類的 Visual Studio® 產品,應該是《MSDN® Magazine》而不是《TechNet Magazine》負責的範圍。不過,MSDN 和 TechNet 似乎越來越像一個溝通不良 — 啊,我是說,快樂的 — 大家庭,所以我們希望不必分得那麼清楚。另外,即使我們討論的主題在傳統上是被當作開發人員工具,但是討論的對象還是 Windows® 系統管理員。別走開,再聽個幾分鐘,您就會明白我們在說什麼了。

首先,您必須先安裝 Visual Basic。等等!先別說「我沒有!」或「我買不起!」這種話,Microsoft 已在 microsoft.com/express/download 提供精簡版的 Visual Basic,供您免費下載。

我們不打算詳細解說如何使用 Visual Basic Express。這些部分您可以參考 [說明] 中的教學課程,而且 [說明] 本身寫得還真不錯 (很難相信吧?) 我們要告訴您的是,如何使用 Visual Basic Express 來解決一個特殊的 Windows Vista® 問題 (不過這個例子也適用於舊版的 Windows),接下來您就可以自己動手試玩。下面就是我們要解決的問題:要如何開啟 Windows Vista 中的 [開啟舊檔] 對話方塊?

我們在幾年前曾經解說過如何從指令碼開啟 [開啟舊檔] 對話方塊 (請參閱 microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0128.mspx 的《如何向使用者顯示一個可讓他們選取檔案的對話方塊》(英文) 專欄。那篇文章早在 Windows Vista 問世前的 2005 年 1 月就出版了。解決的辦法是使用 UserAccounts.CommonDialog ActiveX® 控制項來開啟 [開啟舊檔] 對話方塊,讓您瀏覽您要開啟的檔案。不過,Windows Vista 已經移除這個控制項,換句話說,這個解決方案在新版系統是行不通的 (其實,根本就沒人問我們移除這個控制項是不是個好主意)。意思就是說,就我們所知,目前沒辦法用 VBScript 開啟 [開啟舊檔] 對話方塊。所以,我們打算使用 Visual Basic 而不是撰寫指令碼,來撰寫應用程式。而這個應用程式的其中一項功能就是開啟 [開啟舊檔] 對話方塊。

沒錯,接下來我們要示範的例子,是在 Visual Basic 建立一個完整的應用程式。這剛開始聽起來工程不免稍嫌浩大,不過接下來您就會見識到 Visual Basic Express 撰寫完整應用程式的本事,絕不會輸給指令碼。這個應用程式含有一個視窗 (或表單),您可以在裡面按其中一個按鈕,開啟 [開啟舊檔] 對話方塊,再從這個對話方塊選取文字檔,接著應用程式會從那些文字檔讀取文字,再從其中選取部分內容顯示在表單內。

好了,讓我們做做看吧。要開始,先開啟 Visual Basic Express。第一件事就是從 [檔案] 功能表選取 [新增專案],建立新專案。此舉會顯示 [新增專案] 對話方塊 (請注意,如果您所用的 Visual Basic Express 版本早於 2008,那麼您所看到的畫面會與我們在此提供的不太一樣)。我們要建立一個 Windows 表單應用程式,接著選取 Windows 表單應用程式範本,然後輸入您要的專案名稱。我們取名為 ReadFiles,如 [圖 1] 所示。

fig01.gif

[圖 1] 在 Visual Basic 建立一個新專案(按一下以放大影像)

專案第一次建立時,會自動提供新表單讓您使用。我們要建立的應用程式,會提供如 [圖 2] 所示的表單給使用者。 我們之前提過,這份表單包含一個按鈕,按一下這個按鈕,就會顯示 [開啟舊檔] 對話方塊,開啟到 C:\Scripts 資料夾。使用者可以從檔案系統的任何地方選取一或多個文字檔。接著應用程式就會讀取每一個所選文字檔的第一行,把結果顯示在表單的清單方塊中 (如果您覺得這個步驟聽起來很熟悉,那您一定參加過「2008 年指令碼比賽」的初學者組別:microsoft.com/technet/scriptcenter/funzone/games/games08/bevent3.mspx)。

fig02.gif

[圖 2] 提供給使用者的 ReadFiles 表單

要建立表單,必須將 [工具箱] 的控制項拖曳到專案表單上。根據預設,[工具箱] 是在 Visual Basic 視窗的左手邊開啟 (如果 [工具箱] 沒有開啟,請按一下 Visual Basic 工作區左手邊的 [工具箱] 按鈕,然後展開 [所有的 Windows 表單 (All Windows Form)])。請按一下 [工具箱] 的 [按鈕],然後將滑鼠拖曳到表單上面,以您要的大小建立按鈕。如果要在按鈕當中加入標籤,請按一下您剛剛加到表單中的按鈕,然後輸入您要的標籤 (您也可以編輯 [內容] 對話方塊中的 [文字] 內容,它預設位於 Visual Basic 工作區的右下角)。此處我們把按鈕的標籤設為 [瀏覽檔案]。接著請按一下 [清單方塊],再按一下表單,然後拖曳滑鼠來建立清單方塊。我們會使用這個清單方塊來顯示我們從文字檔讀取的字行。

建立表單要做的就是這些了。接下來好戲才要上場:我們希望在按一下按鈕之後,發生一些事情。開始先按兩下表單中的 [按鈕] 控制項,這會開啟程式碼編輯器,而且也幫您建好了一個新的副程式 (Button1_Click 副程式):

Private Sub Button1_Click _
  (ByVal sender As System.Object, _
   ByVal e As System.EventArgs) _
  Handles Button1.Click
End Sub

每當有人按一下表單中的這個按鈕時,就會執行這個副程式。如您所見,此時副程式還是空的;我們需要加入程式碼,告訴應用程式,當我們按了該按鈕時,它該做什麼。我們到底要做什麼呢?首先,要做的是我們在本專欄一開始所承諾的事:開啟 [開啟舊檔] 對話方塊。就像我們用 Visual Basic 做每一件事一樣,這一次我們要用 Microsoft .NET Framework 來進行。

我們先在副程式上面加入幾個 Imports 陳述式:

Imports System
Imports System.IO

這些陳述式會指定 .NET Framework 命名空間。我們要使用位於這些命名空間當中的類別,在此匯入它們,以便參照我們想要的類別。請注意,我們說過要把這些陳述式加在副程式上面。Imports 陳述式是全域通用,也就是說,它們不能放在副程式或函數當中,必須單獨留在外面。

在 VBScript 中,除非您把 Option Explicit 陳述式加在指令碼前面,否則不必明確宣告變數。但在 Visual Basic 中它會自動加入,所以您必須宣告所有的變數。我們需要一個變數來保留 OpenFileDialog 物件的參照 (該物件剛好代表 [開啟舊檔] 對話方塊):

Dim dlg As Windows.Forms.OpenFileDialog

宣告 (Dim-ed) OpenFileDialog 型別的變數之後,我們就可以為這個物件建立新的執行個體了,如下所示:

dlg = New OpenFileDialog()

但是,我們還沒有顯示這個對話方塊。首先,我們需要設定一些屬性:

dlg.Multiselect = True
dlg.InitialDirectory = "c:\scripts"
dlg.Filter = "txt files (*.txt)|*.txt|" & _
  "All files (*.*)|*.*"

Multiselect 屬性會指定使用者是否可以從 [開啟舊檔] 對話方塊選取一個以上的檔案。我們希望可以,所以把這個屬性設為 True,然後再把 InitialDirectory 屬性設為 C:\Scripts。如果不設定這個屬性,對話方塊就會開啟到主要電腦目錄。

最後 (而且肯定也很重要),我們再設定 Filter 屬性:

dlg.Filter = "txt files (*.txt)|*.txt|" & _
  "All files (*.*)|*.*"

我們要在這裡篩選對話方塊顯示給使用者看的檔案。我們只要顯示 .txt 檔。設定這些屬性會讓我們的 [開啟舊檔] 對話方塊如 [圖 3] 所示。

fig03.gif

[圖 3] 只顯示文字檔的 [開啟舊檔] 對話方塊 (按一下以放大影像)

接下來終於要顯示對話方塊了。這個步驟我們以 ShowDialog 方法來執行:

dlg.ShowDialog()

ShowDialog 方法會傳回一值,指出使用者是按了 [開啟舊檔] 來開啟所選的檔案,還是按了 [取消],關閉對話方塊。如果是按 [取消],我們就不必做任何動作。因此我們將 ShowDialog 的呼叫置於 If 陳述式當中,確保他們按了 [開啟舊檔] 之後再繼續進行:

If dlg.ShowDialog() = _
  Windows.Forms.DialogResult.OK Then

沒錯,我們勾選的是 OK 屬性,而不是 Open 屬性。[開啟舊檔] 按鈕在幕後其實跟 [確定] 按鈕一樣 — 只不過顯示 [開啟舊檔] 顯得更有意義。

接著我們必須知道使用者從對話方塊選了哪個 (或哪些) 檔案。檔名是包含在 OpenFileDialog 物件的 FileNames 屬性當中,因此我們設定 For Each 迴圈,一一讀過該屬性所含的檔名。

For Each strName In dlg.FileNames 

糟糕,忘了宣告 strName:

Dim strName As String

現在我們需要開啟每一個檔案,從這些檔案讀取。我們在 Visual Basic 所採取的方法是 Using 區塊:

Using sr As StreamReader = File.OpenText(strName)

VBScript 指令碼人員不會使用 Using 區塊,因為 VBScript 根本就沒有這個東西。Visual Basic 在管理系統資源方面,比起 VBScript 略勝一籌 (好吧,在許多方面其實都遠超過 VBScript 啦)。Using 陳述式最重要的工作是,在我們結束區塊時,確保系統資源皆已全部釋出。在本例中,我們只要確定別緊抓著檔案內容以及大型記憶體區塊不放就行了。

沒錯,聽起來好像有點複雜。不過,只要把它當作 Set 陳述式來看就行了。我們只要建立一個新物件 (在本例中是 StreamReader 物件) 的執行個體,然後把 File.OpenText 方法傳回的文字資料流指派給它。請注意,我們是把要開啟之檔案的名稱傳給 OpenText,這個檔案是來自目前正在重複執行的 FileNames 集合。

而 StreamReader 變數 sr 含有該檔案的內容。接下來需要另一個變數:

Dim strLine As String

這個變數是用來儲存剛剛開啟的檔案的第一行:

strLine = sr.ReadLine()

我們在 StreamReader 物件呼叫 ReadLine 方法,從檔案讀取第一行 (記住,StreamReader 物件含有我們檔案的內容),然後再把這行文字儲存到變數 strLine 當中。

接著,只要在 ListBox 物件呼叫 Add 方法,將這一行加到清單方塊就行了:

ListBox1.Items.Add(strLine)

以這個例子來說,我們只需要用到文字檔的第一行 (不需要整篇文字內容) 來關閉 StreamReader,然後再關閉 Using 區塊:

sr.Close()
End Using

接下來,再執行一次迴圈尋找從 [開啟舊檔] 對話方塊選出的下一個檔案,直到讀完所有選取的檔案,並且將所有的文字行加到清單方塊為止。完成的程式碼如 [圖 4] 所示。

[圖 4] 完整的 ReadFiles 程式碼

Imports System
Imports System.IO

Public Class Form1

  Private Sub Button1_Click _
   (ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
   Handles Button1.Click
    Dim dlg As Windows.Forms.OpenFileDialog
    Dim strName As String

    dlg = New OpenFileDialog()

    dlg.Multiselect = True
    dlg.InitialDirectory = "c:\scripts"
    dlg.Filter = "txt files (*.txt)|" & _
      "*.txt|All files (*.*)|*.*"

    If dlg.ShowDialog() = _
     Windows.Forms.DialogResult.OK Then
      For Each strName In dlg.FileNames
        Using sr As StreamReader = _
         File.OpenText(strName)
          Dim strLine As String
          strLine = sr.ReadLine()
          ListBox1.Items.Add(strLine)
          sr.Close()
        End Using
      Next
    End If
  End Sub
End Class

我們說得沒錯吧,建立應用程式,不比建立指令碼難多少。

您可以按 F5 (或者按 [偵錯] 工具列上的 [開始偵錯] 按鈕),來測試應用程式。當您按下該按鈕,然後在 [開啟舊檔] 對話方塊選取一或多個檔案之後,結果應該如 [圖 5] 所示。

fig05.gif

[圖 5]顯示在清單方塊中的選定檔案的第一行

如果應用程式按照您的意思順利執行時,請從 [建置] 功能表選取 [建置 ReadFiles (或是您的專案名稱)],建立一個名叫 ReadFiles.exe 的 .exe 檔,您可以像執行其他任何應用程式一樣來執行這個檔案,也可以把它發佈給您的使用者。

也許使用 [開啟舊檔] 對話方塊,不像搭特快車那麼快,不過當您想到從 Windows Vista 開始,就不能靠撰寫指令碼這麼做之後,撰寫簡單的應用程式也算是值得付出的小小代價啦。就像在高速公路上得付錢才能到目的地一樣:雖然有點麻煩,不過終究還是到得了您要去的地方。

使用 Visual Basic 還有一個優點,就是這個工具比 VBScript 更強大,而且還有一個好用的使用者介面,讓您建立應用程式起來更輕鬆;這就是它振奮人心的地方。系統管理員還會發現到 Visual Basic 能夠完成其他許多任務。

記住,改走一條新的收費路段,不必重新學習開車,只要習慣您前面的車子其實有在動就行了。同樣的,如果您懂 VBScript,那麼要改用 Visual Basic,也不必重頭學習全新的語言,只要習慣您能做的事情變多了就行了。

Dr. Scripto 的指令碼謎題 (Scripting Perplexer)

這個每月一次的挑戰不僅測試您的解謎功力,更要測試您的指令碼技巧。

2008 年 8 月:Scripting 字母表

在本月份的謎題中,您必須在藍色空格中插入 A 到 Z 的字母,來顯示一個與 Scripting 多少有點關聯的字。每個字母 (A 到 Z) 都只能用一次,而且這些字母不會按照字母順序顯示。插入的字母可以是該字的開頭、結尾,或是中間任何位置。比方說,在第一行插入字母 C,就得出 SCRIPT 這個字了:

fig08.gif

答案是:

Dr. Scripto 的指令碼謎題 (Scripting Perplexer)

答案是:Scripting 字母表,2008 年 8 月

C:\Users\v-kabirs\Desktop\August Technet\HeyScriptingGuy - 0808\layout\FIGURES\puzzle_answer.gif

Scripting Guy 為 Microsoft 做事,也就是受雇於 Microsoft。他們在不玩、不教或不看棒球 (或者其他各種活動) 的時候,就負責管理 TechNet 指令碼中心。請造訪他們的網站:www.scriptingguys.com

© 2008 Microsoft Corporation and CMP Media, LLC.著作權所有,並保留一切權利。未經許可,不得部分或全部重製。