RSS

Monthly Archives: 十一月 2005

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

从06财年开始(2005/8),我们IW Team(会有朋友不知道什么是IW吗?)增加了一位同事,专门负责OPS,OPS即Office Professional Solution,如何清晰明了的解释OPS是个什么东东的确是一个令人头疼的问题。用排除法来说的话,凡不是企业信息门户、企业项目管理、即时通讯、内容管理的其他IW解决方案,都可以归类为OPS。其实我更喜欢Office SmartClient这个定义,虽然从范围来说Office SmartClient不足以包含OPS,但是它的定义更清晰。将客户端的Office作为企业应用的前端,通过前端的这些Office智能客户端展现、输入、操作后端的应用系统,我们就可以认为这是一个Office SmartClient应用。

不管叫什么名字,都可以看出微软对于Office开发是越来越看重的。从开发人员的角度,我写了一些针对Office进行开发的文档,希望能够对Office开发人员们有帮助。这里贴出来的是系列文章的第二篇《Office with .Net (二) ――― 使用.Net访问Office编程接口》。

写完这篇文章,终于长吁一口气,整个10月份没有写一篇blog,现在时刻担心开心把俺给踢出博客堂。:)

补充:如果希望应用构建在Office XP上,可以选择使用Office XP PIA,Office XP PIA可以应用于Office XP和Office 2003。点击这里下载Office XP PIA。

 

Posted by on 2005/11/23 in 未分类

5 Comments

Office with .Net 系列之 ――― 在自己的程序中宿主Office

这个《Office with .Net》系列的最终目标和重头肯定是VSTO2005,希望能够尽快写到VSTO2005的部分。

 

Posted by on 2005/11/23 in 未分类

5 Comments

一个简单的SharePoint表单库 + InfoPath应用

这阵子,我和另外几位同事一起,在准备我们部门新的门户站点,当然,我们使用的是SharePoint Portal Server 2003,因为感觉这过程中有一些东东挺有意思,所以记录下来,和大家分享。

新门户的一个需求就是,之前我们部门一直在维护一张很大的Excel工作表,里面记录了很多条的业务信息,我们希望能够将其改造为使用SharePoint表单库来存储和维护这些数据,然后同事就能直接使用InfoPath来填写这些数据,并在之后能很方便的进行修改。

同时,对于这些数据,我们还希望能够非常好的进行汇总和分析,最好能以各种角度,进行统计和图形化展现。

首先,我请负责InfoPath的同事帮忙制作好了InfoPath表单,并将其发布到了我们的新门户的一个表单库中,然后,我在后台的数据库中创建了一个新的Table,并将表单中需要抽取出来进行分析的数据定义成Table中的字段,接着,我对那个sharepoint表单库编写了一个事件处理程序。

这个事件处理程序监控了表单库中四种事件:
新增:当有新的InfoPath表单库被保存到表单库中时,事件处理程序将表单中的数据抽取出来,保存到后台的数据库表中;
修改:当有InfoPath表单被修改时,也需要相应的更新后台数据库中相应的记录;
移动:当用户将一个InfoPath改名时,会触发这个事件,这时事件处理程序也需要更新后台数据库中记录中的相应数据;
删除:当一个InfoPath表单被删除时,相应的数据库表记录也需要被删除。

这样,所有的数据都同时被保存在了后台的数据库表中,剩下的工作只是直接使用sharepoint自带的Office数据透视视图这个WebPart,连接到那个数据库中,以各种数据透视图的方式将数据展现出来,效果非常不错。

工作进行到这里,同事提出了一个新的需求,那就是之前我们已经有许多数据被记录在了那张很长的Excel工作表中,我们当然希望能够将那张工作表上的数据导入到sharepoint表单库中,这样我们就能直接转换到新的平台上继续工作了。

我使用的方法,是首先将Excel工作表中的数据导入到后台的那个数据库表中,利用SQL Server自带的数据导入工具,经过一些字段匹配处理,我将Excel工作表的数据全部导入到了SQL Server数据库表中。然后,我编写了一个小的Console程序,将这些已经存放在SQL Server数据库表中的数据全部转换成InfoPath表单,保存到新门户的表单库中。

这个Console程序的工作原理,只是要根据开始做好的InfoPath表单的Schema,构建出一个正确的XML Document,然后用数据库中的数据填充它,然后将它转换成二进制格式,调用SharePoint对象模型,将这些二进制数据作为文件写到SharePoint表单库中。因为实际上,SharePoint表单库中的InfoPath表单,本质上也就是一些标准的xml文件,我们可以通过SharePoint对象模型,像操作普通文件一样操作它们。

非常方便,不是吗?SharePoint表单库+InfoPath提供了我们一个非常好的表单系统,基于它们,就能为我们的企业很快的构建出方便高效的表单输入、维护、统计分析的应用。

 

Posted by on 2005/11/15 in 未分类

38 Comments

Tags:

SharePoint Portal Server 2003 SP2对文档库事件处理程序所带来的影响

当服务器管理员在SharePoint Portal Server 2003门户服务器上安装了SPS2003 SP2后,可能会发现原本工作正常的文档库事件处理程序突然不工作了,如果打开管理中心的事件查看器,可能还有发现有类似“操作无法完成”的异常信息。

这是因为SPS2003 SP2(实际上,这个影响是从SharePoint Windows Services 2.0 SP2所带来的)更改了原本的文档库事件处理程序的认证方式,但之前,我们编写的文档库事件处理程序可以直接以SPS站点所宿主的应用程序池的账号权限来运行,但在安装了SP2之后,如果没有在事件处理程序中用代码显式的进行帐户模拟,那么事件处理程序将默认没有权限访问SharePoint Object Model。

修正这个影响的方法,就是在我们的事件处理程序代码中显式进行帐户模拟。如果SPS站点所宿主的应用程序池帐户的权限已经足够大,那么我们可以用如下的简单代码来完成这个工作:

WindowsImpersonationContext wic = WindowsIdentity.GetCurrent().Impersonate();
// 事件处理程序代码…
wic.Undo();

这个问题已经被KB 909455所描述。

 

Posted by on 2005/11/15 in 未分类

4 Comments

Tags:

Office with .Net 系列之 ――― 在自己的程序中宿主Office

这个《Office with .Net》系列的最终目标和重头肯定是VSTO2005,希望能够尽快写到VSTO2005的部分。

点击此处查看文章。

 

Posted by on 2005/11/07 in 未分类

5 Comments

Tags:

Office with .Net(二)之外传―――“彻底干净的”关闭Office程序

Office with .Net (二) ――― 使用.Net访问Office编程接口》一文中,已经介绍了使用Office AutomationOffice自动化)技术,在.Net代码中通过Office PIA直接访问Office编程接口。比如,在那篇文章中,我们创建了一个C#编写的WinForms程序,在程序中直接启动Word,用代码操作Word自动完成一些工作,然后再用代码将Word关闭。

 

凡是涉及到使用Office Automation,即通过自定义的代码启动Office,操作Office编程接口完成一些工作(不管是在WinForms程序,或是ASP.NET程序中),都不可避免的会遇到一个问题,就是如何“彻底干净的”将代码启动的Office程序关闭掉。实际上,如果没有处理好这个问题,那么会造成应用程序所在计算机上,相关的Office进程始终无法关闭,而如果应用程序运行在一台服务器上,那么造成的后果也更加严重,甚至可能导致服务器资源耗尽而宕机。

 

一、服务器端场景

 

服务器端Office Automation就是指我们在一个位于服务器端运行的程序中,访问Office编程接口,启动Office程序,操纵Office完成某些自动化操作。比如,在一个ASP.NET程序,或者在一个Windows Service中,都是服务器端Office Automation场景。

 

服务器端Office Automation的第一准则就是:不要在服务器端进行Office Automcation操作!甚至在服务器上进行Office Automcation操作是不被微软所Support的!

 

没错,因为在服务器端进行Office Automcation操作是非常非常危险的行为,Office原本就不是被设计成以无人值守方式运行的,就是说,Office程序在设计的时候,总是默认假定有一个真正的用户坐在计算机前,用鼠标和键盘与Office程序进行交互。而如果我们用代码来操作Office,那么实际上已经打破了这个假定。打破这个假定可能带来哪些问题呢?下面列举了一些常见的问题:

 

1)由于Office总是假定当前有一个真正的“用户”在使用它,所以,它可能在某些时候会主动弹出一些窗口,要求用户与之交互。比如,当某个操作没有成功完成,或发生一些非预见情况时(比如Office要打印却发现没有打印机、要保存一个文件却发现已存在同名文件),Office会显示一个模式窗口,提示或询问用户一些信息,而在哪些时候会出现这些窗口是不能被完全预见的。由于我们的代码不能取消这样的模式窗口,那么当前进程会被完全堵塞,失去响应。

2)作为一个在服务器端运行的组件,必须事先被设计成能够被多个客户端重复使用、开销尽可能少,而Office恰恰相反(因为Office原本就是设计成在客户端被使用),每个Office应用程序都占用大量的资源,也很难被重复使用。

3)大家日常使用Office的时候,应该能够经常看到Office会出现一个“正在准备安装”的对话窗口,这是因为Office引入了一种叫做“首次使用时安装”的安装模式,某些组件有可能在第一次被使用到时才去安装它。而如果在服务器端出现这样的情形,那么服务器的稳定性就很难保证了。

4Office总是假定当前的运行环境中,是一个真实用户的账号身份,但是服务器端Office Automation有时候却是使用一些系统账号(比如Network ServiceIUser_Machine之类的)来运行Office,这时Office很可能会无法正常启动,抛出错误。

 

所以,除非万不得已,不要进行服务器端Office Automation操作!但是,有时候很多事情并不是由程序员决定的,所以还是有不少人铁了心、咬着牙,非得在服务器端做这个操作不可。如果你真的已经下定了决心,并且有信心克服遇到的一切困难,那么下面提供一些服务器端Office Automation的建议,供大家参考。

 

1)尽可能的预防Office主动弹出一些用户交互窗口。比如,修改ApplicationAskToUpdateLinksAlertBeforeOverwritingDisplayAlertsFeatureInstall这些属性的值,都能够预防一些用户交互窗口的弹出。另外,在编写代码时主动进行防御也很重要,比如在保存一个文件之前,先用代码检测一下是否已经有同名文件存在,打开一个文件之前,也用代码先检测一下是否文件确定存在。

2)将运行Office的环境隔离起来。不要直接在ASP.NET代码中创建Office应用程序的实例,否则出现问题以后,IIS都可能宕掉。创建一个单独的应用程序,来进行Office Automation的操作,然后让ASP.NET程序与这个单独的应用程序通讯,间接访问Office的功能。如果有条件,甚至最好将进行Office Automation操作的单独应用程序放在一台单独的服务器上运行,这样如果真的出现异常情况,可以直接重新启动这台服务器而不影响真正业务系统的正常运行。另外,让那个单独的应用程序使用一个特定的账号运行(比如新创建并设置好的一个可以进行客户交互的账号)。

3)最好创建一个单独的守护进程,检测是否Office没有被正确关闭,如果发现这样的情况,在守护进程中直接关闭掉Office相应进程。

 

二、在代码中关闭Office应用程序

 

当我们在.Net代码中访问Office编程接口时,COM Interop在底下会创建一个RCWRuntime Callable Wrapper,运行时远程访问包装器),来维护对Office COM组件的引用。为了让Office能够被正常关闭,关键就是要在代码中释放掉对Office 相关对象的引用。

 

下面介绍了多种保障措施,让Office应用程序能够被正常关闭,在某些情况下,使用最简单的一种方式即可,而在某些情况下,则可能需要将多种方式综合起来使用。

 

0、记得调用Application.Quit()方法

 

呵呵,还真有程序员忘记调用这个方法来退出Office应用程序,不管最后用哪种方法保障关闭Office,却忘记调用这个Quit()方法,那什么都是白搭。

 

1、让垃圾回收完成所有工作

 

由于.Net Framework提供了垃圾回收器来进行内存的自动管理,所以原理上,只要我们的代码中释放掉对Office相关对象的引用(将其赋值为null),那么垃圾回收最终会将这个对象回收,那时RCW会相应的释放掉Office COM组件,使Office被关闭。为了保证关闭的即时性,我们最好主动调用垃圾回收,让垃圾回收立即进行。

 

Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();

// 进行某些操作

Object missing = Type.Missing;

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

wordApp = null;

 

GC.Collect();

GC.WaitForPendingFinalizers();

GC.Collect();

GC.WaitForPendingFinalizers();

 

在大部分情况下,这种方法已经可以让我们的代码释放掉对Office的引用,使Office被关闭掉。

 

2、调用System.Runtime.InteropServices.Marshal.ReleaseComObject()方法

 

ReleaseComObject()方法可以使RCW减少一个对COM组件的引用,并返回减少一个引用后RCWCOM组件的剩余引用数量。我们用一个循环,就可以让RCW将所有对COM组件的引用全部去掉。

 

先创建一个单独的方法,释放一个Office相关对象的所有引用。

 

private void ReleaseAllRef(Object obj)

{

try

{

    while (ReleaseComObject(obj) > 1);

}

finally

{

obj = null;
}

}

 

然后,调用这个ReleaseAllRef()方法即可。

 

Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();

// 进行某些操作

Object missing = Type.Missing;

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

 

ReleaseAllRef(wordApp);

 

GC.Collect();

GC.WaitForPendingFinalizers();

GC.Collect();

GC.WaitForPendingFinalizers();

 

3)明确单独声明和释放每一个中间对象变量

 

中间对象变量就是指代码中直接通过一个对象的属性得到的一个对象,不单独声明它,而再次直接使用它。比如:

 

Document doc = wordApp.Documents.Add(…);

 

上面的代码中,wordApp.Documents这个属性实际是一个Microsoft.Office.Interop.Word.Documents类型的对象,但是上面的代码没有单独声明这个对象,而是直接使用了它的Add()方法。如果要单独声明它,则需要更改成如下:

 

Documents docs = wordApp.Documents;

Document doc = docs.Add(…);

 

在使用完这些对象后,使用(2)中所描述的方法,再一一释放掉它们。

 

doc.Close(…);

ReleaseAllRef(doc);

ReleaseAllRef(docs);
wordApp.Quit(…);

ReleaseAllRef(wordApp);

 

三、最后的总结

 

这篇文章的标题是《“彻底干净的”关闭Office程序》,之所以在“彻底干净的”这个修饰上打上引号,原因就是其实是没有任何一劳永逸的、100%有效的方法,关闭掉Office程序。任何进行了Office Automation操作的代码,都必须被仔细测试和评估,将其对我们的程序所造成的影响,降到最低。

 

Posted by on 2005/11/04 in 未分类

7 Comments

Tags:

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

从06财年开始(2005/8),我们IW Team(会有朋友不知道什么是IW吗?)增加了一位同事,专门负责OPS,OPS即Office Professional Solution,如何清晰明了的解释OPS是个什么东东的确是一个令人头疼的问题。用排除法来说的话,凡不是企业信息门户、企业项目管理、即时通讯、内容管理的其他IW解决方案,都可以归类为OPS。其实我更喜欢Office SmartClient这个定义,虽然从范围来说Office SmartClient不足以包含OPS,但是它的定义更清晰。将客户端的Office作为企业应用的前端,通过前端的这些Office智能客户端展现、输入、操作后端的应用系统,我们就可以认为这是一个Office SmartClient应用。

不管叫什么名字,都可以看出微软对于Office开发是越来越看重的。从开发人员的角度,我写了一些针对Office进行开发的文档,希望能够对Office开发人员们有帮助。这里贴出来的是系列文章的第二篇《Office with .Net (二) ――― 使用.Net访问Office编程接口》。

点击这里查看文章。

写完这篇文章,终于长吁一口气,整个10月份没有写一篇blog,现在时刻担心开心把俺给踢出博客堂。:)

补充:如果希望应用构建在Office XP上,可以选择使用Office XP PIA,Office XP PIA可以应用于Office XP和Office 2003。点击这里下载Office XP PIA。

 

Posted by on 2005/11/03 in 未分类

9 Comments

Tags: