7. Internet元件的應用

 

對不同的人而言,Internet應用程式代表著不同的意義。從商業軟體的角度來看,它可能代表在Web上的主從式工具;對銷售及行銷人員而言,它可能是一個可以從網頁上接受顧客訂單的系統;而對人力資源管理人員而言,它可能是一套可以從Internet上面即時更新的員工手冊出版系統。

因為這個主題具備著多樣性,我們特別把Internet程式設計分成三章予以詳細討論。本章的重點在於討論如何使用Visual Basic的Active X控制項來處理Internet相關的程式需求,包括低階的網路協定通訊以及建立自己的網頁瀏覽器。 第八章"建立Internet元件" 告訴你如何以Visual Basic提供的表單收納器在Internet上散佈資訊,同時也討論如何建立在Internet上使用的Active X控制項和Web物件類別。 第九章"建立Internet應用程式" 將綜合第七章及第八章所介紹的知識,建立三個Internet應用程式。

如何使用Internet控制項?
 

Visual Basic專業版和企業版包含了三種ActiveX控制項,這三種控制項提供了不同層次的Internet通訊功能。

  • WinSock控制項(MSWINSCK.OCX)提供了低階的Transfer Control Protocol (TCP)和User Datagram Protocol (UDP)兩種在Internet上面應用的網路通訊協定。使用WinSock控制項的交談型應用程式,可以在多部電腦之間直接進行資料交換。
     
  • InternetTransfer控制項(MSINET.OCX)讓你能從HTTP(Hypertext Transfer Protocol)或FTP (File Transfer Protocol)伺服器上複製檔案到自己的機器上,而且也可以讓你瀏覽檔案的目錄,以及以同步或非同步的模式來讀取資料。這個控制項可以用來發展具有FTP瀏覽功能和檔案傳輸功能的應用程式。
     
  • WebBrowser控制項(SHDOCVW.DLL)把所有Microsoft Internet Explorer (IE)的功能全部包裝在一個控制項裡,你可以用這個控制項在某個應用程式裡加入一個Internet瀏覽器,或者可以在某個應用程式裡透過WebBrowser控制項來控制Internet Explorer。
     

注意:

WebBrowser控制項在「設定使用元件」對話方塊中被稱為Microsoft Internet Controls,在安裝Internet Explorer時它就會被自動地安裝到你的電腦裡。


以下各節介紹各種不同層次的Internet資料傳輸並且以實例介紹如何使用這些控制項。

Internet網路協定如何運作?
 

Internet是一個允許多個(數目正持續增加中)不同性質的網路系統可以相互溝通的大系統,它以多層的網路協定(Protocol)來管理其多樣性,這些不同層次的協定都知道自己該負責的任務以及該取得的資訊。圖7-1告訴你這些協定是如何安排的。


 

 圖7-1 以不同的通訊協定階層來協助管理Internet通訊的複雜性

Transport階層界定了應用程式的終點以及Internet階層的起點,這個階層包括User Datagram Protocol (UDP)和Transmission Control Protocol (TCP),這兩種協定決定了應用程式在Internet上傳輸資料的方式,也就是說,它們可以決定兩端電腦連結的方式和資料包裝的方式。你可以在Internet上面使用UDP或TCP來做兩端的直接通訊。例如,你可以傳送應用程式自訂格式的資料,或是傳送一個簡單的訊息給多部機器。UDP和TCP在較低的階層工作,因此它們不會像應用階層的協定(如HTTP和FTP)那樣,會造成較大的系統負擔。

本章一開始就提到Winsock控制項可以直接使用UDP或TCP,而且,InternetTransfer控制項可以使用FTP和HTTP協定。另外,WebBrowser控制項則能將FTP和HTTP的資料轉譯成可被Internet Explorer辨識的格式。如何選擇以上這些控制項呢?這端賴應用程式的需求。我們將在以下這幾節中討論這些課題。

如何建立網路通訊?
 

為了能夠討論本章及下一章的Internet元件,你必須至少準備兩部以上以TCP/IP通訊的電腦。Windows 95和Windows NT都提供TCP/IP協定,如果要檢查TCP/IP是否安裝妥當,請你在「控制台」的「網路」圖像上點兩下滑鼠左鍵,然後點選「協定」(Windows NT)或是「組態」(Windows 95),就可以看見所有在你電腦上已經安裝的協定,如圖7-2。


 

 圖7-2 使用Winsock控制項必須先安裝TCP/IP協定

如果沒有完整的網路環境,你可以用Windows NT的Remote Access Service (RAS)建立一個撥入伺服器(Dial-in Server),然後從另一部電腦的「撥號網路」撥接到這部NT。RAS是Windows NT的一個安裝選項,而「撥號網路」則是Windows 95和Windows NT上面都有的工具。

如果用RAS和「撥號網路」做網路通訊,你只能用固定的IP位址,而不能用電腦的名稱。你可以在「 TCP/IP內容」對話方塊中設定固定的IP位址,如圖7-3。IP位址設好之後便可以被用在任何一個需要IP位址的地方;例如,Winsock控制項的RemoteHost屬性,InternetTransfer控制項的OpenURL物件方法,或是Internet Explorer的「位址」欄中,都需要IP位址。

另外,你可能也需要安裝Microsoft Personal Web Server (PWS)或是Microsoft Internet Information Server (IIS)以便你能從這些伺服器上散佈一些檔案,並且從另一部電腦上以Internet Explorer來瀏覽這些檔案。這樣,就可以很方便地測試你的Active Server Pages動態網頁,而且也可以用來測試安裝Internet元件。(PWS和IIS是Microsoft Visual Studio的安裝選項。)


 

 圖7-3 「TCP/IP內容」對話方塊可以讓你設定IP位址

如何使用Winsock控制項?
 

應用程式連接到Internet必須透過一組IP位址和通訊埠(Port)號碼,這種IP位址和通訊埠號碼的組合便稱為一個Socket,兩部電腦之間如果要能夠相互溝通便需要一對匹配的Socket。

你可以用Winsock控制項(MSWINSCK.OCX)建立匹配的Socket,接著你便可以選擇要用UDP還是TCP做為你的通訊協定:

  • UDP所提供的是一種"非直接連接"(Conectionless)的通訊方式。當你送出資料時,你不知道對方何時或者是否會收到資料。這種通訊方式較適合於網路檔案服務、聊天軟體以及網路廣播等服務。
     
  • TCP要求你在傳送資料之前必須先建立直接連接的通訊管道,資料傳輸完畢後必須關閉通訊管道。TCP在通訊過程中維持著資料傳輸的順序,並且可以確保資料能被對方正確地收到。這種通訊方式適合於大量資料傳輸或檔案傳輸,以及使用者與使用者的直接通訊。
     

以下幾個小節裡,我們會分別介紹如何以Winsock控制項建立使用UDP和使用TCP的Internet應用程式;不過在開始之前,你必須了解一件事:Winsock控制項是一個低階的工具,在Visual Basic裡已經提供了許多高階(應用程式階層)的工具,包括InternetTransfer控制項(MSINET.OCX)以供FTP和HTTP使用,也包括其他控制項以供Post Office Protocol (POP)、音訊資料 (Audio) 和三維 (3D) 資料傳輸。這些協力廠商所提供的控制項資料可以在Internet上面找到,在這裡我們提供幾個參考網站:

UDP廣播服務
 

使用Winsock控制項的UDP需要兩組程序,第一組程序用來傳送資料,第二組程序用來接收資料。

如果要傳送資料,請先在表單上加入一個Winsock控制項,然後按照以下步驟完成設定工作:

  1. 將Winsock控制項的RemotePort屬性設為對方電腦的通訊埠號碼。
  2. 將RemoteHost屬性設為對方電腦的IP位址或電腦名稱。
  3. 以Bind物件方法打開自己的通訊埠以便送出資料。
  4. 以SendData方法傳出資料。

    如果要以UDP接收資料,請按照以下三個步驟完成設定工作:

  1. 將接收端電腦上Winsock控制項的RemotePort屬性設為上面步驟3的通訊埠號碼。
  2. 以Bind物件方法打開接收端的通訊埠。這個通訊埠號碼應該和第一組程序步驟1所使用的通訊埠號碼相同。
  3. 在接收端以DataArrival事件程序呼叫GetData物件方法以便接收資料。

廣播服務範例
 

使用UDP接收資料時,你不需要指明發送端的IP位址,因此,你可以用UDP接收來自不同發送端傳來的訊息,這種多對一的關係正好可以讓你用來建立網路管理的工具,監視網路上所有工作站的狀態,如圖7-4裡的System Status Monitor (SysStat.VBP)。


 

 圖7-4 System Status Monitor可以看見所有工作站上的可用磁碟空間統計數字

System Status Monitor有兩個功能:如果程式啟動時指明接收端電腦的名稱或IP位址(當作命令參數),那麼目前這部電腦就是資料發送端,System Status Monitor會把可用磁碟空間的百分比資料傳送到接收端。如果啟動System Status Monitor時不指明接收端,那麼本地端這部電腦就會是一部被動的接收端,可以接收來自網路上任何一部電腦送出的訊息。

以下這段程式告訴你如何設定Winsock物件:

Option Explicit
`Create object for log file
Dim fsysLog As New Scripting.FileSystemObject

`Command line specifies the name or IP address of
`the machine to send data to
Private Sub Form_Load()
    `Start this application in send mode
    `if a command line is specified

    If Command <> "" Then
        `Set a remote port to send to
        sckUDP.RemotePort = 1002
        `Identify the host to send to
        sckUDP.RemoteHost = Command
        `Bind to a local port to send from
        sckUDP.Bind 1001
        `Send information
        sckUDP.SendData ShowStats
        `End this application
        Unload Me
    `Start in receive mode if no
    `command line
    Else
        `Specify remort port to listen for
        sckUDP.RemotePort = 1001
        `Specify local port to receive from
        sckUDP.Bind 1002
        `Display information along with this
        `machine's "friendly" name
        Me.Caption = Me.Caption & ": " & sckUDP.LocalHostName
    End If
End Sub

如果Winsock控制項發現沒有連接上網路或是接收端電腦的名稱不正確,它的Error事件函式就會被呼叫。在我們的範例中,錯誤查核的動作不多,錯誤發生時只是顯示出錯誤訊息而已:

`Handle transmission errors
Private Sub sckUDP_Error(ByVal Number As Integer, _
    Description As String, ByVal Scode As Long, _
    ByVal Source As String, ByVal HelpFile As String, _
    ByVal HelpContext As Long, CancelDisplay As Boolean _
)
    `Display error messages
    MsgBox Number & " " & Description, vbCritical, App.Title
End Sub

Winsock控制項在通訊埠上收到資料時,它的DataArrival事件程序會被呼叫。GetData物件方法的功能在於讀取已經到達接收緩衝區的資料,並且清空緩衝區,以便接收下一筆資料。

`Handle data as it comes in
Private Sub sckUDP_DataArrival(ByVal bytesTotal As Long)
    Dim strData As String
    `Retrieve the data
    sckUDP.GetData strData
    `Display it
    ShowText strData
    `Save data in log file if check box selected
    If chkLog.Value Then
        fsysLog.CreateTextFile(CurDir & "\stats.log", _
        True).Write txtReceive.Text
    End If
End Sub

UDP一次能傳送的資料量由網路決定,你可以自己實驗一下,找出傳輸的上限。不過,傳遞大量資料最好是用TCP,不要用UDP。

以TCP作一對一交談
 

如果要用Winsock控制項的TCP協定,你必須在傳送資料前先建立起與對方的連線,建立連線包括兩組程序:第一組程序讓其中一部電腦要求建立連線,第二組程序讓另一部電腦接受連線的要求。

請在表單上加入一個Winsock控制項,按照以下幾個步驟讓Winsock控制項提出連線要求:

  1. 將Winsock控制項的RemoteHost屬性設為對方電腦的名稱或IP位址。
  2. 將RemotePort屬性設為對方電腦的通訊埠號碼。
  3. 以Connect物件方法向對方電腦提出連線要求。
  4. 以SendData物件方法傳送資料。

如果要接收一個連線要求,請按照以下這幾個步驟:

  1. 將LocalPort屬性設定為上面步驟2中RemotePort所指定的通訊埠號碼。
  2. 以Listen物件方法開啟通訊埠,準備接受連線要求。
  3. 在ConnectionRequest事件程序中以Accept物件方法建立連線。

一旦連線完成後,你就可以用SendData和GetData物件方法來做資料交換。TCP和UDP有一點不同,TCP要求你在建立一個新連線之前必須以Close物件方法關閉目前的連線。

聊天軟體範例
 

Chat(Chat.VBP)應用程式告訴你如何使用Winsock控制項的TCP為兩部電腦建立連線;一旦連線建立之後,兩位使用者便可以各自在他們的文字方塊中輸入訊息,相互交換,如圖7-5所示。


 

 圖7-5 Chat應用程式以TCP協定讓兩位使用者作線上交談

Chat應用程式一開始便在等待對方的連線請求。Form_Load事件程序設定通訊埠,然後以Listen物件方法聽候連線請求,請看以下這段程式:

Option Explicit
`Start out listening for connection
`requests
Private Sub Form_Load()
    `Set the port to listen on
    sckTCP.LocalPort = 1002
    `Begin listening
    sckTCP.Listen
    `Update status bar
    ShowText "Listening"
End Sub

如果要建立連線,你可以用Connect物件方法。Chat應用程式讓使用者可以指定一個電腦名稱或是IP位址,關閉目前的連線,然後建立新的連線,請看以下這段程式:

Private Sub mnuConnect_Click()
    Dim strRemoteHost As String
    `Get the name of a computer to connect to
    strRemoteHost = InputBox("Enter name or IP address of computer " & _
                  "to connect to.", vbOKCancel)
    `Exit if cancelled
    If strRemoteHost = "" Then Exit Sub
    `Close any open connections
    sckTCP.Close
    `Set the name of the computer to connect to
    sckTCP.RemoteHost = strRemoteHost
    `Specify a port number on remote host
    sckTCP.RemotePort = 1002
    `This seems to prevent some TCP errors
    DoEvents
    `Request the connection
    sckTCP.Connect
End Sub

當等候連線請求的電腦收到另一部電腦的連線請求時,ConnectionRequest事件即被觸發。Chat應用程式在這個事件程序中接受所有的連線請求,請看程式:

Private Sub sckTCP_ConnectionRequest(ByVal requestID As Long)
    sckTCP.Close
    sckTCP.Accept requestID
    ShowText "Accepting request from " & sckTCP.RemoteHostIP
End Sub

等候連線請求的電腦接受了請求之後,兩端便可以開始用SendData傳送資料。Chat應用程式用txtChat文字方塊讓使用者編寫要傳出的訊息,也在這裡顯示收到的訊息。txtChat文字方塊的KeyPress事件程序除了記錄著使用者打入的每一個字元之外,還負責在鍵被按下時以SendData送出訊息。請看程式:

Private Sub txtChat_KeyPress(KeyAscii As Integer)
    Static strSend As String
    `Make sure there is a connection
    If sckTCP.State <> sckConnected Then Exit Sub
    `Send data when user presses Enter
    If KeyAscii = Asc(vbCr) Then
        `Send the string
        sckTCP.SendData strSend
        `Clear the variable
        strSend = ""
    Else
        `Keep track of what is being typed
        strSend = strSend & Chr(KeyAscii)
    End If
End Sub

SendData物件方法會觸發接收端的DataArrival事件,Chat應用程式用GetData讀取訊息佇列中的資訊並將其內容顯示在txtChat文字方塊中。請看程式:

Private Sub sckTCP_DataArrival(ByVal bytesTotal As Long)
    Dim strText As String
    `Get data
    sckTCP.GetData strText
    `Display data received
    txtChat = txtChat & ">>" & strText & vbCrLf
    `Move cursor to end
    txtChat.SelStart = Len(txtChat)
    ShowText "Bytes received: " & bytesTotal
End Sub

若要結束連線,只要呼叫Close物件方法即可。Chat應用程式以一個功能表選項中斷連線並且使程式回到聽候狀態。

Private Sub mnuDisconnect_Click()
    sckTCP.Close
    DoEvents
    sckTCP.Listen
    ShowText "Listen"
End Sub

Close物件方法會觸發另一部電腦上的Close事件。當Close執行時,同樣地,Chat應用程式也回復到聽候狀態,以等待新的連線。請看以下程式:

Private Sub sckTCP_Close()
    ShowText "Close"
    `When connection by remote machine, go back to listening
    sckTCP.Close
    sckTCP.Listen
    ShowText "Listen"
End Sub

TCP連線所提供的錯誤訊息比UDP能提供的還要豐富。因此,當錯誤發生時,顯示錯誤訊息是相當重要的一件事,Chat應用程式以下面這段程式顯示錯誤訊息:

`Display error information
Private Sub sckTCP_Error(ByVal Number As Integer, _
    Description As String, ByVal Scode As Long, _
    ByVal Source As String, ByVal HelpFile As String, _
    ByVal HelpContext As Long, CancelDisplay As Boolean _
)
    ShowText "Error " & Number & " " & Description
End Sub

隨書附贈的光碟中收錄了完整的Chat.VBP,你可以在裡面看到更多TCP連線事件的詳細資訊。另外,Visual Basic的線上手冊也有專門的主題"Using the Winsock Control"討論相關課題。

如何建立一個FTP瀏覽器?
 

在Viusal Basic線上說明中有關InternetTransfer控制項的部分,告訴了你一些如何建立FTP瀏覽器的片段資訊,但並沒有把這些片斷資訊整合起來。由於InternetTransfer控制項是非同步的,所以事件處理和錯誤處理成了這個控制項技術上最困難、而且也是文件中最難說明的部份。

圖7-6是筆者自行建立的一個簡單的FTP瀏覽器,這個瀏覽器裡使用了兩個文字方塊控制項和一個InternetTransfer控制項。你可以在Address文字方塊中打入FTP伺服器的網址(URL),然後可以點選被顯示出來的目錄或檔案。如果你點選的是一個目錄,這個瀏覽器會顯示這個目錄的內容;如果你選擇了一個檔案,這個檔案會被下載到你機器上的Windows\Temp目錄下。

當使用者在Address文字方塊中輸入網址並按下鍵後,瀏覽器便會執行兩個主要動作:設定InternetTransfer控制項的URL屬性,以及呼叫Execute方法。OpenURL方法和Execute方法一樣,都是被用來讀取一個檔案,但是,當你用OpenURL方法來傳回一個目錄的內容時,它會傳回HTML原始碼,表示目錄內容已經被傳回了,因此,在這裡我刻意不用OpenURL方法。以下是Address文字方塊控制項KeyPress事件程序的內容。


 

 圖7-6 用InternetTransfer控制項建立簡單的FTP瀏覽器
Private Sub txtAddress_KeyPress(KeyAscii As Integer)
    If KeyAscii = Asc(vbCr) Then
        `Eat keystroke
        KeyAscii = 0
        `Select text
        txtAddress.SelStart = 0
        txtAddress.SelLength = Len(txtAddress)
        On Error GoTo errOpenURL
        `Set FTP address to view
        inetBrowse.URL = txtAddress
        `Get directory
        inetBrowse.Execute , "Dir "
        txtAddress = inetBrowse.URL
    End If
    Exit Sub

errOpenURL:
    Select Case Err.Number
        Case icBadUrl
            MsgBox "Bad address. Please reenter."
        Case icConnectFailed, icConnectionAborted, _
                icCannotConnect
            MsgBox "Unable to connect to network."
        Case icInetTimeout
            MsgBox "Connection timed out."
        Case icExecuting
            `Cancel previous request
            inetBrowse.Cancel
            `Check whether cancel worked
            If inetBrowse.StillExecuting Then
                Caption = "Couldn't cancel request."
            `Resubmit current request
            Else
                Resume
            End If
        Case Else
            Debug.Print Err.Number, Err.Description
    End Select
End Sub

錯誤處理
 

錯誤發生時的處理動作是一件很重要的工作,在這個例子裡,處理錯誤訊息代碼icExecuting的錯誤處理動作更是特別重要。

InternetTransfer控制項以非同步的方式處理所有的請求(request), 但一次只處理一個請求。如果你取消了一個正在被處理的請求,一定要檢查StillExecuting屬性。因為有些請求無法被取消,如果毫無條件地執行Resume,那麼程式就會跑進一個無窮迴圈裡去。

接下我們來看看txtContents的DblClick事件程序。這個程序用來組合一個URL字串,並且執行適當的指令。當使用者在一個次目錄上連續點選兩次時,這個程序會執行Dir指令,而當點選的對象是一個檔案時,它會執行GET指令讀取資料。

Private Sub txtContents_DblClick()
    `Browse selected directory
    If txtContents.SelLength Then
        `If selection is a directoryDear John, How Do I... 
        If Right(txtContents.SelText, 1) = "/" Then
            `Add selected item to address
            txtAddress = txtAddress & "/" & _
                Left(txtContents.SelText, _
                txtContents.SelLength - 1)
            `Trap errors (important!)
            On Error GoTo errBrowse
            `Show directory
            mstrDir = Right(txtAddress, Len(txtAddress) _
                - Len(inetBrowse.URL))
            inetBrowse.Execute , "Dir " & mstrDir & "/*"
        `Otherwise, it's a file, so retrieve it
        Else
            Dim strFilename
            `Build pathname of file
            mstrDir = Right(txtAddress, Len(txtAddress) _
                - Len(inetBrowse.URL)) & "/" & _
                txtContents.SelText
            mstrDir = Right(mstrDir, Len(mstrDir) - 1)
            strFilename = mstrDir
            Do
                strFilename = Right(strFilename, _
                Len(strFilename) - InStr(strFilename, "/"))
            Loop Until InStr(strFilename, "/") = 0 `Retrieve file
            inetBrowse.Execute , "Get " & mstrDir & _
                " " & mstrTempDir & strFilename
        End If
    End If
Exit Sub
errBrowse:
    If Err = icExecuting Then
        `Cancel previous request
        inetBrowse.Cancel
        `Check whether cancel worked
        If inetBrowse.StillExecuting Then
            Caption = "Couldn't cancel request."
        `Resubmit current request
        Else
            Resume
        End If
    Else
        `Display error
        Debug.Print Err & " " & Err.Description
    End If
End Sub

Execute和OpenURL方法都會觸發StateChanged事件,這裡值得注意的是,OpenURL雖然是一個同步執行的物件方法,但執行OpenURL時,如果發生錯誤,StateChanged事件仍會被觸發,因而造成Reentrency的錯誤。

以下的事件程序會更新表單標題,讓使用者可以掌握資料傳輸的狀態,而且如果程式執行的是Dir指令,這個事件程序會顯示GetChunk方法所傳回的目錄內容。

Private Sub inetBrowse_StateChanged(ByVal State As Integer)
    Select Case State
        Case icError
            Debug.Print inetBrowse.ResponseCode & " " & _
                inetBrowse.ResponseInfo
        Case icResolvingHost, icRequesting, icRequestSent
            Caption = "SearchingDear John, How Do I... "
        Case icHostResolved
            Caption = "Found."
        Case icReceivingResponse, icResponseReceived
            Caption = "Receiving data."
        Case icResponseCompleted
            Dim strBuffer As String
            `Get data
            strBuffer = inetBrowse.GetChunk(1024)
            `If data is a directory, display it
            If strBuffer <> "" Then
                Caption = "Completed."
                txtContents = strBuffer
            Else
                Caption = "File saved in " & _
                    mstrTempDir & "."
            End If
        Case icConnecting, icConnected
            Caption = "Connecting."
        Case icDisconnecting
        Case icDisconnected
        Case Else
            Debug.Print State
    End Select
End Sub

注意:

根據目前Visual Basic文件所述,GetChunk方法可以和Execute方法中的Get指令一起使用,但事實卻不然。Get指令的語法要求我們要指明資料來源和目的檔名,因此,如果我們要從伺服器上複製檔案下來,只要使用Get就可以了,不需要再用GetChunk的方法。


完整的FTP瀏覽器程式,包括GetTempPath API函式的宣告以及Form_Load事件程序,都可以在隨書光碟中找到。

如何控制Internet Explorer?
 

WebBrowser控制項的原始碼SHDOCVW.DLL包含了Internet Explorer的型別庫(Type Library),型別庫裡存放著建立ActiveX物件所需的資訊。因此,你可以在程式中使用這個DLL檔,透過Automation技術(以前叫OLE Automation),啟動並控制一個Internet Explorer的執行實體。

一般而言,Internet Explorer會把已經載入的網頁資料放在快取記憶區(Cache),等下一次使用者要求讀取相同的網頁資料時,Internet Explorer會直接從快取記憶區中讀取網頁。然而在對Internet應用程式偵錯時,你需要的通常不是快取記憶區的資料,而是重新載入的資料。這一節裡我們要介紹Internet Explorer的Add-In範例,如圖7-7,這個Add-In應用程式會開啟一個Internet Explorer並將快取記憶區關閉,方便設計人員對應用程式進行偵錯。

除了標準連線物件類別(CLS)和啟動模組(BAS)之外,這個Add-In應用程式(WEBTOOL.VBP)包括了一張表單,表單上有兩個指令按鈕控制項和一個文字方塊控制項,指令按鈕控制項讓使用者可以看前一頁和下一頁的資料,而文字方塊控制項讓使用者填入URL。

以下的程式碼告訴你如何在程式中產生一個Internet Explorer物件,以及如何以txtAddress文字方塊設定VBD暫存檔的路徑的內容,我們會在 第九章 裡詳細地討論VBD檔。


 

 圖7-7 網頁瀏覽器Add-In
Option Explicit

'deletes cached page, replaces the Navigate method's
'navNoReadFromCache flag
Private Declare Function DeleteUrlCacheEntry Lib _
    "WinInet.DLL" (strURL As String) As Boolean

'Specify the path where VB.EXE is installed
Const VBPath = "file://C:\Program Files\DevStudio\VB\"

`Create an Internet Explorer object variable. Note that
`you must use the "_V1" object to be able to bind to
`the ieView_Quit event
Private WithEvents ieView As SHDocVw.WebBrowser_V1
`In IE3, the following declaration was used:
`Private WithEvents ieView As InternetExplorer

Private Sub Form_Load()
    `Establish a reference to application object
    Set ieView = GetObject("", "InternetExplorer.Application")
    `Be sure Internet Explorer is visible
    ieView.Visible = True
    `Start with VB.EXE path because that's where VBD
    `files are stored during debugging
    txtAddress = VBPath
End Sub

使用GetObject函式時,如果函式的第一個引數是空字串,那麼你將無法取得正在執行的Internet Explorer的執行實體。你必須啟動一個新的Internet Explorer,這個Internet Explorer執行實體產生後,也要讓使用者看見這個Internet Explorer,因此必須將Visible屬性設為True。

接下來的這段程式所作工作是進行網頁巡覽的動作。DeleteUrlCacheEntry API函式可以保證Navigate方法一定會從URL上面下載最新的內容,而不會從快取記憶區中載入舊資料。

Private Sub txtAddress_KeyPress(KeyAscii As Integer)
Dim blnResult As Boolean
    If KeyAscii = Asc(vbCr) Then
        `Eat keystroke
        KeyAscii = 0

        `Select text
        txtAddress.SelLength = Len(txtAddress)
        `Delete this URL if it is cached
        blnResult = DeleteUrlCacheEntry(ByVal txtAddress)
        'Navigate to address
        ieView.Navigate txtAddress
    End If
End Sub

到這裡我們請你再回頭看看Form_Load事件程序。注意一下ieView物件變數宣告的方式,我們用WithEvents宣告ieView,因此ieView可以接受Internet Explorer所有的事件。另外,我們用了CommandStateChange事件來打開或是關閉前一頁按鈕和下一頁按鈕。

Private Sub ieView_CommandStateChange( _
    ByVal Command As Long, _
    ByVal Enable As Boolean _
)
    `Enable or disable Back and Forward command buttons
    `based on whether there is an address to go to
    Select Case Command
        Case CSC_NAVIGATEBACK
            cmdBack.Enabled = Enable
        Case CSC_NAVIGATEFORWARD
            cmdForward.Enabled = Enable
        Case CSC_UPDATECOMMANDS
    End Select
End Sub

Private Sub cmdBack_Click()
    ieView.GoBack
End Sub

Private Sub cmdForward_Click()
    ieView.GoForward
End Sub

當網頁顯示完畢之後,Internet Explorer會啟動NavigateComplete事件,而當使用者關閉應用程式時,Internet Explorer會啟動Quit事件,以下的程式就是這些事件程序的內容:

Private Sub ieView_NavigateComplete(ByVal URL As String)
    `Update text box with the final address
    txtAddress.Text = URL
    txtAddress.SelLength = Len(txtAddress)
    `Display the Web page title in the form's caption
    Caption = ieView.LocationName
End Sub

Private Sub ieView_Quit(Cancel As Boolean)
    `Close this application if user closes Internet Explorer
    End
End Sub

完整的WebTool Add-In專案收錄在隨書光碟中,請參閱其詳細的內容。


參考資料:

請參閱 第二十七章"進階程式設計技巧" 有關增益功能的部分。