如何從 Internet Explorer 使用 VB ActiveX 元件進行 Word 自動化

摘要

本文示範如何從 Internet Explorer 中轉譯的網頁,使用 ActiveX 元件進行 Word 的用戶端自動化。 從網頁使用 ActiveX 元件,而不是內嵌在網頁本身的腳本有幾個優點:

  • 如果您已經有可自動化 Microsoft Word 的 Visual Basic 程式碼,您可以將 Visual Basic 專案轉換成 ActiveX EXE 或 ActiveX DLL,以在瀏覽器中重複使用您的程式碼。
  • Word 未標示為安全的腳本。 視 Internet Explorer 中的安全性設定而定,腳本中的 Word Automation 程式碼可能不會執行,或使用者可能會收到安全性警告提示。 假設您的 ActiveX 元件符合特定指導方針,可能會標示為安全的腳本,以避免這些安全性問題。
  • Visual Basic 有數個功能,您無法在網頁中搭配腳本使用。 例如,Visual Basic 可用但不適用於網頁腳本的其中一項功能,就是能夠呼叫 Windows 應用程式開發介面 (API) 。

常見的開發人員案例是向使用者展示網頁介面,以使用來自某些外部來源或邏輯的資料來建立 Word 檔。 雖然您可以使用伺服器端 Word 自動化來產生檔,並將其串流回用戶端,但使用牽涉到 Word Automation 的伺服器端方法有許多缺點。 主要缺點是延展性;Word 是非常耗用資源的自動化伺服器,不建議在網頁伺服器上產生檔。

藉由使用 ActiveX 元件在用戶端執行檔產生,您可以將耗用大量資源的 Word Automation 從 Web 服務器移開。 這是本文所討論的範例 ActiveX 元件所呈現的解決方案。 雖然此範例專屬於 Word Automation,但相同的原則也適用于自動化其他 Microsoft Office 應用程式,例如 Microsoft Excel。

其他相關資訊

Visual Basic ActiveX 元件

此範例中的 Visual Basic ActiveX 元件會與網頁腳本互動,以在使用者的要求下產生訂單發票檔。 Web 應用程式可能會允許 ActiveX 元件取得指定訂單識別碼的訂單資訊,或者 Web 應用程式可以選擇將訂單資訊封裝為 XML,並傳送至 ActiveX 元件進行處理。 不論是哪一種情況,元件取得訂單資訊之後,都可以將 Word 自動化,以建置並顯示訂單的發票檔。

(AutomateWord) 的 ActiveX 元件包含單一類別 Invoice 類別,它會公開三種方法:

  • GetData 方法會使用 ActiveX Data Objects (ADO) 來擷取 Northwind 範例資料庫中訂單的相關資訊。 訂單資訊會儲存在m_Data私用成員變數中。 您可以呼叫 GetData 方法,讓資料擷取發生在用戶端。
  • SendData 方法會使用 Microsoft XML (MSXML) ,以呼叫端所提供的順序資訊填入m_Data私用成員變數。 SendData 需要一個代表訂單資訊之 DOMDocument 物件的參數。 您可以呼叫 SendData 方法,將訂單資訊從網頁傳送至元件。 透過這種方法,您可以使用 ASP 來擷取資料伺服器端,並以可用於產生檔的 XML 資料島呈現用戶端。
  • MakeInvoice 方法會使用 Word Automation 來建置檔,其中包含m_Data私用成員變數中的訂單資訊。 儲存在網頁伺服器上的檔會作為發票的起點。 呼叫端可以選擇在瀏覽器外部顯示已完成的 Word 檔,或將完成的檔儲存至磁片以供稍後使用。

Invoice.cls

Option Explicit

Private Type InvoiceData
    OrderID As String
    OrderDate As Date
    CustID As String
    CustInfo As String
    ProdInfo As Variant
End Type

Private m_Data As InvoiceData

Public Sub GetData(sOrderID As Variant, sConn As Variant)

Dim oConn As Object, oRS As Object

'Connect to the Northwind database.
    Set oConn = CreateObject("ADODB.Connection")
    oConn.Open sConn

'Obtain the Customer ID and Order Date.
    Set oRS = CreateObject("ADODB.Recordset")
    oRS.Open "Select [OrderDate], [CustomerID] from Orders where " & _
             "[OrderID]=" & sOrderID, oConn, 3 'adOpenStatic=3
    m_Data.OrderID = sOrderID
    m_Data.OrderDate = CDate(oRS.Fields("OrderDate").Value)
    m_Data.CustID = oRS.Fields("CustomerID").Value
    oRS.Close

'Obtain Customer information.
    Set oRS = CreateObject("ADODB.Recordset")
    oRS.Open "Select * from Customers Where CustomerID='" & _
             m_Data.CustID & "'", oConn, 3 'adOpenStatic=3
    m_Data.CustInfo = oRS.Fields("CompanyName").Value & vbCrLf & _
                      oRS.Fields("City") & " "
    If Not (IsNull(oRS.Fields("Region"))) Then
       m_Data.CustInfo = m_Data.CustInfo & oRS.Fields("Region").Value & " "
    End If
    m_Data.CustInfo = m_Data.CustInfo & oRS.Fields("PostalCode").Value & _
                      vbCrLf & oRS.Fields("Country").Value
    oRS.Close

'Obtain Product information.
    Set oRS = CreateObject("ADODB.Recordset")
    oRS.Open "Select ProductName, Quantity, [Order Details].UnitPrice," & _
             "Discount from Products Inner Join [Order Details] on " & _
             "Products.ProductID = [Order Details].ProductID " & _
             "Where OrderID = " & sOrderID, oConn, 3 'adOpenStatic=3
    m_Data.ProdInfo = oRS.GetRows
    oRS.Close

'Close the connection to the database.
    oConn.Close

End Sub

Public Sub SendData(oXML As Variant)

'Extract the information from the DOMDocument object oXML and store
    'it in the private member variable m_Data.

m_Data.OrderID = oXML.getElementsByTagName("OrderID").Item(0).Text
    m_Data.OrderDate = oXML.getElementsByTagName("OrderDate").Item(0).Text
    m_Data.CustID = oXML.getElementsByTagName("CustID").Item(0).Text
    m_Data.CustInfo = oXML.getElementsByTagName("CustInfo").Item(0).Text

Dim oItems As Object, oItem As Object
    Set oItems = oXML.getElementsByTagName("Items").Item(0)
    ReDim vArray(0 To 3, 0 To oItems.childNodes.Length - 1) As Variant
    Dim i As Integer
    For i = 0 To UBound(vArray, 2)
        Set oItem = oItems.childNodes(i)
        vArray(0, i) = oItem.getAttribute("Desc")
        vArray(1, i) = oItem.getAttribute("Qty")
        vArray(2, i) = oItem.getAttribute("Price")
        vArray(3, i) = oItem.getAttribute("Disc")
    Next
    m_Data.ProdInfo = vArray

End Sub

Public Sub MakeInvoice(sTemplate As Variant, Optional bSave As Variant)

Dim oWord As Object
    Dim oDoc As Object
    Dim oTable As Object

If IsMissing(bSave) Then bSave = False

'Open the document as read-only.
    Set oWord = CreateObject("Word.Application")
    Set oDoc = oWord.Documents.Open(sTemplate, , True)

'Fill in the bookmarks.
    oDoc.Bookmarks("Customer_Info").Range.Text = m_Data.CustInfo
    oDoc.Bookmarks("Customer_ID").Range.Text = m_Data.CustID
    oDoc.Bookmarks("Order_ID").Range.Text = m_Data.OrderID
    oDoc.Bookmarks("Order_Date").Range.Text = m_Data.OrderDate

'Fill in the table with the product information.
    '** Note that the table starts out with three rows -- the first row
    '   contains headers for the table, the second row is for
    '   the first set of product data, and the third row contains a total.
    '   New rows are added for additional products before the "total row".

Set oTable = oDoc.Tables(1)
    Dim r As Integer, c As Integer
    For r = 1 To UBound(m_Data.ProdInfo, 2) + 1
        If r > 1 Then oTable.Rows.Add (oTable.Rows(oTable.Rows.Count))
        For c = 1 To 4
            oTable.Cell(r + 1, c).Range.Text = _
               m_Data.ProdInfo(c - 1, r - 1)
        Next
        oTable.Cell(r + 1, 5).Formula _
            "=(B" & r + 1 & "*C" & r + 1 & ")*(1-D" & r + 1 & ")", _
            "#,##0.00"
    Next

'Update the field for the grand total and protect the document.
    oTable.Cell(oTable.Rows.Count, 5).Range.Fields.Update
    oDoc.Protect 1 'wdAllowOnlyComments=1

If bSave Then
        'Save the document as "c:\invoice.doc" and quit Word.
        Dim nResult As Long
        nResult = MsgBox("Are you sure you wish to create the document" & _
             " ""c:\invoice.doc""? If this document already exists, " & _
             "it will be replaced", vbYesNo, "AutomateWord")
        If nResult = vbYes Then oDoc.SaveAs "c:\invoice.doc"
        oDoc.Close False
        oWord.Quit
    Else
        'Make Word visible.
        oWord.Visible = True
    End If

End Sub

從網頁使用 ActiveX 元件

Autoword1.htm示範如何使用 GetData 方法,讓 ActiveX 元件從用戶端擷取訂單資料並建置檔。

Autoword1.htm

<HTML>
<HEAD>
   <OBJECT ID="AutoWord"
    CLASSID="CLSID:32646EBA-0919-4C2F-94D6-599F46DC34F2"
    CODEBASE="https://YourWebServer/invoice/package/AutomateWord.CAB#version=1,0,0,0">
   </OBJECT>
</HEAD>
<BODY>
Enter an order id between 10248 and 11077 and click the button to view the invoice for the order:
<P/><INPUT TYPE="text" VALUE="10500" ID="OrderID">
<P/><BUTTON ID="InvoiceButton">Create Invoice</BUTTON>
</BODY>

<SCRIPT Language="VBScript">

Function InvoiceButton_OnClick()
      Dim sConn
      sConn = "Provider=sqloledb;Data Source=YourSQLServer;Initial Catalog=Northwind;UID=sa;"
      AutoWord.GetData OrderID.Value, sConn
      AutoWord.MakeInvoice "https://YourWebServer/invoice/invoice.doc"
   End Function

</SCRIPT>
</HTML>

Autoword1.htm中的腳本會使用 ActiveX 元件,在瀏覽器外部顯示已完成的檔。 您也可以選擇儲存已完成的檔,並將其顯示在瀏覽器中;不過,這麼做需要將 Word 檔儲存至磁片。 元件可以將檔儲存為用戶端本機磁片磁碟機上的C:\Invoice.doc。 因為 ActiveX 元件標示為安全的腳本,所以會提示用戶端確認儲存。

如果您想要在瀏覽器中顯示已完成的檔,請將Autoword1.htm中 MakeInvoice 的呼叫變更為下列內容:

      AutoWord.MakeInvoice "https://YourWebServer/invoice/invoice.doc", True
      window.navigate "c:\invoice.doc"

Autoword2.htm示範如何使用 SendData 方法,將訂單資料當做 DOMDocument 物件傳送至 ActiveX 元件,以產生已完成的檔。 DOMDocument 是從位於網頁上的 XML 資料島建立。 若要讓 ActiveX 元件正確處理呼叫端所傳送的順序資訊,XML 必須格式正確且結構化,元件才能將它解譯為順序資訊。

Autoword2.htm

<HTML>
<HEAD>
   <OBJECT ID="AutoWord"
    CLASSID="CLSID:32646EBA-0919-4C2F-94D6-599F46DC34F2"
    CODEBASE="https://YourWebServer/invoice/package/AutomateWord.CAB#version=1,0,0,0">
   </OBJECT>
</HEAD>
<BODY>
   <BUTTON ID="InvoiceButton">Create Invoice</BUTTON>
   <XML ID="DataXML">
     <Order>
        <OrderID>10700</OrderID>
        <OrderDate>10/10/2000</OrderDate>
        <CustID>SAVEA</CustID>
        <CustInfo>Save-a-lot
Markets Boise ID 83720
USA</CustInfo>
        <Items>
           <Product Desc="Chai" Qty="5" Price="18" Disc="0.2"/>
           <Product Desc="Sasquatch Ale" Qty="12" Price="14" Disc="0.2"/>
           <Product Desc="Scottish Longbreads" Qty="40" Price="12.5" Disc="0.2"/>
           <Product Desc="Flotemysost" Qty="60" Price="21.5" Disc="0.2"/>
        </Items>        
     </Order>
   </XML>
</BODY>

<SCRIPT Language="VBScript">

Function InvoiceButton_OnClick()
      AutoWord.SendData DataXML.XMLDocument
      AutoWord.MakeInvoice "https://YourWebServer/invoice/invoice.doc"
   End Function

</SCRIPT>
</HTML>

在Autoword1.htm和Autoword2.htm中,您應該注意 ActiveX 元件是透過標記而非 CreateObject 函式來具現化。 使用 標記的目的是為尚未安裝元件的使用者啟用 ActiveX 元件的自動下載。 如果使用者造訪其中一個頁面,但未安裝元件,則會從封包 (CAB) 檔案下載,該檔案位於 CODEBASE 屬性中指示的 URL。 視使用者在 Internet Explorer 中的安全性設定而定,他們可能會先收到確認下載的提示。

注意:包含在 Autoword.exe 中的 CAB 檔案是使用 Visual Basic 的套件和部署精靈所建立。 套件中的 ActiveX 元件會標示為安全的腳本和初始化,但不會以數位方式簽署。

如需建立網際網路元件下載、數位簽署,以及將元件標示為安全的腳本和初始化的詳細資訊,請參閱下列 Microsoft Developer Network (MSDN) 網站:

使用 Authenticode 簽署和檢查程式碼 https://msdn.microsoft.com/en-us/library/ms537364.aspx

ActiveX 控制項的安全初始化和腳本 https://msdn.microsoft.com/en-us/library/Aa751977.aspx

參考

如需其他資訊,請按一下下列文章編號以檢視 Microsoft 知識庫中的文章:

257757 資訊:不建議或支援自動執行 Office 的自動化

(c) Microsoft Corporation 2001, All Rights Reserved. 由 Lori B. 客戶、Microsoft Corporation 參與。