Domino 和 Word 的集成
簡介: 在大部分的 OA(Office Automation)系統中都有涉及公文流轉的模塊,而這些模塊往往是整個 OA 系統的核心模塊,在公文流轉中有一項需求特別多,就是要將公文在流轉中的“痕跡”(比如是誰在什麼時候增加,刪除或者修改了文檔的哪一部分,領導的意見,批註等)保留下來,供公文流轉過程中的各種人員參考。本文將介紹利用 LotusScript 實現 Microsoft Word 文檔在公文流轉中的公文留痕的方法。
<!-- -->
Object Linking and Embedding (OLE) 對象
OLE 技術,全稱爲對象連接與嵌入技術,是一種面嚮對象的技術,通過定義和實現應用程序作爲對象彼此連接的機制,完成應用程序之間的集成。OLE 是在客戶應用程序間傳輸和共享信息的一組綜合標準,基於組件對象模型(COM),現在已經廣泛應用於電子表格、字處理、財務軟件、項目管理軟件等等。
在 LotusScript 中要創建或者得到 OLE 對象,需要使用 CreateObject 函數或者 GetObject 函數。
CreateObject 函數
創建一個指定類型的 OLE 對象
語法
CreateObject ( className )
參數
className 是一個 appName.appClass 格式的字符串,表示要創建的對象的類型,比如“WordPro.Application”。appName 表示支持 OLE 的應用程序名,appClass 表示要創建的對象的類型
返回值
返回一個 OLE 對象的引用
用法
在 LotusScript 中要用 Set 來把 CreateObject 函數返回的對象引用賦值給一個變體類型(Variant)的變量。
如果該類型的應用程序還沒有運行,CreateObject 函數會先啓動這個應用程序然後再創建 OLE 對象。OLE 對象引用只在應用程序運行時有效,如果在使用 OLE 對象引用時應用程序退出了,LotusScript 將拋出一個運行時錯誤。每一種 OLE 對象都有其自己定義和提供的一套類,通過這些類就可以操作該種應用程序。
示例
Sub Initialize '創建一個 Word.Application 對象 Set MyApp = CreateObject ( "Word.Application") '設置該對象的 Visible 屬性爲 True MyApp.Visible = True End Sub |
GetObject 函數
打開一個應用程序文件包含的 OLE 對象或者返回一個當前活動的指定類型的 OLE 對象。
語法
GetObject ( [pathName] [ , className ] )
參數
pathName 一個包含全路徑文件名的應用程序文件或者爲空。該應用程序必須支持 OLE。如果爲空字符串 (“”) 或者省略,則必須制定 className,並且會返回當期活動的對象。
className 同 CreateObject 的 className 參數。但是可以省略,如果省略,則更具 pathName 來決定返回的 OLE 對象。
返回值
返回一個 OLE 對象的引用
用法
同 CreateObject
示例
Sub Initialize Dim myDoc As Variant '從文件得到 WordPro.Document 對象。 Set mydoc = getobject("d:\wordpro\docs\test.lwp","WordPro.Document") ' 調用 WordPro.Document 對象的 Print 方法。 myDoc.Print End Sub |
實現 Microsoft Word 文檔在公文流轉中的公文留痕
下面通過一個例子來展示如何利用 LotusScript 來實現 Microsoft Word 文檔在公文流轉中的公文留痕。本例中用戶首先建立一個發文稿,正文爲 Word 文檔,發稿人寫完正文後以附件形式保存,然後提交審覈,審覈過程中將會實現留痕,審覈完畢後將形成正式公文,以後可以查看正文但是不能修改,查看方式可以顯示或者隱藏修訂的信息。本例中爲了讓讀者看起來方便,沒有加任何錯誤處理的代碼,實際應用中肯定需要加上這種代碼來保證出錯的時候能然 Word 程序退出和臨時文件的清除。
首先創建一個空白的 WordTest.nsf,建立一個表單名爲“發文”,別稱爲“FaWen”,爲了簡化,此表單中只包含三個域:Status,Title,Body。Status 表示公文流轉的狀態,各個表單按鈕根據 Status 的值來隱藏或者顯示,Status 本身總是隱藏的,Title 表示本發文的標題,Body 保存 Word 正文,總是隱藏,以免用戶不通過表單按鈕來操作 Body 域中的 Word 正文。本例中實現了一個簡單的公文流轉的流程,包括公文起草,審批和審批完畢後的查看,所有代碼都在發文表單的操作中完成。下面先看看起草正文的代碼。
清單 1
Sub Click(Source As Button) Dim activedoc As Variant Dim WordApp As Variant Dim s As New NotesSession Dim ws As New NotesUIWorkspace Dim db As NotesDatabase Dim uidoc As NotesUIDocument Dim doc As NotesDocument Set db = s.CurrentDatabase Set uidoc = ws.CurrentDocument Set doc = uidoc.Document Dim rtitem As NotesRichTextItem Set rtitem = doc.GetFirstItem("Body") If rtitem Is Nothing Then Set rtitem = New NotesRichTextItem(doc, "Body") End If '定義文件名和全路徑文件名 Dim sFileName As String, sFilePath As String '根據標題來確定正文文件名 sFileName = Trim(uidoc.FieldGetText("Title"))+".doc" If sFileName = ".doc" Then Msgbox "請輸入標題" Call uidoc.GotoField("Title") Exit Sub End If sFilePath = "C:\\"+sFileName '創建 Word 對象 Set WordApp=CreateObject("Word.Application") WordApp.Visible=True '打開或者新建正文 If Not OpenWordDoc(WordApp, uidoc, sFileName) Then Exit Sub '激活當前的文檔 Set activedoc = WordApp.ActiveDocument '設置 Word 文檔的作者爲當前用戶 WordApp.Username = s.CommonUsername WordApp.Activate activedoc.Activate '最大化 Word 窗口 WordApp.WindowState =1 '編輯完成後保存並退出 Word Msgbox "請單擊確定完成編輯",32,"消息" '保存正文並退出 Word Call activedoc.SaveAs(sFilePath) Call activedoc.Close(0) Call WordApp.Quit(0) Set activedoc = Nothing Set WordApp = Nothing '附上修改後的正文 Set rtitem = New NotesRichTextItem(doc, "Body") Call rtitem.EmbedObject( EMBED_ATTACHMENT , "" , sFilePath ) doc.SaveOptions = 0 Call uidoc.Close doc.SaveOptions = 1 doc.Status = "草稿" doc.Form = "FaWen" Call doc.Save(True, True) '刪除在硬盤的臨時文件 Kill sFilePath Call ws.EditDocument(False, doc) Msgbox "正文起草完畢" End Sub |
在本例中,根據標題來確定 Word 正文文件名,然後創建 Word 對象並設置 Word 可見,然後調用 OpenWordDoc() 函數來新建或者打開已經存在於 Body 域的 Word 文檔,然後將當前 Notes 用戶名傳給 Word 作爲 Word 文檔的作者並激活 Word 程序,然後下面的這句很重要,它相當於暫停了程序讓用戶能在 Word 文檔中編寫發文的正文,等編輯完成後點擊確定按鈕讓後面的程序繼續執行。
Msgbox "請單擊確定完成編輯",32,"消息" |
確定完成編輯後,通過調用 VBA 相關的方法保存該 Word 文檔並退出 Word 程序,然後將此正文嵌入到 Body 域,最後刪除留在硬盤的臨時文件。
下面是 OpenWordDoc() 函數的實現:
清單 2
Function OpenWordDoc(WordApp As Variant, uidoc As notesuidocument, sFileName As String) As Boolean OpenWordDoc=True Dim doc As notesdocument Set doc = uidoc.Document '如果已經有了正文附件,直接打開修改,否則根據狀態新建一個空的 Word 文件或者退出 Dim attachment As NotesEmbeddedObject Set attachment = doc.GetAttachment(sFileName) If Not attachment Is Nothing Then If Dir$( attachment.Name)<> "" Then Kill "C:\\"+sFileName '將正文附件解開到硬盤並打開 Call attachment.ExtractFile("C:\\"+sFileName) Call WordApp.Documents.Open("C:\\"+sFileName) If Not doc.Status(0) = "審覈完畢" Then Call doc.RemoveItem("Body") End If Else If (doc.Status(0)="草稿") Or (doc.Status(0)="") Then Call WordApp.Documents.Add Else Msgbox "沒有找到正文,請先起草正文" OpenWordDoc=False Exit Function End If End If End Function |
這個函數比較簡單,首先判斷是否已經存在 Word 正文了,如果有了就解壓到硬盤然後調用 Open() 方法用 Word 打開該 Word 文檔,否則根據當前發文狀態,如果在草稿階段就新建一個 Word 文檔,否則報錯並退出。
起草正文可以多人多次來完成,一旦最終完成就可以點擊“提交審覈”操作進入審覈階段,該操作代碼如下,只是將 Status 域的值設爲“審覈中”,由於代碼很簡單,這裏就不分析了。
清單 3
Sub Click(Source As Button) Dim ws As New NotesUIWorkSpace Dim uidoc As NotesUIDocument Dim doc As NotesDocument Set uidoc = ws.CurrentDocument Set doc = uidoc.Document Dim rtitem As NotesRichTextItem Set rtitem = doc.GetFirstItem("Body") If rtitem Is Nothing Then Msgbox "沒有找到正文,請先起草正文" Exit Sub End If Dim sFileName As String sFileName = Trim(uidoc.FieldGetText("Title"))+".doc" Dim attachment As NotesEmbeddedObject Set attachment = doc.GetAttachment(sFileName) If attachment Is Nothing Then Msgbox "沒有找到正文,請先起草正文" Exit Sub End If uidoc.EditMode = True Call uidoc.FieldSetText("Status", "審覈中") Call uidoc.Save Msgbox "成功提交審覈" Call uidoc.Close End Sub |
在提交審覈後,就進入審覈階段,點擊“審覈正文”操作將會打開 Body 域中的 Word 正文並設置正文爲修訂狀態,這樣所有對文檔的改動都將被記錄下來。代碼如下:
清單 4
Sub Click(Source As Button) Dim activedoc As Variant Dim WordApp As Variant Dim s As New NotesSession Dim ws As New NotesUIWorkspace Dim db As NotesDatabase Dim uidoc As NotesUIDocument Dim doc As NotesDocument Set db = s.CurrentDatabase Set uidoc = ws.CurrentDocument Set doc = uidoc.Document Dim rtitem As NotesRichTextItem Set rtitem = doc.GetFirstItem("Body") If rtitem Is Nothing Then Msgbox "沒有找到正文,請先起草正文" Exit Sub End If '定義文件名和全路徑文件名 Dim sFileName As String, sFilePath As String '根據標題來確定正文文件名 sFileName = Trim(uidoc.FieldGetText("Title"))+".doc" sFilePath = "C:\\"+sFileName '創建 Word 對象 Set WordApp=CreateObject("Word.Application") WordApp.Visible=True '隱藏 Word 中相關菜單 Call HideWordMenu(WordApp) '用 Word 打開正文 If Not OpenWordDoc(WordApp, uidoc, sFileName) Then Exit Sub '激活當前的文檔 Set activedoc = WordApp.ActiveDocument '設置 Word 文檔的作者爲當前用戶 WordApp.Username = s.CommonUsername WordApp.Activate activedoc.Activate '最大化 Word 窗口 WordApp.WindowState =1 '設置痕跡保護 If activedoc.ProtectionType = -1 Then activedoc.Protect(0) End If activedoc.TrackRevisions = True activedoc.PrintRevisions = True activedoc.ShowRevisions = True '審覈完成後保存並退出 Word Msgbox "請單擊確定編輯完成",32,"消息" '恢復 Word 菜單 Call WordApp.CommandBars("Menu Bar").Reset Call activedoc.SaveAs(sFilePath) Call activedoc.Close(0) Call WordApp.Quit(0) Set activedoc = Nothing Set WordApp = Nothing '附上審覈後的正文 Set rtitem = New NotesRichTextItem(doc, "Body") Call rtitem.EmbedObject( EMBED_ATTACHMENT , "" , sFilePath ) doc.SaveOptions = 0 Call uidoc.Close doc.SaveOptions = 1 doc.Status = "審覈中" Call doc.Save(True, True) '刪除在硬盤的臨時文件 Kill sFilePath Call ws.EditDocument(False, doc) Msgbox "正文審覈結束" End Sub |
在上面的代碼中,需要詳細討論的有兩部分。
第一是通過調用過程 HideWordMenu() 來隱藏 Word 中相關菜單,第二是實現具體修訂留痕的部分,下面分別分析。
通過調用過程 HideWordMenu() 來隱藏 Word 中相關菜單,代碼如下:
清單 5
Sub HideWordMenu(wordapp As Variant) Dim commandBar As Variant '隱藏工具菜單 Set commandBar = WordApp.CommandBars.FindControl(,30007,,True) If Not commandBar Is Nothing Then commandBar.Visible = False commandBar.Enabled = False End If '隱藏 VB 編輯器菜單 Set commandBar = WordApp.CommandBars.FindControl(,1695,,True) If Not commandBar Is Nothing Then commandBar.Visible = False commandBar.Enabled = False End If '隱藏錄製新宏菜單 Set commandBar = WordApp.CommandBars.FindControl(,2780,,True) If Not commandBar Is Nothing Then commandBar.Visible = False commandBar.Enabled = False End If End Sub |
這個過程隱藏了 Word 的工具菜單,VB 編輯器菜單和錄製新宏菜單,這是爲了避免用戶審覈的時候的誤操作改變了當前文檔的修訂留痕狀態。在實際的應用中,這裏更爲複雜,可能不僅需要隱藏更多的菜單項,還可能會增加一些自定義的菜單,這與項目的具體情況有關。要隱藏任何菜單,最重要的通過 FindControl() 方法得到該菜單,該方法的詳細用法可以參考 VBA 幫助。而要使用此方法,最重要的是得到要隱藏菜單的 ID,比如上面代碼中要工具菜單的 ID 是 30007,這個 ID 值是不變的,要得到 Word 菜單的 ID,可以用一個簡單的程序得到,這個程序在在 WordTest.nsf 中也有,具體在發文表單的操作“取 Word 菜單 ID”中。代碼如下:
清單 6
Sub Click(Source As Button) '創建 Word 對象 Dim ws As New NotesUIWorkspace Set WordApp=CreateObject("Word.Application") WordApp.Visible=True tmp$="" For i=1 To 35000 Set ctl = wordapp.CommandBars.FindControl(,i) If Not ctl Is Nothing Then tmp$=tmp$+Cstr(i)+":Caption="+ctl.Caption+Chr(13)+Chr(10) End If Next Call ws.CurrentDocument.fieldsettext("Body",tmp$) Call WordApp.Quit(0) Set WordApp = Nothing End Sub |
只要運行這個程序,則會在發文表單的 Body 域中得到所有的 Word 菜單的 ID 和名稱的對應關係。這個程序很簡單,就是枚舉出所有 ID。注意在 WordTest.nsf 中,Body 域和操作“取 Word 菜單 ID”都是隱藏的,要使用此功能時需要先把隱藏公式去掉。
主要代碼如下:
清單 7
If activedoc.ProtectionType = -1 Then activedoc.Protect(0) End If activedoc.TrackRevisions = True activedoc.PrintRevisions = True activedoc.ShowRevisions = True |
這裏 ProtectionType 返回當前文檔的保護類型,可能的值和說明如下:
- -1 沒有保護
- 0 只允許修訂和批註
- 1 只允許批註
- 2 不能修訂和批註
首先判斷當前的文檔保護是否已經啓用,如果沒有則將當前文檔保護,級別爲可以修訂和批註。注意一定要先通過 ProtectionType 來判斷當前文檔是否已經被保護,否則如果文檔已經被保護則 Protect 方法會報錯。
然後分別設置 TrackRevisions,PrintRevisions 和 ShowRevisions 三個屬性爲 true,這就保證了當用戶修改文本時所有的修改痕跡都會被標記,並且所有修改痕跡會顯示,打印時也會打印出來。這裏說的修改痕跡包括增加,修改和刪除。下面是這三個屬性的說明:
- Document.TrackRevisions: 如果該屬性值爲 True,則標記對指定文檔的修改。Boolean 類型,可讀寫。
- Document.PrintRevisions: 如果該屬性值爲 True,則在打印文檔的同時打印修訂標記。如果返回 False,則不打印修訂標記(即打印接受修訂後的狀態)。Boolean 類型,可讀寫。
- Document.ShowRevisions: 如果該屬性值爲 True,則在屏幕上顯示對指定文檔的修訂。Boolean 類型,可讀寫。
在所有的人都審覈完畢後,就可以將正文設爲只讀的保護起來,同時提供查看正文的功能,查看正文又分爲顯示修訂信息和隱藏修訂信息兩種,可以讓有權限的用戶查看,這幾個功能主要還是通過設置文檔保護和修訂狀態來實現的,具體代碼可以在 WordTest.nsf 的發文表單的相應操作中看到。
下面是 WordTest.nsf 中演示公文留痕的步驟和截圖:
- 在 Notes Client 中打開 WordTest.nsf
圖 1. 在 Notes Client 中打開 WordTest.nsf - 在視圖中點擊“新建”按鈕新建一個發文文檔。
Figure xxx. Requires a heading - 在視圖中點擊“新建”按鈕新建一個發文文檔。
圖 2. 新建 Word 文檔 - 輸入標題,點擊“起草正文”按鈕後,將會新建一個 Word 文檔,在此文檔中起草的發文內容。
圖 3. 切換到 Notes 客戶端 - 點擊確定後,系統將自動保存 Word 文檔並以附件形式保存在隱藏的 Body 域中。
- 起草可以多次,再次點擊“起草正文”按鈕可以繼續在原來的草稿中編輯。
- 起草完成後,點擊“提交審覈”按鈕,這樣正文的狀態被置爲“審覈中”,同時,隱藏“起草正文”和“提交審覈”按鈕,顯示“審覈正文”和“審覈完畢”按鈕。
圖 4. 提交審覈顯示“審覈正文”和“審覈完畢”按鈕 - 點擊“審覈正文”按鈕進入審覈過程,這個過程可以由多人完成,在此過程中,任何人對正文的修改痕跡都會被保留,包括被誰修改的也會保留,同時可以看到相應的菜單已經被隱藏。
圖 5. 進入審覈過程 - 審覈完成後,點擊“審覈完畢”按鈕,則正文將被置於只讀狀態,表示這是最終修訂過的版本了。同時,原來的“審覈正文”和“審覈完畢”按鈕被隱藏,顯示“查看正文”按鈕。
圖 6. 查看正文 - 查看正文時,如果選擇顯示修訂信息的方式,則內容和最後審覈完畢前的狀態相同,都是直接將修改痕跡顯示出來,只是不能再次修改了,如果選擇隱藏修訂信息的方式,則所有的修改痕跡會被合併然後顯示。
圖 7. 查看正文
本文通過這個示例詳細展示瞭如何利用 LotusScript 來實現 OA 系統中常用的公文留痕功能,希望能夠拋磚引玉,以此爲基礎,從而實現更爲複雜的留痕功能。
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
本文代碼下載 | WordTest.zip | 41 KB | HTTP |
學習
- 參閱 developerWorks 文章:“如何在 LotusScript 中處理組”。
- 參閱 developerWorks 文章:“用 LotusScript 實現 Excel 報表的自動生成和操作”。
- 參閱 developerWorks 文章:“在 LotusScript 中爲自定義對象模擬事件”。
- 參閱 developerWorks 文章:“利用 LotusScript 靈活操作 Lotus Notes 富文本域”。
討論