摘要: 本文介绍了 Microsoft Outlook 2003 对象模型介,并探讨了如何使用 C# 编程语言生成 Outlook 识别的应用程序和 Outlook 外接程序。
作为对象模型的 Outlook 2003
在将应用程序的功能公开给外部程序方面,Microsoft 有很长的历史。例如,如果项目需要拼写检查功能,您可以利用从 Microsoft_ Word 公开的对象模型。以同样的方式,如果正在生成的应用程序需要 Microsoft_ Outlook_ 2003 提供的功能,则可以利用关联的对象模型。简单地说,Outlook 2003 对象模型允许您与下列各项交互:
· 电子邮件项。
· Outlook 联系人数据库。
· Outlook 日历。
· Outlook 注释和任务。
· Outlook 本身的UI(资源管理器、检查器、命令栏等)。
这显然是所包含功能的子集,但我肯定您有了大概的了解:可以通过关联的对象模型来访问 Outlook 2003 的功能。
Outlook 主互操作程序集 (PIA)
到目前为止,Outlook 的功能是通过一个基于 COM 的进程内服务器 (msoutl.olb) 来公开的。。NET 开发人员希望与这些 COM 类型交互,因此,您需要通过互操作层来这样做。Microsoft Corporation 已经提供了一个 Outlook 2003 附带的"正式的"互操作程序集(即主互操作程序集)。
该程序集已经强命名,并驻留在名称 Microsoft.Office.Interop.Outlook.dll 下面的全局程序集缓存中。要从 Microsoft_ Visual Studio_ .NET 2003 引用该程序集,请从"Add References"对话框访问"COM"选项卡,并选择"Microsoft Outlook 11.0 Object Library"(图 1)。
图 1. 引用 Outlook PIA
注 如果利用 Outlook PIA 的以前版本(或多个版本)生成自定义应用程序,一定要阅读 http://go.microsoft.com/fwlink/?LinkId=30833,该文讨论了某些可能的版本冲突。
有关互操作程序集的简介
任何互操作程序集的最终目标都是要提供外观与体验与原始 COM 类型相似的 .NET 类型。互操作层(结合运行库生成的代理,该代理的术语名称是"运行库可调用包装",即 RCW)处理各种关于封送处理数据类型的详细信息。例如,如果接口方法定义为接受一个基于 COM 的 BSTR 参数,则 .NET 开发人员可以自由传递基于 CLR 的 System.String.
对于每个 COM 类,互操作程序集包含总是带有"–Class"后缀的具体类型,以及名称相同的托管等价项。例如,以下 COM IDL 定义:
coclass MyComObject
|
结果是两个名为 MyComObject 和 MyComObjectClass 的 .NET 类类型。MyComObject 类型只公开 [default] 接口的成员。希望访问其他接口的功能时,需要执行显式转换(这将在后台触发对 IUnknown::QueryInterface() 的调用):
// Create a new MyComObject.
|
另一方面,如果利用 MyComObjectClass 类型,您就能够使用单个对象引用来访问每个接口中的每个成员:
// Create a new MyComObjectClass.
|
实际上,带 –Class 后缀的类型是原始 COM 类型的所有接口方法的联合。假定 Outlook 2003 coclass 最初旨在仅支持单个 [default] COM 接口,则通常可以忽略以 –Class 为后缀的类型,并利用名称相同的 .NET 代理。
注 如果希望更深入讨论 COM 到 .NET 的转换过程,访问 http://blogs.msdn.com/eric_carter/archive/2004/05/06/127698.aspx 将很有帮助。
关于从托管语言与 COM 类型的交互,最后一点与 CLR 垃圾收集器的角色有关。。NET 内存管理模型在本质上是不确定的,因为我们作为开发人员不会准确知道对象将在什么时候被销毁,而只知道它最终会被销毁。另一方面,COM 内存模型在本质上具有很麻烦的确定性,因为我们被迫使用各种 IUnknown::AddRef() 和 IUnknown::Release() 调用来手动调整对 COM 类型的对象内部引用计数(尽管 Visual Basic_ 6.0 试图隐藏这一点)。
针对互操作程序集中的类型进行编程时,将像任何 CLR 引用类型一样对代理类型进行垃圾收集。一旦代理已经被垃圾收集,RCW 将把所有需要的 IUnknown::Release() 调用转发给关联的 COM 对象,并在这时销毁代理。使用该技术,可以确信只要代理在内存中是活动的,则关联的 COM 对象在内存中也是活动的。
如果希望确保 COM 类型以更及时和更可预言的方式被销毁,则可以利用 System.Runtime.InteropServices.Marshal 类型。该类定义了一个静态方法,名为 ReleaseComObject()。只是传递对象引用,关联的 COM 类型将被当场销毁:
using System.Runtime.InteropServices;
|
虽然销毁 COM 类型的想法听起来可能很吸引人,但必须知道在 AppDomain 中的其他 CLR 对象现在无法使用基本 COM 类型。有了这种(危险的)可能性,本文中的示例代码将避免使用 Marshal.ReleaseComObject()。
注 在即将发布的 .NET 平台(Microsoft_ Visual Studio.NET_ 2005,即 Whidbey)的版本中,这个问题已经得到解决。有关进一步的详细信息,请参阅 http://blogs.msdn.com/yvesdolc/archive/2004/04/17/115379.aspx.
Outlook 2003 对象模型
一旦引用了 Outlook PIA,下一个任务就是调查 Microsoft.Office.Interop.Outlook 命名空间中的很多类型(图 2)。
图 2. Microsoft.Office.Interop.Outlook 命名空间
不管类型的大小是多少,好消息是对象模型本身组织得非常好,并利用了常见设计模式。因此,一旦了解如何遍历联系人列表,则遍历收件箱项就会很简单。
其他的好消息是,整个对象模型在帮助文件 (vbaol11.chm) 中有完整的介绍,默认情况下该帮助文件位于 :\Program Files\Microsoft Office\OFFICE11\1033 下(图 3)。
图 3. Outlook 2003 文档
现在,坏消息(取决于您的视点)是帮助系统使用 VBScript 代码示例和成员原型。假定本文没有试图详细介绍 Outlook 2003 对象模型中的每个类型,请您参考该帮助系统来获得完整的信息。下面,让我们来研究某些核心类类型。
Application 类型
第一个要知道的类型被适当地称为"Application",它是层次结构中其他所有对象的根。一旦获得该类型的对象,就能以编程方式控制 Outlook 本身的所有方面。表 1 列出了某些需要注意的(但决不是所有)成员。
表 1.选择 Application 类型的成员
Application 类型的成员 | 基本含义 |
ActiveExplorer() ActiveInspector() | 这些方法分别从当前 Outlook 实例检索 Explorer / Inspector 类型。本文随后描述资源管理器/检查器模型。 |
CreateItem() | 允许通过编程创建新的 Outlook 项。 |
GetNamespace() | 提供对数据存储项的访问。到 Outlook 2003 为止,MAPI 是唯一可以使用的命名空间,它用于访问 Outlook 文件夹组(收件箱、注释等)。 |
Quit() | 终止当前 Outlook 会话。 |
COMAddIns | 该属性允许您在运行时发现插入到当前 Outlook 实例中的外接程序集合。 |
Explorers Inspectors | 这些属性允许获得强类型的 Explorers/Inspectors 集合。 |
获得 Application 类型的确切方式将根据所开发软件的种类而有略微的不同。如果要生成一个合并 Outlook 2003 的自定义应用程序,则要做的所有事情是使用 C# new 关键字创建该类型:
// Create an Outlook Application object. |
另一方面,生成 Outlook 2003 外接程序时(本文随后介绍),将通过名为 OnConnection() 的方法传递 Application 实例:
public void OnConnection(object application, |
除了各种属性和方法以外,Application 类型还定义了在各种环境中触发的很多事件(StartUp、Quit、ItemSend、NewMailEx)。请考虑以下代码片段:
public class MyApp
|
再次,在给定互操作层的角色后,处理基于 COM 的事件的过程看起来与处理 CLR 事件的过程相同。暂时不要理会细节,只需注意 NewMailEx 事件与一个具体的委托(ApplicationEvents_11_NewMailExEventHandler) 一起工作,这个委托可以调用任何接受 System.String 作为其唯一参数,并且不返回任何内容的方法。
Outlook"Item"类类型
一旦有了 Application 类型,就能创建新的 Outlook"项".通过 Microsoft.Office.Interop.Outlook.OlItemType 枚举可以列出可能的项:
public enum OlItemType |
假设您希望通过编程来创建新的 Outlook Task 项。要这样做,请指定 OlItemType.olTaskItem 作为 Application.CreateItem() 的参数:
public static void Main()
|
注意,CreateItem() 的返回值是一般的 OlItemType;因此需要显式地将结果转换为正确的类型(在这里是 TaskItem)。这时,只需要使用类型的公共接口来配置项。一旦执行,将能够在 Outlook 任务检查器中查找任务(图 4)。
图 4. 通过编程生成的任务
尽管 OlItemType 枚举的名称很简单,但表 2 详细列出了 OlItemType 枚举的成员与 Application.CreateItem() 产生的返回类型之间的关系。
表 2.OlItemType enum/Outlook 类类型关系
OlItemType 枚举值 | 所产生的类型 | 基本含义 |
olAppointmentItem | AppointmentItem | 表示单个约会。 |
olContactItem | ContactItem | 表示单个联系人。 |
olDistributionListItem | DistributionListItem | 表示一个通讯组列表。 |
olJournalItem | JournalItem | 表示单个日记项。 |
olMailItem | MailItem | 表示单个电子邮件项。 |
olNoteItem | NoteItem | 表示单个注释。 |
olPostItem | PostItem | 表示其他人可能浏览的公用文件夹中的公告。 |
olTaskItem | TaskItem | 表示单个任务。 |
获得现有 Outlook 项
除了创建新项以外,Outlook 2003 模型还允许获得(并且可能修改)现有项。不管对枚举哪个 Outlook 项感兴趣,基本过程都是:
* 从 Application.GetNamespace() 获得 NameSpace 类型。
* 从 NameSpace.GetDefaultFolder() 获得 MAPIFolder 类型。
* 使用 MAPIFolder.Items 索引器枚举子项。
指定字符串"MAPI"作为 GetNamespace() 的参数时,将收到一个 NameSpace 类型,该类型表示具体的 Outlook 数据存储的抽象级别(目前,"MAPI"是唯一有效的命名空间)。MAPIFolder 类型可以表示给定用户的邮件存储中的任何文件夹(已删除项、收件箱、日记项等)。文件夹选项的完整范围由 OlDefaultFolders 枚举来表示:
public enum OlDefaultFolders |
要请求具体的文件夹,请将 OlDefaultFolders 枚举中的值指定为 NameSpace.GetDefaultFolder() 的参数。请考虑以下代码,这些代码枚举了当前用户的任务集合:
static void Main(string[] args) |
Inspectors 和 Explorers
Outlook 对象模型不仅使您能够访问各种项,还定义了用来对用户界面进行操作的类型。Explorer 类型表示用于显示文件夹内容的窗口。另一方面,Inspectors 表示打开后可查看的单个项。Application 类维护一个由所有 Explorers 和 Inspectors 组成的集合,通过使用适当命名的 Explorers / Inspectors 属性可以获得这些类型:
Application app = new Application(); |
Application 类的 GetActiveExplorer() 和 GetActiveInspector() 方法可以用来获得当前活动的 UI 元素:
Application app = new Application(); |
当您生成自定义的 Outlook 外接程序时,Explorers 和 Inspectors 是很有用的,因为它们让您能够将 UI 小部件附加到现有的 CommandBars 集合中。本文稍后将进一步介绍这方面的情况。
生成 Outlook 识别的应用程序
要重点操作 Outlook 的对象模型(而不是生成奇特的用户界面),第一个示例将利用简单的命令行用户界面。如果希望跟着做,请创建一个新的 C# 控制台应用程序,并命名为 OPine.Unix 用户可能知道,"Pine"是一个很流行的命令行电子邮件实用工具的名称。OPine 将模仿 Pine 的功能子集。具体来说,OPine 将响应以下命令:
* dib:显示收件箱项
* snm:发送新邮件项
* cn:创建新注释
* dn:显示现有注释
* q:退出 OPine
通过响应 NewMailEx 事件,OPine 还能在新邮件到达时通知用户。
注OPine 将利用 ApplicationClass 类型(而不是 Application)来解决一个在随后引用 System.Windows.Forms.dll 程序集时引入的名称冲突。也可以使用如下所示的 C# 别名解决名称冲突:
using OutLookApp = Microsoft.Office.Interop.Outlook.Application; |
但在这种情况下,使用 –Class 类型将不会损害 OPine 示例。
处理"dib"命令
假定已经引用了 Outlook 2003 PIA,下一步是创建一个帮助器类 (OPineHelper),用该类定义一组执行批量处理的静态方法。首先,我们有一个名为 DisplayInbox() 的方法,该方法接受 ApplicationClass 类型作为其唯一参数。DisplayInbox() 的实现将获得当前的 MAPI 命名空间,以便检索收件箱文件夹中的每个 MailItem.在这里,我们将使用 MailItem 类型的各种属性,将接收时间、发件人名称和主题打印到控制台:
public static void DisplayInbox(ApplicationClass o) |
注意,我们将通过 Items 属性所获得的项当作一般 System.Objects,而不是所期望的 MailItem 类型。此外还要注意,我们执行了一个动态检查,以确定当前项是否可以被视为 MailItem(通过 C# 的 as 关键字),以及如果这样我们将与类型的各种属性交互。我们执行该动态检查的理由是 Outlook 收件箱的确可以包含超过 MailItem 类型的项(例如,满足请求)。如果将 foreach 逻辑设置为:
foreach(MailItem item in inboxFolder.Items) |
那么,如果遇到 MailItem 以外的任何内容,就可以收到运行库异常。
在任何情况下,除了 ReceivedTime、SenderName 和 Subject 属性,MailItem 类型还能够访问附件和重要性级别,以及内容的 HTML 表现形式(通过 HTMLBody 属性)。有关这方面的完整细节,请参阅 Outlook 2003 文档。
处理"snm"命令
OPineHelper 的下一个静态方法是 SendNewMail(),该方法负责代表用户创建和发送新的电子邮件。和前面看到的一样,我们将通过 ApplicationClass.CreateItem() 创建新的 MailItem 类型。阅读到这里,以下代码应当很容易理解:
public static void SendNewMail(ApplicationClass o) |
创建 (cn) 和显示 (dn) 注释
假如我们实际需要做的只是重复用来创建新电子邮件和遍历现有电子邮件项的过程,那么随后两个静态方法是很简单的。在以下代码中,请注意由 OlItemType 和 OlDefaultFolders 枚举所指定值:
public static void CreateNote(ApplicationClass o) |
最后接触
这里关心的最后的静态方法只是向最终用户显示一组选项:
public static void DisplayOPineOptions() { Console.WriteLine("***** Welcome To OPine *****"); Console.WriteLine("dib : Display Inbox"); Console.WriteLine("snm : Send New Mail"); Console.WriteLine("cn : Create Note"); Console.WriteLine("dn : Display Notes"); Console.WriteLine("q : Quit"); Console.WriteLine("****************************"); } |
这将包装 OPine 帮助器类的创建过程;现在可以使用它。
实现 Main() 方法
到这里,我们准备实现 Main() 方法,该方法负责执行以下任务:
* 创建 ApplicationClass 类型的实例
* 通过 Console.ReadLine() 获得用户的命令选项
* 接受用户提供的字符串,并执行合适的方法 OPineHelper
给出这些要点后,下面是一个可能的实现:
static void Main(string[] args) |
处理 NewMailEx 事件
我们将添加到 OPine 中的最后一项功能是处理传入新电子邮件的能力。首先,在分配 ApplicationClass 类型之后处理 NewMailEx 事件:
// Create an Outlook application object. |
ApplicationEvents_11_NewMailExEventHandler 委托的目标需要一个类型为 System.String 的参数。该字符串的值表示新的 MailItem 本身的 ID(可以通过 NameSpace.GetItemFromID() 方法来获得 MailItem)。
在后面的事件处理程序中,注意我们使用 System.Windows.Forms.MessageBox 类型来通知用户有新的邮件,所以一定要添加对 System.Windows.Forms.dll 的引用(并使用指令集更新您的文件):
private static void outLookApp_NewMailEx(string EntryIDCollection) |
这就是最后的步骤。现在我们可以执行编译,并对 OPine 进行测试(图 5)。
图 5. 运行中的 Opine
我敢肯定,您可以找到很多方式来扩展和改进 OPine,包括从基于控制台的 UI 移动到图形 UI(通过 Windows 窗体)。尽管我显然知道你们很少生成命令行电子邮件程序,但我希望该示例已经阐明了通过自定义应用程序与 Outlook 交互的过程。
与 Outlook 安全更新的冲突
运行 OPine 时,您肯定知道由 Outlook 启动的以下对话框(图 6)
图 6. Outlook 2003 安全警告
尽管这会干扰最终用户,但该行为是设计造成的。在 Outlook 2003 下面,(选择对象的)选择成员被认为是可能有安全风险的。因而,系统会提示用户输入权限才能继续操作,防止电子邮件蠕虫和病毒使用对象模型干坏事。
注 如果希望阅读关于哪些 Outlook 类型和成员导致该安全提示的文档,请参阅文章 What's New in Microsoft Office Outlook 2003 for Developers?
假如最终用户总是可以通过对安全提示作出"No"的响应来拒绝对 Outlook 的访问,您就能够在自定义应用程序中通过编程使用 Outlook 时自由地使用 try/catch 逻辑。例如,为了避免发生运行库故障,应当对 OPineHelper.DisplayNotes()(以及其余方法)进行如下更改:
public static void DisplayNotes(ApplicationClass o)
|
注 值得注意的是,生成 Outlook 外接程序时,OnConnection() 方法的传入 Microsoft.Office.Interop.Outlook.Application 参数被假设为可信任的,在大多数 情况下,这将阻止安全警报的出现。
使用 Visual Studio .NET 2003 创建 Outlook 外接程序
下一个示例研究如何使用自定义功能来扩展 Outlook 2003.应用程序可扩展性的整个想法是 Microsoft 产品的另一个基石。基本上,诸如Outlook、Word 或 Visual Studio .NET 这样的应用程序都旨在能够让外部厂商或个人通过插入新的对象(假设上述对象实现了正确的接口)来扩展上述功能。
虽然大多数时候您肯定只使用 C# 命令行编译器 (csc.exe) 和 notepad.exe 来生成外接程序,但如果利用 Visual Studio .NET 共享外接程序项目模板,将节省一些键入时间。为了清楚地加以说明,我们将创建一个名为 EMailStatsAddIn 的外接程序。该外接程序将插到 Outlook 2003 的现有 UI 中,并提供以下功能:
* 显示用户在该天/月接收了多少封邮件。
* 显示用户在该天/月发送了多少封邮件。
首先从 New Project 对话框的 Other Projects | Extensibility Projects 文件夹中选择该模板(图 7)。
图 7. 共享的外接程序项目模板
一旦单击 OK 按钮,系统将指引您执行一个五步的向导,以便配置初始的共享外接程序项目。第一个步骤是选择要使用的语言(Microsoft_ Visual C#_ 或 Microsoft_ Visual Basic_ .NET C++)和基本框架(。NET 或基于 COM 的 ATL)。对于我们的示例,我们显然希望 Visual C#.
第二个步骤是选择外接程序的宿主。假定我们只对 Outlook 2003 感兴趣,请取消选中其他所有选项(图 8)。
图 8. 选择所需宿主
步骤三允许您提供当前外接程序的"友好"名称和说明。这些字符串值用于控制外接程序将被宿主外接程序对话框如何注册和显示。请随便输入您认为适合的值。
步骤 4 中显示的两个选项用于指定外接程序是否应当在启动时自动加载到宿主中,以及允许目标机器上的哪些用户访问外接程序。对于 EMailStatsAddIn,我们将同时选中这两个选项(图 9)。
图 9. 加载共享外接程序的选项。
步骤五只用来确认所选项。一旦完成共享外接程序向导,就会发现您已经得到一个包含两个项目的解决方案:
*外接程序本身 (EMailStatsAddIn)
*安装项目 (EMailStatsAddInSetup)
本文稍后讨论安装项目的角色。
引用的程序集
除了标准的 System.dll、System.Data.dll 和 System.XML.dll 程序集以外,共享外接程序还自动引用了一个名为 Extensibility.dll 的程序集。该程序集包含单个命名空间 (Extensibility),该命名空间确切定义了三个类型(参阅表 3)。
表 3.可扩展性命名空间的类型
可扩展性命名空间的类型 | 基本含义 |
IDTExtensibiltity2 | 所有外接程序都必须实现的关键接口。 |
ext_ConnectMode | 枚举,表示将宿主连接到给定外接程序的各种方式。 |
ext_DisconnectMode | 枚举,表示可以将给定的外接程序与宿主断开的各种方式。 |
需要注意的被引用的其他程序集是 Office.dll.虽然该程序集的确定义很多类型(可以通过 Visual Studio.NET 2003 对象浏览器来确认),但最重要的类型必须与用自定义小部件来扩展宿主的 GUI 以便与正在开发的外接程序进行交互有关。在这里,我不会对 Office 对象模型深入讨论太多,这方面的内容请参阅 MSDN 网站上的 online reference.
注意,共享外接程序项目模板不会自动引用 Microsoft.Office.Interop.Outlook.dll 程序集,所以一定要现在通过 Add References 对话框进行该引用。这样做时,请添加对 System.Windows.Forms.dll 的引用,在访问 MessageBox 类型时将需要它。
自由广告区 |
分类导航 |
邮件新闻资讯: IT业界 | 邮件服务器 | 邮件趣闻 | 移动电邮 电子邮箱 | 反垃圾邮件|邮件客户端|网络安全 行业数据 | 邮件人物 | 网站公告 | 行业法规 网络技术: 邮件原理 | 网络协议 | 网络管理 | 传输介质 线路接入 | 路由接口 | 邮件存储 | 华为3Com CISCO技术 | 网络与服务器硬件 操作系统: Windows 9X | Linux&Uinx | Windows NT Windows Vista | FreeBSD | 其它操作系统 邮件服务器: 程序与开发 | Exchange | Qmail | Postfix Sendmail | MDaemon | Domino | Foxmail KerioMail | JavaMail | Winwebmail |James Merak&VisNetic | CMailServer | WinMail 金笛邮件系统 | 其它 | 反垃圾邮件: 综述| 客户端反垃圾邮件|服务器端反垃圾邮件 邮件客户端软件: Outlook | Foxmail | DreamMail| KooMail The bat | 雷鸟 | Eudora |Becky! |Pegasus IncrediMail |其它 电子邮箱: 个人邮箱 | 企业邮箱 |Gmail 移动电子邮件:服务器 | 客户端 | 技术前沿 邮件网络安全: 软件漏洞 | 安全知识 | 病毒公告 |防火墙 攻防技术 | 病毒查杀| ISA | 数字签名 邮件营销: Email营销 | 网络营销 | 营销技巧 |营销案例 邮件人才:招聘 | 职场 | 培训 | 指南 | 职场 解决方案: 邮件系统|反垃圾邮件 |安全 |移动电邮 |招标 产品评测: 邮件系统 |反垃圾邮件 |邮箱 |安全 |客户端 |