打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
使用.Net访问Office编程接口(转)
 

Office with .Net (二) ――― 使用.Net访问Office编程接口

 

在这篇文章里面,我将向大家介绍如何在.Net中访问Office所公开的编程接口。其实,不管是使用哪种具体的技术来针对Office进行开发(比如VSTO,或者用C#编写一个OfficeAdd-in,或者在一个WinForms程序中调用Office的功能,甚至在一个ASP.NET应用的服务器端启动一个Excel进程),只要是基于.Net平台,这篇文章所描述的内容都是有价值的。

 

在这篇文章以及后续的文章中,所有的演示都将基于Office 2003Professional和Visual Studio 2005。使用Visual Studio2005并不代表我们不能在Visual Studio2003中使用这些方法来访问Office编程接口,相反,这篇文章以及后续文章中的几乎所有演示,都能在VisualStudio 2003中完成。笔者使用Visual Studio2005的原因只是因为喜欢它更好的IDE特性。:)

 

一、Office PIA

 

在第一篇文章中曾经说过,Office的编程接口都是通过COM组件公开的,任何访问Office编程接口的程序,实际上都必须要最终调用OfficeCOM组件。如果你是一个刚从事Windows平台开发不太久,一开始就是学习和使用.Net的程序员,也许你又要感到郁闷了。所幸的是,.Net能够让开发人员非常方便的访问COM组件。我会用尽量简洁明了的描述,让大家理解我们在.Net中是如何访问OfficeCOM组件的。

 

(一)Interop Assembly

 

在.Net Framework中,提供了一项叫做COMInterop的技术,这项技术就是专门用于让我们能够在.Net代码中直接访问COM组件的。它的基本原理是,.NetFramework能够自动针对某一个COM组件,帮助开发人员生成一个InteropAssembly(互调用程序集,后面简称IA),IA是一个完全的托管程序集。IA中的名称空间、类、方法等等,都是针对那个COM组件对应的。在我们的.Net程序中,我们可以直接引用这个IA,并且调用里面相关的方法,这时IA就会帮我们再去访问真正的COM组件里面的相应方法。最后的效果就是,在我们自己的应用程序中,只需要调用一个纯粹.Net的IA即可。

 

下面的图片说明了IA是如何帮我们的程序访问到COM组件的。

 

生成一个IA的方法非常简单,当我们在VisualStudio开发环境中添加一个新的COM组件引用时,VisualStudio就会自动帮我们生成一个相应的IA。如下图,我们示范在一个项目中引用MicrosoftXML 5.0组件。

 

当在上图中点击OK按钮,VisualStudio就已经自动为我们生成了一个针对Microsoft XML5.0组件的IA。打开项目目录的obj\debug目录,就能够看到一个名称为Interop.MSXML2.dll的程序集文件,这个文件就是自动生成的IA,并且在项目中,VisualStudio也自动引用了这个IA程序集。如下图。

 

(二)Primary Interop Assembly

 

我们在自己的应用程序中,访问OfficeCOM组件的方法的基本原理,就如同下面所述,都是通过COMInterop,透过IA间接的访问到Office中的COM组件。但是针对Office这个软件,则有一点点特殊的区别,那就是我们不应该自己在VisualStudio中生成一个“自己的”访问OfficeCOM的IA,而需要使用微软提供的“官方的”PIA。

 

PIA的意思可以理解为“官方互操作程序集”,它和IA最主要的区别如下:

1、IA是由开发人员在开发机器上通过向导自动生成的,PIA是由软件厂商(针对Office这个软件而言,就是指微软)提供的;

2、PIA经过了厂商的优化处理,使之更容易被.Net调用;

 

(三)Office Primary Interop Assembly

 

所以,我们都应该使用PIA来访问OfficeCOM组件,而不应该使用IA。那么如何把OfficePIA安装到我们的电脑上呢?

 

如果我们的机器上已经安装了.NetFramework,那么在安装Office时,在安装向导的高级自定义选项中,我们在每个组件(Word、Excel、PowperPoint等)的子选项中,都能看到一个“.NET可编程性支持”,选择安装它,Office2003的安装程序就会自动把PIA安装到我们的计算机上。

 

另外,对于OfficePIA的客户端分发(就是说,给我们软件的用户都统一装上PIA),微软专门提供了一个安装包。可以在http://www.microsoft.com/downloads/details.aspx?FamilyID=3c9a983a-ac14-4125-8ba0-d36d67e0f4ad&DisplayLang=en下载到这个分发安装包。

 

OfficePIA按照Office的各个组件(Word、Excel、PowerPoint、Outlook等),分成多个单独的程序集。比如Word对应的PIA程序集是Microsoft.Office.Interop.Word.dll(程序集里面的类都放在命名空间Microsoft.Office.Interop.Word中),Excel对应的程序集是Microsoft.Office.Interop.Excel.dll(程序集里面的类都放在命名空间Microsoft.Office.Interop.Excel中)。另外,Office公用的一些组件(比如菜单栏)放在一个单独的程序集中:Office.dll(对应的命名空间是Microsoft.Office.Interop.Core)。

 

如果我们的开发机器上已经安装好了OfficePIA,那么当我们通过上面所述的方法,在Visual Studio中引用OfficeCOM组件时,Visual Studio会检测到本机已经安装了OfficePIA,然后,它会直接引用安装好了的PIA,而不会再自动生成一个新的IA。

 

如下图,我们在Visual Studio中添加一个对WordCOM组件的引用(Word在COM组件列表中是“Microsoft Word 11.0 ObjectLibrary”,相似的,Excel、Outlook、PowerPoint的COM组件名称都遵循这个规律)。

 

在上图中点击OK按钮后,在项目管理器中就可以看到,VisualStudio已经帮我们引用了需要引用的组件。实际上,除了我们选择要引用的Word组件外,其他额外但是必需的诸如Microsoft.Office.Core、stdole、VBIDE等组件也已经被自动引用进来了。

 

在上图的Word组件引用上点击鼠标右键,查看它的属性,在它的路径属性中,我们可以看到这个PIA文件其实是在“C:\Windows\assembly\...”目录中,这个目录也就是我们机器上的全局程序集缓存(GAC,GlobalAssembly Cache)所在的目录。这是因为OfficePIA是被安装到机器上的GAC中,所以对OfficePIA的引用会直接指向GAC中的相应文件。

 

二、深入浏览Office PIA

 

如果读者曾经使用过VBA进行过开发(或者使用其他的开发工具诸如VB/VC/Delphi直接调用过Office),那么其实你已经对OfficeCOM接口有了一定的了解,因为在VBA编辑器中所编写的操作诸如Application、Document、Range的代码,其实正是在操作OfficeCOM组件中的Application、Document、Range这些类。

 

我们已经知道,在Office PIA中,已经把OfficeCOM组件进行了封装,所以我们可以预见,对于每一个OfficeCOM组件中的类或者接口,在OfficePIA的程序集中,我们应该都能找到一个对应的类或者接口。接下来,我们就用对象浏览器直接打开OfficeCOM组件,然后再打开OfficePIA,这样我们就可以对照它们,更清楚的理解它们。

 

在VisualStudio中,打开视图菜单中的对象浏览器,然后点击对象浏览器中的添加其他组件按钮,在出现的选择窗口中,选择COM组件中的“MicrosoftWord 11 Object Library”,这时对象浏览器就直接打开了Word2003的COM组件,如下图。

 

在上图所示的WordCOM组件成员列表中,可以看到我选中了Word中的Application类的Quit()方法。Application类可以说是各个Office组件的核心类,不管是Word、Excel、PowerPoint,都存在一个对应的Application类,对应Word、Excel、PowerPoint主程序。如果要在我们的程序中直接打开Word,就需要创建这个Application类的一个实例,如果要关闭掉这个新打开的Word程序,就调用这个新创建的Application对象的Quit()方法。

 

接下来,我们再用对象浏览器打开OfficePIA中的Word所对应的程序集。在前面的操作步骤中,我们已经在项目中引用了Word的PIA,在项目管理器的引用列表中选中Word,点击鼠标右键,选择在对象浏览器中查看,就可以在对象浏览器中打开Word的PIA了。如下图。

 

如果在上图所示的Microsoft.Office.Interop.Word命名空间所包含的类中做一些浏览,相信读者会发现一个很有意思的事情。那就是其实Word的PIA中的类、接口,并不是和Word的COM组件中的类、接口一一对应的。比如,我们在WordCOM组件中能够看到一个叫做Application的类,但是在Word的PIA中,我们只能找到一个叫做Application的接口,和一个叫做ApplicationClass的类。

 

出现这个情况的原因,在于.Net的COM Interop(具体说就是.NetSDK中的TlbImp.exe这个命令行工具)帮我们根据COM组件生成InteropAssembly时,其实是不会一一对照COM组件来生成.Net类和接口的。相反,它会根据一定的规则,来生成对应的.Net类和接口。

 

由于Application是Word编程接口中最重要的部分,所以我具体针对Word中的Application这个接口,把它的转换规则简要的说明一下(实际生成的接口和类比下面描述的要更多,相关的关系更复杂)。首先,WordPIA中会生成一个_Application接口,这个_Application接口基本描述了WordCOM组件中的Application类中的所有操作和属性,然后,WordPIA中还会生成多个ApplicationEvents_Event系列接口(ApplicationEvents2_Event、ApplicationEvents3_Event、ApplicationEvents4_Event接口…我们可以不用管这些具体的细节),这个接口基本描述了WordCOM组件中的Application类中的所有事件。然后,WordPIA中会生成一个Applicatin接口,它实现了_Application接口和ApplicationEvents_Even接口,这样,Application接口就基本描述了WordCOM组件中的Application类中的所有操作、属性、事件等等。最后,WordPIA中生成了一个具体的ApplicationClass类,这个类实现了Applicatin接口。

 

如果你已经被上面那一段描述搞得头昏脑胀,那么只需要记住:在WordPIA中,我们有一个Application接口和一个ApplicationClass类,Application接口描述了对应的WordCOM组件中的Application类的所有成员,而ApplicationClass类是具体的实现类。

 

三、Code WalkThrough:一个.Net WinForms程序

 

终于,在你忍受了N久,勉强看完了上面那些罗嗦的文字之后,总算可以看到一个具体的示范了。我们要用C#写一个Windows应用程序,在这个程序中,启动Word,用代码操作它做一些操作,然后再关闭掉它。

 

首先,我们创建一个新的C#Windows应用程序,然后通过上面介绍过的方法,在项目中引用Word的PIA(在添加引用的界面中,选择COM组件列表中的MicrosoftWord 11 Object Library)。

 

在自动创建的启动窗体上,放两个Button控件,一个叫做btnStartWord,另外一个叫做btnStopWord。我们希望当用户点击btnStartWord时,我们的程序自动启动Word,然后创建一个新的Word文档,然后将其自动保存在磁盘上,当用户点击btnStopWord时,就关闭掉Word。窗体设计视图如下。

 

 

在这个主窗体类的源代码中,我们引用WordPIA的名称空间,我们使用MSWord来替代Microsoft.Office.Interop.Word这个完整的命名空间名称:

 

using MSWord = Microsoft.Office.Interop.Word;

 

在主窗体类的源码中,添加一个类级别的成员,_wordApp是一个Application类型的对象(记住:MSWord.Application是一个接口!):

 

private MSWord.Application _wordApp = null;

 

然后在btnStartWord按钮的点击事件代码中,添加如下代码,代码创建一个新的Word实例,然后显示它:

 

_wordApp = new MSWord.Application();

_wordApp.Visible = true;

 

看到这里,很多人有一个非常大的疑惑,那就是MSWord.Application实际上是一个接口,那么我们怎么可能通过“newMSWord.Application()”来创建一个Word实例呢?难道我们不应该使用“newMSWord.ApplicationClass()”来做吗?毕竟ApplicationClass才是实现Application接口的具体类啊。

 

在这里,OfficePIA为我们提供了一个小小的“cookie”,我们实际上的确可以使用“newMSWord.Application()”来创建一个Word程序实例的,我们只需要知道,OfficePIA会在底下自动帮我们创建一个真正的Word程序实例。

 

接下来,我们在btnStartWord按钮的事件代码中,再添加如下的代码。

 

Object missing = Type.Missing;

Object sFileName = "C:\\Sample.doc";

 

MSWord.Documents docs = _wordApp.Documents;

MSWord.Document doc = docs.Add(ref missing, ref missing, refmissing, ref missing);

doc.SaveAs(ref sFileName, ref missing, ref missing, ref missing,ref missing, ref missing, ref missing, ref missing, ref missing,ref missing, ref missing, ref missing, ref missing, ref missing,ref missing, ref missing);

doc.Close(ref missing, ref missing, ref missing);

 

在上面的代码中,我们通过访问Application的Documents属性,得到一个Documents类,然后通过Documents类的Add()方法,创建一个新文档,并得到对应这个新文档的类型为Document的对象,然后通过Document类的SaveAs()方法将文档保存在磁盘上,最后通过Document类的Close()方法关闭这个新文档。

 

嗯,我知道我其实解释得不够彻底,上面代码中的那些ref、missing之类的东东,到底是什么意思,为什么要用它们,相信不少人都非常迷惑(特别是曾经用VBA或其他语言访问过OfficeCOM组件接口的程序员而言)。这其实牵涉到用C#语言调用Office编程接口的一个“语法兼容”问题。就是说,Office的产品开发组在对编程接口进行设计时,实际上是专门设计为被VBA调用的,所以接口都非常配合VBA的语法,使VBA程序员尽量感到方便。但是由于C#语法和VB语法有很多不同,所以在用C#访问Office编程接口时,就会感到非常的“别扭”。

 

这这里,我只想对上面的代码做如下简要的额外解释:

(1)很多的Office编程接口中的方法,都带了非常多的参数(比如Document.SaveAs()方法有16个参数!!!),而实际上我们调用它们的时候,并不是每一个参数都需要明确给一个特定的值的(比如Document.SaveAs()方法只需要明确给定第一个参数,即保存到哪里),那么对于不需要给定明确值的参数,我们可以直接传一个.Net类库中自带的静态对象:Type.Missing就可以了。

(2)很多的Office编程接口中的方法,其参数都必需传引用,而不能传值,所以,调用这些方法的时候,对于参数都需要加上C#中的ref关键字。比如上面代码中的Document.Add()、Document.SaveAs()、Document.Close()方法,它们的参数都必须传引用,所以每个参数前面都加上了ref关键字。

 

对于使用C#语言调用Office编程接口时,对“语法兼容”问题的更全面的描述,请参看《Officewith.Net(二)之外传―――C#访问Office编程接口时的“语法兼容”问题》。

 

继续为我们的项目添加代码。在btnStopWord按钮的事件代码中,填充下面的代码:

 

Object missing = Type.Missing;

 

_wordApp.Quit(ref missing, ref missing, ref missing);

 

_wordApp = null;

 

GC.Collect();

GC.WaitForPendingFinalizers();

GC.Collect();

GC.WaitForPendingFinalizers();

 

上面的代码通过调用Application.Quit()方法,退出Word程序。更值得关注的部分是如何释放掉Word程序实例。上面的代码用了一个简单但是很有效的方法,让Word程序进程被关闭回收,首先将对象_wordApp重新赋值为null,这样底下的那个WordApplication对象将不再被任何变量引用,最后通过强行调用.NetFramework中的垃圾收集方法,使Application对象能够被垃圾回收器回收掉。(实际上,.NetFramework的垃圾回收器回收的只是OfficePIA的一个包装类对象而已,但是这个包装类对象被回收后,对应Word程序的COM组件对象会发现自己不再被其他任何对象引用,引用计数变为了0,于是,那个COM组件就会被真正释放掉了。)

 

如何保证在自己的应用程序中关闭Office程序其实是一个不小的问题,上面描述的方法并不是100%有效的,对这个话题更完整的描述请参考《Officewith .Net(二)之外传―――“彻底干净的”关闭Office程序》一文。

 

我们的第一个示范程序到这里就已经写完了,现在我们可以运行一下这个程序,然后先点击第一个按钮启动Word,并操作Word创建一个新文档后再保存到磁盘上,接着点击第二个按钮关闭掉Word。

 

(四)总结

 

这篇文档简要描述了如何在.Net中访问Office的编程接口,讲解了OfficePIA的概念和使用方法。从这篇文章可以看出,在.Net中操作Office是非常简单而直接的,微软通过提供OfficePIA,大大简化了.Net程序员的工作。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
vsto下开发wps插件
利用word将PDF转换DOC文件的方法 --电脑高手
Visual Studio 2010特性支持Office|IT168 技术开发
Office组件轻松把PDF文件转成Word文档
C#操作Word中的表格
Microsoft.Office.Interop.Word.
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服