C# Office COM 加载项

笔记哥 / 03-31 / 5点赞 / 0评论 / 396阅读
# Office COM 加载项开发笔记 ## 一、实现接口 IDTExtensibility2 这是实现 Office COM 加载项最基本的接口 添加 COM 引用 Microsoft Add-In Designer 即可 > > > 对应文件 Extensibility.dll 只包含 IDTExtensibility2 接口其中和用到的枚举 ext\_ConnectMode、ext\_DisconnectMode, > > 可以减少模块引用自行复制代码到自己项目中,注意 IDTExtensibility2 不可被混淆 > ⚠ 注意:开发 Office 或 WPS COM 加载项添加 COM 引用时,需要安装对应的套件才能找到相关的 COM 组件,添加 WPS COM 引用时会受到两者安装的先后顺序和管理员权限影响,导致无法添加引用,若 VS 报错无法添加,需要卸载 Office 才能顺利添加。但下文会提到仅需引用其中一套 COM 组件即可同时兼容 Office 和 WPS ```csharp #if BrandName1 namespace BrandName1 // 品牌1 #else namespace BrandName2 // 品牌2 #endif { [Obfuscation] // 不可被混淆 [ComVisible(true)] // COM 组件类可见, 并且类型要设为公开 public [Guid("XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")] // CLSID // [ProgId("BrandName1.OfficeAddIn")] // Office COM 加载项的 ProgID 须与类全名一致 public class OfficeAddIn : IDTExtensibility2 { public void OnConnection( object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) { MessageBox.Show("OnConnection"); // 注册成功的加载项将会在对应应用启动时弹窗 } // 其他 IDTExtensibility2 的接口方法... } } ``` ⚠ 注意:Office COM 加载项须保证类的 [ProgID](https://learn.microsoft.com/en-us/windows/win32/com/-progid--key) 与类全名完全匹配, ProgID 特性未设置时默认使用类的全名,故也无需设置;并且类不可被混淆,被其继承的接口也不可被混淆 > > > ProgID 与产品和对应功能相关,文件关联也会用到,建议名称是 .,故示例中以 BrandName1 为名称空间,OfficeAddIn 为类名,那么 ProgID 就是 BrandName1.OfficeAddIn。为区分品牌,在品牌条件编译中使用不同的名称空间,而不是不同的类名,这样更符合规范,也更好编写注册的代码 > ## 二、注册 Office COM 加载项 COM CLSID 和 Office 产品的注册表都有 HKCU、HKLM 和 64、32位的项,为了提高兼容性,可在这些注册表项下都添加上注册信息 ### 注册 COM 组件 C# 注册 COM 组件一般通过调用 RegAsm.exe 文件来注册,区分位数和运行时版本 > > > %windir%\Microsoft.NET\Framework[64]\_"ver"\_\RegAsm.exe MyCOM.dll /codebase [/u] > RegAsm.exe 作用就是添加注册表项,避免系统缺失该文件,也为了添加日志输出,可自行写注册表实现 ```csharp {HKCU|HKLM}\Software\Classes ProgID ● "" = 'ProgID' CLSID ● "" = 'CLSID' [Wow6432Node\]CLSID\'CLSID' ● "" = 'ProgID' Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29} InprocServer32 ● "" = "mscoree.dll" ● "Assembly" = 'Assembly.FullName' ● "Class" = 'ProgID' ● "CodeBase" = 'Assembly.CodeBase' ● "RuntimeVersion" = 'Environment.Version' ● "ThreadingModel" = "Both" ProgId ● "" = 'ProgID' ``` ⚠ 注意:RegAsm.exe 注册方式会用到反射,如果不将引用到的程序集文件放到同目录下,并且系统未注册 COM 类继承的接口时,会出错导致注册失败。如果注册方式和 RegAsm.exe 一样会用到类型本身,为避免用户未安装 COM 组件相关的应用,需要打包引用到的程序集 ⚠ 注意:同一个 COM 组件项目创建不同品牌的程序集并注册时,如果两个程序集文件名相同、签名相同、版本相同,则会导致两者程序集全名相同,导致系统无法区分。区分方式是三者至少有一个不同,最简单的方式就是条件编译设置不同版本号 ⚠ 注意:为提高兼容性,目标平台选择 AnyCPU 即可兼容 64/32 位系统和软件。作为 COM 组件运行时,是作为被 .NET 虚拟机进程引用的程序集来运行的,只需将目标框架设为 .NET Framework 3.5, 不需要 app.config 文件就可以兼容 3.5 和 4.0,无需编译多个框架版本。支持 .dll 和 .exe 文件,只要是 .NET 程序集就可以,如果是可将自身注册为 COM 组件 exe,那在注册时还是需要 app.config 的 ### 添加到 Office 加载项列表 需要在加载项列表下新建加载项类 ProgID 同名子项,并添加三个必要的注册表键值 ```csharp {HKCU|HKLM}\Software\[Wow6432Node\]Microsoft\Office AddIns 'ProgID' ● FriendlyName = "加载项列表中显示的友好名称" ● Description = "加载项列表中显示的描述" ● LoadBehavior = 3 (启动时连接和加载) ``` > > > 另外还可以添加 CommandLineSafe = 1, 指示命令行操作安全,可能可以减少弹窗警告 > 经过这两步注册示例插件后,启动对应的 Office 应用时,就会弹出消息框,验证注册成功了 ## 三、实现接口 IRibbonExtensibility 这个接口用于在 Office 应用的 Ribbon 中添加自定义 UI 添加 COM 引用 Microsoft Office  Object Library 即可, 是 Office 版本号 > > > 为提高兼容性,可以安装 Office 2007 获取到 12.0 版本的 COM,并将对应的文件 Office.dll 复制到项目目录中,并修改引用为相对文件,避免在其他未安装 Office 2007 的电脑上无法生成。注意此接口也要被加载项类继承,故不可被混淆 > 此接口只有一个 `GetCutsomUI` 的方法,需要返回 XML 格式的字符串 为了代码可读性,建议使用编写和加载 XML 资源文件的方式 并且在 VS 中编写 XML 添加名称空间后在编写元素属性时将会有候选词列表,十分方便 ```xml