当前位置: 美高梅集团手机版 > 美高梅集团 > 正文

让大家理解我们在.Net中是如何访问Office,但是任

时间:2020-02-05 16:13来源:美高梅集团
准备工作 在这篇文章里面,我将向大家介绍如何在.Net中访问Office所公开的编程接口。其实,不管是使用哪种具体的技术来针对Office进行开发(比如VSTO,或者用C#编写一个OfficeAdd-in,或

准备工作

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

首先,请确保在你的Windows系统中已经安装并配置好了一个典型的WAMP环境。由于Interop纯粹是一个Windows的特性,我们将在Windows平台下搭建Apache和PHP。在这个实例中,我使用了EasyPHP 14.1,这款软件安装和配置都十分容易。

 

接下来,我们要安装Microsoft Office。版本不是严格要求的。我正在使用的是Office2013专业版,但是任何2007之后的Office版本都应该可以使用。

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

我们然后需要去确保开发Interop应用的库是安装好的。为了确保这个,我们可以打开资源管理器,然后找到assembly,我们将会看到下面安装好的PIAs分支:

 

我们可以看到一个 Microsoft.Office.Interop.Word 条目。 这就是我们在这个示例中将要使用的 PIA。请特别注意它的“名称”,“版本”和“公钥标记”。我们将要在PHP脚本中用到它们。

一、Office PIA

在这个目录中,我们还可以看到其它用于编程的PIAs。

 

如果这个列表没有包含 Microsoft.Office.Interop 的整个包,我们可以重新安装Office并且在安装中包含PIA;我们也可以手动下载安装这个包。安装的详细步骤可以查阅这个MSDN页面。

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

注意:只有Microsoft Office 2010 PIA Redistributable 可以被单独下载安装。这个包中的 PIA 版本是14.0.0。版本15只能通过安装Office获得。

 

最后,我们需要在文件 php.ini 中启用 PHP 扩展 php_com_dotnet.dll,并且重启服务器。

(一)Interop Assembly

现在我们可以开始编程了。

 

HTML表单

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

由于该demo主要关注与后台的处理,所以我们这里就用一个简单的HTML表单做前台的展示,看起来应该是这样的:

 

我们有一个文本框用于输入“Name”,一个“Gender”的单选按钮组,一个“Age”的域值控制还有一个文本域来写“Message”,最后,还需要一个“Submit”按钮。

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

将该文件命名为“index.html”,保存在虚拟主机的根目录下,这样我们可以直接通过URL访问该文件,例如:

 

后台

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

后台的PHP文件是我们所要讨论的核心部分。我先将代码贴到下面,接下来在一步一步的进行解释

 

visible = true; $fn = __DIR__ . '\template.docx'; $d = $w->Documents->Open; echo "Document opened.
"; $flds = $d->Fields;$count = $flds->Count;echo "There are $count fields in this document.
";echo "

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

  • Mappig field $index: $key with value $value

 

"; echo "Mapping done!

(二)Primary Interop Assembly


 

";echo "Printing. Please wait...
"; $d->PrintOut;echo "Done!"; $w->Quit;$w=null; function setupfields; $mapping[0] = 'gender'; $mapping[1] = 'name'; $mapping[2] = 'age'; $mapping[3] = 'msg'; $mapping[4] = 'printdate'; return $mapping;}

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

在设置完用来获取表单中传过来的值的变量$inputs之后,我们要创建一个虚拟值用来存放printdate——我们稍后会讨论为何需要这个变量——现在,我们看到这4行比较关键的代码:

 

$assembly = 'Microsoft.Office.Interop.Word, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c';$class = 'Microsoft.Office.Interop.Word.ApplicationClass'; $w = new DOTNET;$w->visible = true;

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

在PHP中的COM操纵需要在一个assembly里请求一个class的实例。在我们的案例中,我见将要操作Word。如果考虑到我们上一个截图中展示的代码,我们将能够构造出一个完整签名的Word PIA:

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

“Name”,“Version”,“Public Key Token”是在当我们浏览“c:Windowsassembly”时所展示的信息 “Cultrue”总是neutrual的。

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

调用类编译后的文件后缀名为通常为ApplicationClass.

 

通过设置下面两个步骤,我们可以初始化一个word对象:

(三)Office Primary Interop Assembly

首先,word对象可以保存在后台或者通过将visible属性设置为true,使它在前台展示出来。

 

然后,我们打开将要处理的文档,把它实例化为一个$d变量。

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

在文档对象中,基于html表单的文本来添加文档的内容,这里可以设置一些参数。最不好的方式是对php页面上所有内容进行硬编码,然后将它们添加到word对象中。我强烈建议不采用此种方式,原因有:

 

1 代码没有灵活性,php内容的任何变化都需要重新修改脚本;2 违反了控制层、展示层的分离;3 如果需要设置word内容的格式,这种方式大大增加了代码行数,并且以编程的方式来修改样式是非常麻烦的。

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

另一种方式是使用“搜索-替换”。PHP内置的这种功能非常强大。我们可以创建一个word文档,在那些需要被替换的占位内容周围放置一些分隔符。比如,我们创建一个文档包含如下内容:

 

{{name}}

另外,对于Office PIA的客户端分发(就是说,给我们软件的用户都统一装上PIA),微软专门提供了一个安装包。可以在下载到这个分发安装包。

在PHP中,我们只需使用从表单提交中获取的“Name”值来替换。这种方式避免了第一选项中的那些缺点。我们只需要找到正确的分隔符,在这个例子中,除了使用的模板是word文档,我们更像是做一个模板渲染。

 

第三个选项是我的建议,并是Word中的高级主题。我们将用域来表示占位符,在我们的PHP代码中,我们会直接更新了相应的表单值的字段。

Office PIA按照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)。

这种方法灵活,快速,符合Word的最佳实践。这也避免了文件的全文搜索,这有助于提高性能。请注意,此选项有它的缺点了。

 

总之,自从首次亮相,Word从来没有支持命名索引的字段。尽管我们对于我们在Word文档中创建的字段提供了一个名字,我们还是要用数字下标来访问每个字段。这也解释了为什么我们要使用专用的功能做表单字段的字段索引和名之间的映射手册

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

学习如何在word文档中插入字段,请参阅相关 Word 帮助主题和手册。对于这个demo,我们有一个具备5个MERGEFIELD字段的文档。此外,我们将文档和PHP脚本放在一个目录下,以方便获取。

 

请注意,printdate字段并没有一个相应的窗体字段。这就是为什么我们要在$inputs数组中添加一个假的printdate作为key。没有这个key,脚本依然可以执行,但是会有提示说明$inputs数组中不存在索引printdate。

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

在使用表单数据更新完字段的值之后,我们将会使用下面的命令打印文档:

 

$d->PrintOut();

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

PrintOut方法有几个可选参数,这里,我们使用最简单的格式。这将会给链接到我们Windows机器的默认打印机打印一份副本。

 

我们可以通过使用PrintPreview进行打印预览。在纯自动化的情景下,当然,我们直接使用PrintOut进行打印。

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

在退出word应用程序之前,我们还需要稍作等待,因为打印工作需要时间来完全退出后台。如果没有delay,$w->Quit将会立刻得到执行,并且打印工作立刻被终止。

 

最终,我们调用 $w->Quit 来选择通过我们的PHP脚本调用关闭word应用程序。这里提供的唯一参数是用来指明我们是否希望在退出前保存更改。我们确实对文档进行了更改,但是我们不希望保存它们,因为我们希望能为其他用户的输入提供一份干净的模板。

二、深入浏览Office PIA

当我们完成编码之后,我们可以加载表单页面,输入一些内容并提交表单。下面的截图展示了PHP脚本的输出,同时更新了Word文档:

 

提高编码速度并更好的理解PIA

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

PHP是一种弱类型的语言。一个COM对象是一种Object类型。在我们的PHP编码过程中,在一个对象中我们无法使用代码自动提示和完成功能,在一个Word应用,一个文档甚至一个字段中同样如此。我们不知道它有哪些特性,或者它支持哪些方法。

 

这将大幅度的降低我们开发的速度。为了使开发更快,首先,我建议我们在c#中开发功能应当迁移至我们的PHP编码。我推荐一款免费的C# IDE 叫做"#develop",你可以在这里下载。相比VS,我更喜欢这一款软件,因为#develop体积更小,更简洁,响应更快。

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

C#代码迁移至PHP一点也不吓人。先让我展示一些C#的代码:复制代码 代码如下: Word.Application w=new Word.Application();w.Visible=true; String path=Application.StartupPath+"\template.docx"; Word.Document d=w.Documents.Open as Word.Document; Word.Fields flds=d.Fields;int len=flds.Count; foreach { f.Select(); int i=f.Index; w.Selection.TypeText;}

 

我们可以看到,C#的代码和我们之前展示的PHP的代码基础一模一样。由于C#是一种强类型语言,所以我们可以看到有些类型转换的语句,我们不得不显性的给我们的变量赋一种类型。

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

有了代码的类型,我们可以尽情的享受代码的自动提示和代码自动完成功能,这样我们开发的速度将有大幅度提高。

 

另一种可以给予我们更快速度进行PHP开发的方式是使用Word的宏命令。我们先操作一遍我们需要重复的动作,然后用一个宏将其录制下来。一个宏其实是Visual Basic,同样也可以非常容易的翻译成PHP。

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

最重要的是,Office PIA微软官方文档,特别是文档中对于每个Office应用的命名空间,总会是我们所需要的最想进的参考。比较常用的3个应用如下:

 

Excel 2013: Word 2013: PowerPoint2013:

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

结语

 

在这篇文章中,我们演示了如何使用PHP COM库和Microsoft Office Interop功能来倩影一个Word文档。

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

Windows和Office在我们的日常生活中可以说是被广泛的使用。能够知道和了解Office或者Windows的强大之处还有PHP,对于任何一个在Windows平台上进行PHP开发的程序员都是十分必要的。

 

使用PHP的COM扩展,掌握这一组合的大门就被打开了。

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

如果你对于这部分的编程比较感兴趣,请留下你的评论,我们将会考虑在这个话题上写更多的文章。我十分期待更多现实生活的应用开发能使用这种方式。

 

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

 

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

 

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

 

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

编辑:美高梅集团 本文来源:让大家理解我们在.Net中是如何访问Office,但是任

关键词: