利用 LotusScript 實現 Microsoft Word 文檔在公文流轉中的公文留痕

 

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 star2 stars3 stars4 stars5 stars 平均分 (共 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 中演示公文留痕的步驟和截圖:

  1. 在 Notes Client 中打開 WordTest.nsf

    圖 1. 在 Notes Client 中打開 WordTest.nsf
    圖 1. 在 Notes Client 中打開 WordTest.nsf

  2. 在視圖中點擊“新建”按鈕新建一個發文文檔。

    Figure xxx. Requires a heading
    Figure xxx. Requires a heading

  3. 在視圖中點擊“新建”按鈕新建一個發文文檔。

    圖 2. 新建 Word 文檔
    圖 2. 新建 Word 文檔

  4. 輸入標題,點擊“起草正文”按鈕後,將會新建一個 Word 文檔,在此文檔中起草的發文內容。

    圖 3. 切換到 Notes 客戶端
    圖 3. 切換到 Notes 客戶端

  5. 點擊確定後,系統將自動保存 Word 文檔並以附件形式保存在隱藏的 Body 域中。
  6. 起草可以多次,再次點擊“起草正文”按鈕可以繼續在原來的草稿中編輯。
  7. 起草完成後,點擊“提交審覈”按鈕,這樣正文的狀態被置爲“審覈中”,同時,隱藏“起草正文”和“提交審覈”按鈕,顯示“審覈正文”和“審覈完畢”按鈕。

    圖 4. 提交審覈顯示“審覈正文”和“審覈完畢”按鈕
    圖 4. 提交審覈顯示“審覈正文”和“審覈完畢”按鈕

  8. 點擊“審覈正文”按鈕進入審覈過程,這個過程可以由多人完成,在此過程中,任何人對正文的修改痕跡都會被保留,包括被誰修改的也會保留,同時可以看到相應的菜單已經被隱藏。

    圖 5. 進入審覈過程
    圖 5. 進入審覈過程

  9. 審覈完成後,點擊“審覈完畢”按鈕,則正文將被置於只讀狀態,表示這是最終修訂過的版本了。同時,原來的“審覈正文”和“審覈完畢”按鈕被隱藏,顯示“查看正文”按鈕。

    圖 6. 查看正文
    圖 6. 查看正文

  10. 查看正文時,如果選擇顯示修訂信息的方式,則內容和最後審覈完畢前的狀態相同,都是直接將修改痕跡顯示出來,只是不能再次修改了,如果選擇隱藏修訂信息的方式,則所有的修改痕跡會被合併然後顯示。

    圖 7. 查看正文
    圖 7. 查看正文


結束語

本文通過這個示例詳細展示瞭如何利用 LotusScript 來實現 OA 系統中常用的公文留痕功能,希望能夠拋磚引玉,以此爲基礎,從而實現更爲複雜的留痕功能。



下載

描述 名字 大小 下載方法
本文代碼下載 WordTest.zip 41 KB HTTP

關於下載方法的信息


參考資料

學習

討論

作者簡介

陳斌是來自 IBM CSTL 的高級軟件開發工程師,現在負責 Lotus Domino for IBM i 的開發、支持以及團隊領導工作。

陳雲是來自 IBM CSTL 的軟件開發工程師,現在從事 Lotus Domino for IBM i 的開發和支持工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章