现在的位置: 首页 > 综合 > 正文

利用 LotusScript 实现 Microsoft Word 文档在公文流转中的公文留痕

2011年12月28日 ⁄ 综合 ⁄ 共 10129字 ⁄ 字号 评论关闭

Domino 和 Word 的集成

陈 斌, 软件工程师 , IBM
陈 云, 软件工程师, IBM

 

简介: 在大部分的 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 的开发和支持工作。

抱歉!评论已关闭.