图 1:使用 ILDASM 工具查看互操作程序集的类型信息
如图 1 所示,程序集位于 Microsoft.Office.Interop.Word.dll 中,而接口和公共类则封装在 Microsoft.Office.Interop.Word 命名空间中。Application 公共类已经展开,这样就可以看到,它扩展(按照 C++ 和 C# 用语,为派生)了 Application,并且在 Word 中实现了 ApplicationEvents2_Event 接口。所有这些内容都将在本文后续部分进行详细讨论。
使用 Office XP 主互操作程序集在运行本文包含的示例之前,应该在计算机上安装 Microsoft Office XP Primary Interop Assemblies (PIAs)(英文)。安装完 PIA 后必须将其置于编译器和已完成程序可以访问的位置。有关详细信息,请参阅 Office XP PIA 下载文档中包含的自述文件和.NET Framework Developer's Guide(要阅读它,请单击开始,指向程序,然后指向 Microsoft .NET Framework SDK 并单击 Documentation [文档])中的Assembly Location一文。
本文出于演示目的,将 Office XP PIA 解压缩到以下文件夹:C:Office XP PIAs。然后将其安装到全局程序集缓存 (GAC) 并进行注册。
可通过在命令行键入 C# 编译器的可执行文件名称 (csc.exe) 来调用此编译器。安装并注册 PIA 后,便可使用 /r 选项,象引用其他任何程序集一样在 csc 命令行上对其进行引用。如果 PIA 的位置无法访问,程序将在运行时失败,并生成一个 System.IO.FileNotFoundException 或 System.TypeInitializationException 类型的异常,告知哪个程序集无法加载。
接下来在如何编译和运行 example1.cs一节中,将会介绍如何使用命令行生成 C# 程序和引用 PIA。
本文包含的示例使用三个 Office XP PIA:
Microsoft.Office.Interop.Word.dll Office.dll Microsoft.Office.Interop.Excel.dll 代码演练演示代码示例之前,首先应下载 odc_offcs.exe 文件并将示例程序解压缩到 C:CSOfficeSamples 或您选择的目录中。为便于引用,在下面的所有示例中,都假定示例程序位于 C:CSOfficeSamples 目录中。
下载文档包含五个 Word 2002 示例程序(example1.cs、example2.cs、example3.cs、example4.cs 和 example5.cs)和一个 Excel 2002 示例程序 (excel1.cs)。示例源文件的相应示例生成文件(example1.exe、example2.exe 等)也一并包含在其中,供读者使用。
所有代码示例都作了详细注释。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/) 示例 1:启动 Word Application 对象第一个示例非常简单,只显示如何启动 Word 2002,并使其在几秒内保持打开状态,然后再将其关闭。首先看一看 example1.cs 源文件中的主要代码行。下面的代码片段分配 Application 对象和它的基类对象,但实际上是进行 CoCreateInstance 调用。
Application app = new Application();Application 类的 Quit 方法接受三个参数:
saveChanges、originalFormat 和 routeDocument。这些可选参数可在 Visual Basic 代码中省略,而 C# 中则没有可选参数;所有这三个参数都必须在调用时传递给 Quit。在 C# 中可通过将值 Missing.Value 赋给每个可选变量(用于通知 Quit 方法使用默认行为)可获得同样效果。在本示例中,即表示不保存文档,保留文档的初始格式,并且不进行路由选择。
object saveChanges = Missing.Value;object originalFormat = Missing.Value;object routeDocument = Missing.Value;app.Quit(ref saveChanges, ref originalFormat, ref routeDocument);
请注意,所有这三个参数都标有 ref 关键字。由于这些方法最初是用 Visual Basic 编写的,而默认情况下 Visual Basic 按引用来传递参数。因此,此处也必须按引用来传递参数。
如何生成和运行 example1.cs要运行该示例,首先要生成 examle1.cs 示例。要在 Visual Studio .NET Command Prompt(Visual Studio .NET 命令提示)窗口中生成该示例:
转到 C:CSOfficeSamples 目录或保存该示例的任何目录。如图 2 所示,在命令提示后键入 cd C:CSOfficeSamples 即可。 然后,在图 2 所示的命令提示后键入 csc /r:"C:Office XP PIAsMicrosoft.Office.Interop.Word.dll" example1.cs 生成 example1.cs。(如果 Office XP PIA 保存在其他位置,则需要使用相应值替换下面的驱动器和安装路径:csc /r:驱动器:<安装路径>Microsoft.Office.Interop.Word.dll example1.cs。) 注意:命令行 csc 对 example1.c s 源文件进行编译,生成 example1.exe 可执行文件。在本示例中,所创建的可执行文件将自动保存在 example1.cs 所在的同一文件夹中。
命令行选项 /r 将引用 Microsoft.Office.Interop.Word.dll。如果 Microsoft.Office.Interop.Word.dll PIA(或引用的任何 PIA)所在位置的路径出现错误,程序将在运行时失败,并生成一个 System.IO.FileNotFoundException 或 System.TypeInitializationException 类型的异常,告知哪个组件无法加载。
图 2:使用命令行生成源文件
要运行 example1.exe(与 example1.cs 源文件位于同一文件夹中),双击该程序即可。该示例是一个非常简单的程序,并不具备任何让人感兴趣的功能,现在让我们看一看示例 2。
示例 2:创建新 Word 文档example2.cs 与示例 1 一样,也是使用 Application 对象启动 Word 2002,然后在打开文档的集合(该集合封装在 Application.Documents 属性中)中添加一个新文档。第一个有意义的代码片断在创建新文档时出现的:
<FONT class=90v>object template=Missing.Value;object newTemplate=Missing.Value;object documentType=Missing.Value;object visible=true;_Document doc = app.Documents.Add( ref template,ref newTemplate,ref documentType,ref visible);</FONT>
Add 方法的所有参数都是可选的,因此必须给这些参数指定一个有意义的值或是指定 Missing.Value。在该示例中,由于我们不需要使用或创建模板,并且这只是一个纯文本文档,因此将前三个参数(template、newTemplate 和 documentType)设置为 Missing.Value。由于希望此文档在本示例中可见,因此将参数 visible 设置为true。
您可能会对如何确定是否应将 Boolean 值赋给 visible 对象感到不解。这就是为什么访问 Word 2002 编程文档很重要的原因所在了。如果看一看 Word 2002 对象模型文档中有关 Documents.Add 方法的说明,您会看到以下内容:
Visible 可选的 Variant。设置为 True 将在可见窗口中打开文档。如果该值为 False,Microsoft Word 将打开文档,但将文档窗口的 Visible 属性设置为 False。默认值为 True。
注意:要查看 Word 2002 Visual Basic 文档中的 Documents.Add 方法,可以在 Word 2002 的工具菜单中,选择宏,然后单击Visual Basic 编辑器。处于Visual Basic 编辑器的键盘状态下时,按 F2 键激活对象浏览器或按 F1 键查看帮助。然后搜索Documents或Documents.Add。在 MSDN 上也可以找到类似文档。这样做回避了一个问题:为什么 PIA 期望 Add 方法的参数类型为 object,而 Documents.Add 方法文档却显示类型 Variant?这是因为 Variant 类型被自动封送处理为 .NET Object 对象类型,后者映射为 C# 的 object 类型。在本示例中,参数 visible 将 Boolean 值 true 封装成 object,并将其传递给 Documents.Add() 函数。
下一行重要代码是:
doc.Words.First.InsertBefore使用从 app.Documents.Add() 函数调用返回的文档接口,在文档开始处添加了一些文本。此处没有特别之处。
下面再来看下一段比较让人感兴趣的代码片断,其作用是保存文档:
<FONT class=90v>object fileName = Environment.CurrentDirectory+"\example2_new";#if OFFICEXPdoc.SaveAs2000( ref fileName,#elsedoc.SaveAs ( ref fileName,#endifref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional);</FONT>
首先要注意的一件事就是,保存文件名称的字符串被封装到 fileName 对象中。其次,此代码将在定义了 OFFICEXP 的情况下调用 SaveAs2000 方法,而在未定义 OFFICEXP 的情况下调用 SaveAs 方法。或许您已经猜到,SaveAs 方法签名在 Office 2000 和 Office XP 之间存在差别。
如何生成和运行 example2.cs要生成 xample2.cs,可以在 Visual Studio .NET Command Prompt(Visual Studio .NET 命令提示)窗口中执行以下操作:
在 C:CSOfficeSamples 目录或任何保存 example2.cs 的目录中,在如图 3 所示的命令提示后键入 csc /r:"C:Office XP PIAsMicrosoft.Office.Interop.Word.dll" /d:OFFICEXP example2.cs。(如果 Office XP PIA 保存在其他位置,则需要使用相应值替换下面的驱动器和安装路径:csc /r:驱动器:<安装路径>Microsoft.Office.Interop.Word.dll /d:OFFICEXP example2.cs。)
图 3:使用命令行编译 example2.cs
要运行 example2.exe(与 example2.cs 源文件位于同一文件夹中),双击该程序即可。 示例 3:打开现有的 Word 文档同 Documents.SaveAs 方法一样,Documents.Open 方法签名在 Office 2000 和 OfficeXP 之间也存在差别,因此新名称包装在 #if 声明中。Open 方法和 SaveAs 方法一样简单,如下所示:
<FONT class=90v> object fileName = Environment.CurrentDirectory+"\example3";object optional=Missing.Value;#if OFFICEXP_Document doc = app.Documents.Open2000( ref fileName,#else_Document doc = app.Documents.Open( ref fileName,#endifref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional);</FONT>
帮助中的 Word 2002 Visual Basic 参考以及 MSDN(英文)中有关 Documents.Open 方法的说明记录了这些可选参数。
本示例中比较让人感兴趣的代码是,打开的文档中的文本先被突出显示,然后被剪切:
<FONT class=90v> object first=0;object last=doc.Characters.Count;Range r = doc.Range(ref first, ref last);r.Select();Thread.Sleep (2000);r.Cut();</FONT>
第一个字符和最后一个字符位置的整数值被封装到第一个和最后一个对象,然后传递给 Document.Range() 函数,该函数返回 Select() 函数调用的 Range 对象。这种显式封装是必需的,因为 Range 对象期待引用其参数,并且任何隐式或显式的转换都会将参数改为右值,而右值是不能按引用传递的。本示例使文本突出显示持续两秒钟,而后对文本进行剪切。剪切操作也可以通过以下代码实现:
object first=0; object units = WdUnits.wdCharacter; object last=doc.Characters.Count; doc.Range(ref first, ref last).Delete(ref units, ref last);
如何生成和运行 example3.cs
要生成 example3.cs,可以在 Visual Studio .NET Command Prompt(Visual Studio .NET 命令提示)窗口中执行以下操作:
打开保存 example3.cs 源文件的目录(例如 C:CSOfficeSamples),并在命令提示后键入 csc /r:"C:Office XP PIAsMicrosoft.Office.Interop.Word.dll" /d:OFFICEXP example3.cs。(如果 Office XP PIA 保存在其他位置,则需要使用相应值替换下面的驱动器和安装路径:csc /r:驱动器:<安装路径>Microsoft.Office.Interop.Word.dll /d:OFFICEXP example3.cs。) 要运行 example3.exe(与 example3.cs 源文件位于同一文件夹中),双击该程序即可。 示例 4:使用 Word 公开的事件
本示例涉及的内容要比其他几个多一些,但实际上并不复杂。看起来复杂的主要原因在于标识事件及其处理程序类型的名称长一些。看一看 Office XP 版本的 DocumentOpen 和 DocumentChange 事件处理程序的设置代码:
... #if OFFICEXP ApplicationEvents3_DocumentOpenEventHandler myOpenDoc = new ApplicationEvents3_DocumentOpenEventHandler (MyOpenEventHandler); ApplicationEvents3_DocumentChangeEventHandler myChangeDoc = new ApplicationEvents3_DocumentChangeEventHandler(DocChange); #else ...
这两条语句仅仅是声明事件的事件处理程序。随后的几行代码中,这些处理程序将指定给 Application 对象 app 中的事件:
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)app.DocumentOpen += myOpenDoc; app.DocumentChange += myChangeDoc;
现在就可以使用这两个事件了。调用 Open 方法时,这两个事件将同时引发。依次打开超链接阅读有关 DocumentOpen(英文)和 DocumentChange(英文)方法的文档。
那么,如何知道哪些事件可用及其处理程序的调用方法呢?如果使用 ILDASM 检查 Word 2002 PIA (Microsoft.Office.Interop.Word.dll),会发现在有些类型前面标有绿色倒三角标志。该标志表示成员是一个事件。图 4 显示了 ILDASM 树视图图标的帮助。
图 4:ILDASM 的树视图图标帮助
图 5:使用 ILDASM 查看 Application 对象的事件
图 5 显示了 Application 对象的事件的部分屏幕快照。每一行最左边的标识符是事件名称。冒号右边是事件处理程序的完整限定类型名。例如,DocumentBeforeSave 事件要求有如下类型的处理程序:
Microsoft.Office.Interop.Word.ApplicationEvents3_DocumentBeforeSaveEventHandler
请注意,事件并未告诉我们任何有关事件处理程序签名的信息。因此,需要看一下事件处理程序声明。在 ILDASM 中,如果双击 ApplicationEvents3_DocumentBeforeSaveEventHandler 类型,就会看到类似图 6 显示的内容。
图 6:在 ILDASM 中查看事件处理程序声明
让我们感兴趣的是 Invoke 方法。为事件处理程序编写的函数必须具有此签名。但是如何知道参数的含义及其使用的值呢?这就是 Word 2002 Visual Basic 文档的重要性所在。对于 DocumentBeforeSave 事件,文档(英文)叙述如下:
Private Sub object_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI AsBoolean, Cancel As Boolean)
该文档接下来描述了每个参数的含义。请记住,C# 在默认情况下按值传递参数,而 Visual Basic 在默认情况下按引用传递参数。这就是为什么两个 Boolean 参数在用 ILDASM 显示时后面要跟 & 符号,而在 C# 中使用时则用关键字 ref 标记的原因了。同样,Visual Basic 中的 Subs 在 C# 中被看作返回 void 的方法。因此,DocumentSave 事件的处理程序应类似于如下所示: