使用 Visual C# .NET 生成 Office COM 外接程序
Microsoft Office XP 和 Microsoft Office 2003 都支持一种新的统一的设计结构,这种结构用于生成应用程序外接程序以增强和控制 Office 应用程序。这些外接程序叫做 COM 外接程序。本文逐步讨论了 Office COM 外接程序,并介绍了如何使用 Microsoft Visual C# .NET 生成 Office COM 外接程序。
IDTExensibility2 接口
COM 外接程序是一种进程内 COM 服务器或 ActiveX 动态链接库 (DLL),它实现如 Microsoft 外接程序设计器类型库 (Msaddndr.dll) 中所描述的 IDTExensibility2 接口。所有 COM 外接程序都从此接口继承而来,而且都必须实现其五个方法中的每一个方法。
OnConnection
每当连接 COM 外接程序时,都会激发 OnConnection 事件。外接程序可以在启动时连接、由最终用户连接或者通过自动化来连接。如果 OnConnection 成功地返回,就表明已加载了外接程序。如果返回错误消息,那么宿主应用程序就立即释放其对该外接程序的引用,而且该对象将被销毁。
OnConnection 使用下列四个参数:
- Application — 一个对宿主应用程序对象的引用。
- ConnectMode — 一个指定外接程序连接方式的常量。外接程序可以采取下列几种方式连接:
- ext_cm_AfterStartup — 外接程序由最终用户从 COM 外接程序 对话框启动。
- ext_cm_CommandLine — 外接程序从命令行连接。注意,此方式不适用于生成 Office 应用程序的 COM 外接程序。
- ext_cm_External — 外接程序由外部应用程序通过自动化连接。请注意,此方式不适用于生成 Office 应用程序的 COM 外接程序。
- ext_cm_Startup — 外接程序由宿主在应用程序启动时启动。此行为由注册表中的设置来控制。
- AddInInst — 一个对 COMAddIn 对象的引用,它引用宿主应用程序的 COMAddIns 集合中的此外接程序。
- Custom — 一个包含 Variant 类型值的数组,它可以存储用户定义的数据。
OnDisconnection
当 COM 外接程序断开连接并且在它从内存中卸载之前,将激发 OnDisconnection 事件。外接程序应在此事件中执行所有资源清理操作,并还原对宿主应用程序所做的任何更改。
OnDisconnection 使用下列两个参数:
- RemoveMode — 一个指定外接程序断开连接的方式的常量。外接程序可以采用下列方式断开连接:
- ext_dm_HostShutdown —外接程序在宿主应用程序关闭时断开连接。
- ext_dm_UserClosed — 外接程序由最终用户或自动化控制器断开连接。
- Custom — 一个包含 Variant 类型值的数组,它可以存储用户定义的数据。
OnAddInsUpdate
当注册的 COM 外接程序集发生变化时,将激发 OnAddInsUpdate 事件。换言之,每当安装 COM 外接程序或者从宿主应用程序中删除 COM 外接程序时,都会激发此事件。
OnStartupComplete 和 OnBeginShutdown
当宿主应用程序在忙于向内存中加载自身或者从内存中卸载自身时应避免用户交互,而 OnStartupComplete 和OnBeginShutdown 方法都是在宿主应用程序已离开或正要进入这一状态时被调用的。只有在启动期间已连接了外接程序的情况下才调用 OnStartupComplete,只有宿主在关闭过程中要断开与外接程序的连接的情况下才调用 OnBeginShutdown。
由于在激发这些事件时宿主应用程序的用户界面是完全活动的,因此它们可能是执行某些操作的唯一途径,以其他途径将无法从OnConnection 和 OnDisconnection 中执行这些操作。
COM 外接程序注册
除了正常的 COM 注册外,COM 外接程序还需要向其运行所在的每一个 Office 应用程序注册自身。为了向特定应用程序注册其自身,外接程序应使用其 ProgID 作为项名称在以下位置下创建一个子项:
外接程序可以在此项的位置为好记的显示名称和完整的说明提供值。此外,外接程序应使用一个名为
的 DWORD 值指定所希望的加载行为。此值确定宿主应用程序如何加载外接程序,而且它由下列值的组合组成:
- 0 = Disconnect — 未加载。
- 1 = Connected — 已加载。
- 2 = Bootload — 在应用程序启动时加载。
- 8 = DemandLoad — 只在由用户请求时加载。
- 16 = ConnectFirstTime — 只加载一次(在下次启动时)。
通常指定 0x03 (Connected | Bootload) 这一典型的值。
实现了 IDTExtensibility2 的外接程序还应指定一个名为
的 DWORD 值,以指出外接程序对于不支持用户界面的操作是否安全。值为 0x00 表示 False,值为 0x01 则表示 True。
如何使用 Visual C# .NET 生成 COM 外接程序
如上文所述,Office COM 外接程序是由 Office 应用程序通过 COM 运行时层激活的进程内 COM 服务器。因此,为了在 .NET 中开发 COM 外接程序,外接程序组件需要在 .NET 中实现,然后通过 COM interop 层向 COM 客户端(即 Office 应用程序)公开。
要在 Visual C# .NET 中创建 COM 外接程序,请按照下列步骤操作:
- 在 Visual C# .NET 中,创建一个类库项目。
- 添加一个对实现了 IDTExtensibility2 的类型库的引用。此项的主 interop 程序集已经出现在 Extensibility 名称下。
- 添加一个对 Microsoft Office 对象库的引用。此项的主 interop 程序集已经出现在 Office 名称下。
- 在实现了 IDTExtensibility2 的类库中创建一个公共类。
- 生成该类库之后,将该库向 COM interop 进行注册。为此,需要为此类库生成一个使用强名称的程序集,然后将它注册到 COM interop。可以使用 Regasm.exe 来向 COM interop 注册 .NET 组件。
- 创建注册表条目以使 Office 应用程序可以识别并加载外接程序。
您可以选择完成所有这些步骤,或可以创建类型为共享的外接程序 的 .NET 项目。这将启动“扩展性向导”,该向导可帮助您在 .NET 中创建 COM 外接程序。
“扩展性向导”将创建一个 Visual C# .NET 类库项目,同时创建一个实现了 IDTExtensibility2 接口的 Connect 类。它还会生成实现IDTExtensibility 的空成员的主干代码。此项目具有对 Extensibility 和 Office 程序集的引用。该项目的生成设置中已选中了注册 COM interop。将生成程序集密钥 (.snk) 文件,并在 Assemblyinfo.vb 文件的 AssemblyKeyfile 属性中进行引用。
除类库项目外,该向导还将生成一个安装项目,该项目可用于在其他计算机上部署 COM 外接程序。在需要时可以删除此项目。
分步示例
- 在 Microsoft Visual Studio .NET 的文件菜单上,单击新建,然后单击项目。
- 在新建项目对话框中,展开项目类型下的其他项目,选择扩展性项目,然后选择共享的外接程序模板。
- 键入 MyCOMAddin 作为该外接程序的名称,然后单击确定。
- “扩展性向导”出现后,请按照下列步骤操作:
- 在第 1 页,选择使用 Visual C# 创建外接程序,然后单击下一步。
- 在第 2 页,选择下面的宿主应用程序,然后单击下一步:
- Microsoft Word
- Microsoft PowerPoint
- Microsoft Outlook
- Microsoft Excel
- Microsoft Access
- 在第 3 页上,输入该外接程序的名称和描述,然后单击下一步。
注意:该外接程序的名称和描述出现在 Office 应用程序的 COM 加载项对话框中。 - 在第 4 页,选择所有可用的选项,然后单击下一步。
- 单击完成。
- 在项目菜单上,单击添加引用。单击组件列表中的 System.Windows.Forms.DLL,单击选择,然后单击确定。
- 将下列代码添加到 Connect 类中的名称空间列表中:
using System.Reflection;
- 将下列成员添加到 Connect 类中:
private CommandBarButton MyButton;
- 在 Connect 类中实现 IDTExtensibility2 的成员的代码,如下所示:
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) { applicationObject = application; addInInstance = addInInst; if(connectMode != Extensibility.ext_ConnectMode.ext_cm_Startup) { OnStartupComplete(ref custom); } } public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom) { if(disconnectMode != Extensibility.ext_DisconnectMode.ext_dm_HostShutdown) { OnBeginShutdown(ref custom); } applicationObject = null; } public void OnAddInsUpdate(ref System.Array custom) { } public void OnStartupComplete(ref System.Array custom) { CommandBars oCommandBars; CommandBar oStandardBar; try { oCommandBars = (CommandBars)applicationObject.GetType().InvokeMember("CommandBars", BindingFlags.GetProperty , null, applicationObject ,null); } catch(Exception) { // Outlook has the CommandBars collection on the Explorer object. object oActiveExplorer; oActiveExplorer= applicationObject.GetType().InvokeMember("ActiveExplorer",BindingFlags.GetProperty,null,applicationObject,null); oCommandBars= (CommandBars)oActiveExplorer.GetType().InvokeMember("CommandBars",BindingFlags.GetProperty,null,oActiveExplorer,null); } // Set up a custom button on the "Standard" commandbar. try { oStandardBar = oCommandBars["Standard"]; } catch(Exception) { // Access names its main toolbar Database. oStandardBar = oCommandBars["Database"]; } // In case the button was not deleted, use the exiting one. try { MyButton = (CommandBarButton)oStandardBar.Controls["My Custom Button"]; } catch(Exception) { object omissing = System.Reflection.Missing.Value ; MyButton = (CommandBarButton) oStandardBar.Controls.Add(1, omissing , omissing , omissing , omissing); MyButton.Caption = "My Custom Button"; MyButton.Style = MsoButtonStyle.msoButtonCaption; } // The following items are optional, but recommended. //The Tag property lets you quickly find the control //and helps MSO keep track of it when more than //one application window is visible. The property is required //by some Office applications and should be provided. MyButton.Tag = "My Custom Button"; // The OnAction property is optional but recommended. //It should be set to the ProgID of the add-in, so that if //the add-in is not loaded when a user presses the button, //MSO loads the add-in automatically and then raises //the Click event for the add-in to handle. MyButton.OnAction = "!<MyCOMAddin.Connect>"; MyButton.Visible = true; MyButton.Click += new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(this.MyButton_Click); object oName = applicationObject.GetType().InvokeMember("Name",BindingFlags.GetProperty,null,applicationObject,null); // Display a simple message to show which application you started in. System.Windows.Forms.MessageBox.Show("This Addin is loaded by " + oName.ToString() , "MyCOMAddin"); oStandardBar = null; oCommandBars = null; } public void OnBeginShutdown(ref System.Array custom) { object omissing = System.Reflection.Missing.Value ; System.Windows.Forms.MessageBox.Show("MyCOMAddin Add-in is unloading."); MyButton.Delete(omissing); MyButton = null; } private void MyButton_Click(CommandBarButton cmdBarbutton,ref bool cancel) { System.Windows.Forms.MessageBox.Show("MyButton was Clicked","MyCOMAddin"); }
- 生成并测试该 COM 外接程序。为此,请按照下列步骤操作:
- 在生成菜单上,单击生成解决方案。请注意,生成 COM 外接程序的过程中实际上就向 COM interop 注册了 .NET 类。
- 启动一个您选作外接程序的宿主应用程序的 Office 应用程序(例如,Microsoft Word 或 Microsoft Excel)。
- 外接程序启动之后,将激发其 OnStartupComplete 事件,您会收到一个消息框。请关闭该消息框。请注意,外接程序向标准工具栏中添加了一个新的标题为“My Custom Button”(我的自定义按钮)的自定义按钮。
- 单击 My Custom Button(我的自定义按钮)。该按钮的 Click 事件将由外接程序来处理,而且您会收到一个消息框。请关闭该消息框。
- 退出该 Office 应用程序。
- 退出该应用程序时,将激发 OnBeginShutDown 事件,您会收到一个消息框。关闭该消息框以结束演示。
在应用程序的开发中,我们可能需要开发Office的插件。在VS2003中,我们很容易地开发一个外接程序,利用COM Add-in,在Office系统软件上添加菜单或者工具栏按钮。
http://dotnet.chinaitlab.com/DotNetFramework/527049.html
完整程序参考:
如果想在程序中,更好地控制OutLook,比如说获取所有邮件,所有联系人、发邮件、控制邮件接收、邮件统计。把我们的应用软件和OutLook集成等等,可以参考:
An Introduction to Programming Outlook 2003 Using C#
What's New in Microsoft Office Outlook 2003 for Developers?
http://techedbloggers.net/Topics/Office/Outlook.category