Domino 和 Word 的整合
陳 斌, 軟體工程師 , IBM陳斌是來自 IBM CSTL 的進階軟體開發工程師,現在負責 Lotus Domino for IBM i 的開發、支援以及團隊領導工作。陳 雲, 軟體工程師, IBM陳雲是來自 IBM CSTL 的軟體開發工程師,現在從事 Lotus Domino for IBM i 的開發和支援工作。
簡介: 在大部分的 OA(Office Automation)系統中都有涉及公文流轉的模組,而這些模組往往是整個 OA 系統的核心模組,在公文流轉中有一項需求特別多,就是要將公文在流轉中的“痕迹”(比如是誰在什麼時候增加,刪除或者修改了文檔的哪一部分,領導的意見,批註等)保留下來,供公文流轉過程中的各種人員參考。本文將介紹利用 LotusScript 實現 Microsoft Word 文檔在公文流轉中的公文留痕的方法。
標記本文!
發布日期: 2010 年 11 月 30 日
層級: 初級
訪問情況 836 次瀏覽
建議: 0 (添加評論)
平均分 (共 1 個評分 )
Object Linking and Embedding (OLE) 對象
OLE 技術,全稱為對象串連與嵌入技術,是一種物件導向的技術,通過定義和實現應用程式作為對象彼此串連的機制,完成應用程式之間的整合。OLE 是在客戶應用程式間傳輸和共用資訊的一組綜合標準,基於元件物件模型(COM),現在已經廣泛應用於試算表、文書處理、財務軟體、專案管理軟體等等。
CreateObject 函數和 GetObject 函數
在 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 富文本域”。
討論
- 加入 My developerWorks 中文社區。
作者簡介
陳斌是來自 IBM CSTL 的進階軟體開發工程師,現在負責 Lotus Domino for IBM i 的開發、支援以及團隊領導工作。
陳雲是來自 IBM CSTL 的軟體開發工程師,現在從事 Lotus Domino for IBM i 的開發和支援工作。