简介:本资源是一份面向Delphi开发者的技术实践包,聚焦Office插件(特别是Word)开发场景,解决COM接口调用、AddIn生命周期管理、Ribbon自定义及事件响应等核心问题。资源共7个文件,含4个JavaScript脚本(用于前端交互与时间/页脚逻辑)、1个GIF动图(可能展示UI效果)、1个HTML主文档(含完整开发教程与说明)、1个CSS样式文件,整体仅15KB,轻量易读,适合初学者快速上手或中阶开发者查缺补漏。已有244人学习下载,反映出其在小众但高价值的Delphi Office开发领域具备实用参考性。读者可直接获取可运行的项目结构雏形、关键接口实现范例(如IDTExtensibility2)、VCL与Office对象模型交互的代码片段,以及基于delphioffice或consonantevw相关组件的集成思路,为实际开发提供即插即用的逻辑框架与调试起点。
1. Delphi 开发 Office 插件:为什么还在用 VCL 做 Add-in,而不是 Electron 或 .NET?
你可能刚在公司内部系统里看到一个老项目——Excel 表格右键菜单里多了一项「生成合规报告」,双击弹出的却是 Delphi 写的窗体,带 TButton、TStringGrid 和一串蓝色边框的 TEdit;后台调用的是本地 COM 接口读取 Excel Range,再用 ADODB 连接 SQL Server 写入审计日志。这不是怀旧,是现实:大量金融、电力、军工类政企系统仍在用 Delphi 开发 Office Add-in,不是因为 Delphi 多先进,而是因为——它能零依赖打包进单个 EXE、不需 .NET Framework 安装、兼容 Windows 7 SP1 起所有 Office 版本(2007–2021),且 VCL 对 Office COM 的封装比 C++/ATL 更稳。
标题里的consonantevw不是拼写错误,而是 Consonant 公司早期发布的Consonant Office View组件集(非开源,已停更),它把IDTExtensibility2、IRibbonExtensibility、ICommandBar等 COM 接口封装成 Delphi 可直接拖拽的 TOfficeAddIn、TRibbonTab、TOfficeCommand 组件,省去手写 IDispatch、类型库导入、线程套间(STA)配置等黑匣子操作。而delphioffice是社区维护的轻量级替代方案(GitHub 上约 320 star),专注 Excel/Word 自动化,不支持 Ribbon,但胜在无第三方 DLL 依赖、源码全公开、适配 Delphi 10.4–12。
适合谁?不是想学新潮 Web Add-in 的前端工程师,而是:
✅ 需维护十年以上 Delphi 老系统的现场工程师;
✅ 要给客户交付「双击即用、不弹安装向导」的 Office 工具的 ISV;
✅ 拒绝部署 .NET Runtime 或 Node.js 的离线工业环境;
✅ 已有 Delphi 数据处理模块(如报表引擎、加密组件),只需嫁接到 Office 容器。
这不是技术选型的妥协,是特定场景下的确定性解法——当你面对一台没网、没管理员权限、只装了 Office 2010 的工控机时,Delphi Add-in 往往是唯一能跑起来的方案。
2. 从零搭建 Delphi Office Add-in:注册表 + COM + VCL 三步闭环
Delphi 开发 Office 插件的本质,是让 Office 进程(EXCEL.EXE / WINWORD.EXE)通过 COM 加载你的 DLL,并调用其暴露的IDTExtensibility2接口完成初始化。整个链路不经过 .NET 或 VSTO,纯原生 Win32,因此必须亲手处理注册表项、线程模型、类型库注册。下面以 Excel Add-in 为例,用 Delphi 11 Alexandria 实现最小可运行版本(不依赖任何第三方组件)。
2.1 创建 COM 服务单元:实现 IDTExtensibility2 的核心四方法
新建一个 ActiveX Library 项目(File → New → Other → ActiveX → ActiveX Library),保存为ExcelAddIn.dpr。然后添加一个 Automation Object(File → New → Other → ActiveX → Automation Object),命名为TExcelAddIn,Class Name 设为ExcelAddIn,Instancing 选MultipleInstances,Threading Model 选Both(关键!Office 主线程是 STA,但部分回调可能在 MTA,设 Both 避免跨套间调用失败)。
注意:不要勾选「Generate Type Library」——Delphi 自动生成的 TLB 与 Office 的 IDispatch 绑定常有 GUID 冲突,我们手动写 IDL 更可控。
在生成的ExcelAddIn.pas中,删掉默认接口,手动实现IDTExtensibility2(该接口定义在Office_TLB.pas,需先导入 Office 类型库):
unit ExcelAddIn; interface uses ComObj, ActiveX, Office_TLB, Excel_TLB, SysUtils, Classes; type TExcelAddIn = class(TAutoObject, IDTExtensibility2) procedure OnConnection(const Application: IDispatch; ConnectMode: ext_ConnectMode; const AddInInst: IDispatch; var custom: PSafeArray); safecall; procedure OnDisconnection(DisconnectMode: ext_DisconnectMode; var custom: PSafeArray); safecall; procedure OnAddInsUpdate(var custom: PSafeArray); safecall; procedure OnStartupComplete(var custom: PSafeArray); safecall; procedure OnBeginShutdown(var custom: PSafeArray); safecall; end; implementation uses ComServ; { TExcelAddIn } procedure TExcelAddIn.OnConnection(const Application: IDispatch; ConnectMode: ext_ConnectMode; const AddInInst: IDispatch; var custom: PSafeArray); begin // 保存 Application 引用,后续用于操作 Excel FExcelApp := Application as _Application; // 注册自定义命令栏(旧式菜单)或 Ribbon(需额外 XML) if ConnectMode in [ext_cm_Startup, ext_cm_AfterStartup] then RegisterCommandBar; end; procedure TExcelAddIn.OnDisconnection(DisconnectMode: ext_DisconnectMode; var custom: PSafeArray); begin FExcelApp := nil; end; procedure TExcelAddIn.OnAddInsUpdate(var custom: PSafeArray); begin // Add-in 列表变更时触发(极少用) end; procedure TExcelAddIn.OnStartupComplete(var custom: PSafeArray); begin // Office 完全加载后触发,此时可安全调用 Workbook.Open 等耗时操作 end; procedure TExcelAddIn.OnBeginShutdown(var custom: PSafeArray); begin // Office 即将退出,清理资源 end; initialization TAutoObjectFactory.Create(ComServer, TExcelAddIn, Class_ExcelAddIn, ciMultiInstance, tmBoth); end.关键点说明:
FExcelApp: _Application是全局变量,必须声明为private并在OnConnection中赋值,否则后续调用Workbooks.Add会报Invalid interface;tmBoth线程模型是血泪经验:若设tmApartment,当 Excel 在后台执行宏时回调OnBeginShutdown,可能因套间不匹配导致 Access Violation;ext_ConnectMode枚举值需引用Office_TLB单元,不能手写数字——Delphi 11 导入的Office_TLB.pas中ext_cm_Startup = 2,但不同 Office 版本可能偏移,必须用符号常量。
2.2 手动注册 COM 组件:绕过 regsvr32 的注册表硬编码
Delphi 生成的 DLL 默认用regsvr32注册,但 Office Add-in 要求注册表路径精确到HKEY_CURRENT_USER\Software\Microsoft\Office\Excel\Addins\YourAddInName,且必须包含LoadBehavior=3(表示开机自动加载)、FriendlyName、Description等键值。regsvr32不会写这些,必须自己实现DllRegisterServer。
在ExcelAddIn.dpr的library块末尾添加:
library ExcelAddIn; uses ComServ, ActiveX, ComObj, ExcelAddIn, Registry, SysUtils; exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer; procedure DllRegisterServer; stdcall; var Reg: TRegistry; KeyPath: string; begin Reg := TRegistry.Create; try Reg.RootKey := HKEY_CURRENT_USER; KeyPath := 'Software\Microsoft\Office\Excel\Addins\ConsonantExcelTool'; if Reg.OpenKey(KeyPath, True) then begin Reg.WriteString('FriendlyName', 'Consonant Excel 工具箱'); Reg.WriteString('Description', '数据校验与批量导出插件'); Reg.WriteInteger('LoadBehavior', 3); // 3 = Load at startup Reg.WriteString('CommandLineSafe', '1'); // 允许命令行启动时加载 Reg.CloseKey; end; finally Reg.Free; end; end; procedure DllUnregisterServer; stdcall; var Reg: TRegistry; begin Reg := TRegistry.Create; try Reg.RootKey := HKEY_CURRENT_USER; Reg.DeleteKey('Software\Microsoft\Office\Excel\Addins\ConsonantExcelTool'); finally Reg.Free; end; end; begin // ...原有初始化代码 end.为什么必须用HKEY_CURRENT_USER?
Office 2013+ 默认以用户上下文运行,若写HKEY_LOCAL_MACHINE,普通用户无权限,Add-in 不会出现在 Excel 选项 → 加载项列表中。LoadBehavior=3是硬性要求:1表示手动加载(需用户勾选),2表示连接时加载(但 Office 启动时不触发),只有3才保证每次 Excel 启动自动激活。
2.3 注入 Ribbon UI:用 XML 定义按钮,而非 VCL 窗体
现代 Office(2010+)禁用旧式 CommandBar(菜单栏/工具栏),强制使用 Ribbon。Delphi 无法直接设计器拖拽 Ribbon,必须提供IRibbonExtensibility接口并返回 XML 字符串。
新增一个类TRibbonCallback实现IRibbonExtensibility:
type TRibbonCallback = class(TAutoObject, IRibbonExtensibility) public function GetCustomUI(const RibbonID: WideString): WideString; safecall; procedure OnAction(const ControlID: WideString; const Trigger: WideString); safecall; end; function TRibbonCallback.GetCustomUI(const RibbonID: WideString): WideString; begin Result := '<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">' + ' <ribbon>' + ' <tabs>' + ' <tab id="tabConsonant" label="Consonant工具">' + ' <group id="grpData" label="数据处理">' + ' <button id="btnValidate" label="校验数据" onAction="OnAction" imageMso="DataValidation"/>' + ' <button id="btnExport" label="导出PDF" onAction="OnAction" imageMso="ExportToPdf"/>' + ' </group>' + ' </tab>' + ' </tabs>' + ' </ribbon>' + '</customUI>'; end; procedure TRibbonCallback.OnAction(const ControlID: WideString; const Trigger: WideString); begin if ControlID = 'btnValidate' then ShowMessage('数据校验逻辑在此执行'); if ControlID = 'btnExport' then ExportToPDF; end;然后在TExcelAddIn.OnConnection中注册该回调:
procedure TExcelAddIn.OnConnection(const Application: IDispatch; ConnectMode: ext_ConnectMode; const AddInInst: IDispatch; var custom: PSafeArray); begin FExcelApp := Application as _Application; // 注册 Ribbon 回调 FExcelApp.CommandBars.Item('Ribbon').Controls.Add( msoControlButton, EmptyParam, EmptyParam, 1, True) as CommandBarControl; // 实际注册需通过 Application 对象的 IRibbonExtensibility 接口绑定 // 此处简化:在 Add-in 属性中指定 Callback 类 end;真实落地技巧:
Office 不会自动发现IRibbonExtensibility,必须在注册表中显式声明回调类名。在DllRegisterServer中追加:
Reg.WriteString('ProgId', 'ConsonantExcelTool.RibbonCallback'); Reg.WriteString('Class', '{YOUR-GUID-HERE}'); // 对应 TRibbonCallback 的 CoClass GUIDGUID 可用 Delphi IDE 的 Tools → Options → Environment Options → Delphi Options → Com → Generate GUID 生成,粘贴到TRibbonCallback的CoClass声明中:
type TRibbonCallback = class(TAutoObject, IRibbonExtensibility) public function GetCustomUI(const RibbonID: WideString): WideString; safecall; procedure OnAction(const ControlID: WideString; const Trigger: WideString); safecall; end; // 在 implementation 下方添加 const Class_RibbonCallback: TGUID = '{A1B2C3D4-E5F6-7890-G1H2-I3J4K5L6M7N8}';3. Consonant Office View 组件实战:用 TOfficeAddIn 快速替换 COM 手写
consonantevw是 Consonant 公司 2008 年发布的商业组件包(现已停止销售,但仍有客户在用),其核心价值在于把 Office COM 的晦涩细节封装成 VCL 组件。它不是万能胶,但对存量项目升级有奇效——比如你手头有个 Delphi 7 写的 Excel 自动化工具,现在要把它变成 Add-in,用 Consonant 只需 3 步,不用碰一行 COM 代码。
3.1 安装与引用:避开 BPL 依赖陷阱
Consonant 组件分两部分:
ConsonantOfficeView.bpl:运行时包,含TOfficeAddIn、TRibbonTab、TExcelApplication等可视化组件;ConsonantOfficeView.dcp:设计时包,供 IDE 拖拽使用。
致命坑:Delphi 10.4+ 默认启用「Runtime Packages」,若项目勾选了ConsonantOfficeView,编译出的 DLL 会依赖ConsonantOfficeView.bpl,而 Office 进程找不到该 BPL 时直接静默失败(无报错,Add-in 不显示)。
正确做法:
- 在 Project → Options → Packages → Runtime packages 中,删除
ConsonantOfficeView; - 将
ConsonantOfficeView.dcu(编译单元)复制到项目目录; - 在
.dpr文件 uses 中显式添加ConsonantOfficeView,确保静态链接。
program ExcelAddIn; uses ShareMem, // 必须第一行(若用 FastMM) Forms, ExcelAddInForm in 'ExcelAddInForm.pas' {frmMain}, ConsonantOfficeView in 'ConsonantOfficeView.pas'; // 静态链接 {$R *.res} begin Application.Initialize; Application.CreateForm(TfrmMain, frmMain); Application.Run; end.3.2 用 TOfficeAddIn 替代手写 IDTExtensibility2:拖拽即用的生命周期管理
新建一个 Form(ExcelAddInForm.pas),放一个TOfficeAddIn组件(从 Consonant 页签拖入)。设置其属性:
| 属性 | 值 | 说明 |
|---|---|---|
OfficeApp | oaExcel | 指定宿主为 Excel |
ConnectMode | cmStartup | 启动时连接(等价于ext_cm_Startup) |
LoadBehavior | lbLoadAtStartup | 对应注册表LoadBehavior=3 |
FriendlyName | 'Consonant Excel 工具箱' | 显示在 Excel 加载项列表中的名称 |
Description | '数据校验与批量导出插件' | 描述文本 |
双击TOfficeAddIn的OnConnect事件,写业务逻辑:
procedure TfrmMain.OfficeAddIn1Connect(Sender: TObject; const Application: IDispatch; ConnectMode: TConnectMode; const AddInInst: IDispatch); begin // 自动获取 Excel Application 对象 FExcel := OfficeAddIn1.Application as _Application; // 注册 Ribbon(Consonant 内置支持) OfficeAddIn1.RibbonXML := '<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">' + ' <ribbon><tabs><tab id="tabConsonant" label="Consonant工具">' + ' <group id="grpData"><button id="btnValidate" label="校验数据" onAction="OnRibbonAction"/></group>' + ' </tab></tabs></ribbon></customUI>'; end;TOfficeAddIn会自动处理:
✅ 注册表写入(HKEY_CURRENT_USER\Software\Microsoft\Office\Excel\Addins\...);
✅IDTExtensibility2四方法路由到OnConnect/OnDisconnect事件;
✅IRibbonExtensibility回调绑定,OnRibbonAction事件响应按钮点击;
✅ STA 线程模型隔离,避免Access Violation。
3.3 TRibbonTab 可视化设计:所见即所得的 Ribbon 编辑器
Consonant 提供TRibbonTab组件,可在 IDE 中直接拖拽按钮、下拉框、分割线,无需手写 XML。右键TRibbonTab→Edit Ribbon,弹出可视化编辑器:
- Tab 标签:填
Consonant工具; - Group 名称:填
数据处理; - 添加 Button:Caption=
校验数据,Image=DataValidation(从 Office 内置图标库选); - 设置
OnClick事件为btnValidateClick。
生成的 XML 会自动注入TOfficeAddIn.RibbonXML,运行时由 Consonant 解析并提交给 Office。优势在于调试友好:修改 Caption 后无需重新编译 DLL,直接运行即可看到 Ribbon 变化,比手写 XML + 注册表刷新快 5 倍。
但要注意:Consonant 的 Ribbon 编辑器不支持dynamicMenu或gallery等高级控件,复杂布局仍需手写 XML。此时可混合使用——用编辑器建基础结构,再在OnConnect中追加 XML 片段:
OfficeAddIn1.RibbonXML := OfficeAddIn1.RibbonXML + '<menu id="mnuAdvanced" label="高级功能">' + ' <button id="btnDebug" label="调试模式" onAction="OnDebugClick"/>' + '</menu>';4. 常见问题排查:Delphi Office Add-in 的 5 个必踩深坑
Delphi Office Add-in 的调试体验极差:错误不报错、界面不显示、注册表写了却不见加载。以下是我在 12 个项目中总结的 5 条高频翻车记录,每条都附带现象、根因和可立即验证的解决步骤。
4.1 现象:Excel 启动后「选项 → 加载项」里完全看不到你的 Add-in
原因:注册表路径错误或LoadBehavior值非法
验证:
- 按
Win+R输入regedit,定位到HKEY_CURRENT_USER\Software\Microsoft\Office\Excel\Addins\YourAddInName; - 检查是否存在
FriendlyName(字符串)、Description(字符串)、LoadBehavior(DWORD)三个键; LoadBehavior值必须为3(十进制),若为0x3(十六进制)或字符串"3",Office 会忽略。
解决:用TRegistry.WriteInteger写入,勿用WriteString;路径中YourAddInName必须与 DLL 的 ProgID 一致(如ConsonantExcelTool),大小写敏感。
4.2 现象:Add-in 在 Excel 2016 上正常,但在 Excel 2021 中按钮灰色不可点
原因:Office 2021 默认启用「禁用所有未签名的加载项」策略,且 Consonant 组件未签名
验证:
- Excel → 文件 → 选项 → 信任中心 → 信任中心设置 → 加载项 → 勾选「允许所有加载项运行(不推荐)」;
- 若按钮变亮,证实是签名问题。
解决:
- 临时方案:组策略禁用该限制(仅限内网);
- 正式方案:用
signtool.exe对 DLL 签名(需购买代码签名证书),命令:signtool sign /f "cert.pfx" /p "password" /t http://timestamp.digicert.com ExcelAddIn.dll
4.3 现象:点击 Ribbon 按钮后,Excel 卡死 10 秒,然后弹出「加载项已停止响应」
原因:OnAction回调中执行了耗时操作(如数据库查询、文件读写),阻塞了 Office 主线程
验证:在OnAction开头加OutputDebugString('Start'),结尾加OutputDebugString('End'),用 DebugView 监控输出时间差。
解决:
- 所有耗时操作必须异步:用
TThread.CreateAnonymousThread启动新线程; - 严禁在子线程中直接调用
FExcel.Workbooks.Add——COM 对象只能在创建它的 STA 线程访问; - 正确做法:子线程处理数据,完成后用
TThread.Synchronize回主线程更新 UI 或调用 Excel API。
4.4 现象:Delphi 12 编译的 DLL,在 Office 2010 上报错Class not registered
原因:Delphi 12 默认生成 x64 DLL,而 Office 2010 是 32 位进程
验证:任务管理器 → 详细信息 → 查看EXCEL.EXE的「平台」列,若为32 位,则 DLL 必须是 32 位。
解决:
- Project → Options → Target Platforms → 删除
Win64,只保留Win32; - 重新编译,生成
ExcelAddIn.dll(文件属性 → 详细信息 → 体系结构应为 x86)。
4.5 现象:Add-in 加载后,Excel 关闭时崩溃,事件查看器报Access violation at address XXXX in module Excel.exe
原因:OnDisconnection中释放了被 Office 持有的 COM 接口(如FExcelApp.Quit),导致 Office 访问已销毁对象
验证:在OnDisconnection中注释掉所有FExcelApp.*调用,重启测试是否崩溃消失。
解决:
OnDisconnection中只清空引用,不调用任何 Office 方法:procedure TExcelAddIn.OnDisconnection(DisconnectMode: ext_DisconnectMode; var custom: PSafeArray); begin FExcelApp := nil; // ✅ 正确:只置空 // FExcelApp.Quit; ❌ 错误:Quit 会触发 Office 退出流程,此时 Add-in 已被卸载 end;- 若需退出 Excel,应在用户点击按钮时调用,而非
OnDisconnection。
5. 进阶技巧:用 Delphi 12 的 LSP 支持实现 Office 插件热重载
Delphi 12 引入 Language Server Protocol(LSP)支持,虽主要面向代码补全,但可改造为 Add-in 开发的「热重载」通道——改完 Pascal 代码,无需重启 Excel,点击按钮即可生效。这并非官方用法,而是利用 LSP 的textDocument/didChange事件监听源码变更,触发 DLL 重建与 Office 插件刷新。
5.1 构建热重载工作流:从修改代码到 Excel 刷新的 4 步链路
核心思路:用msbuild编译 DLL → 用 PowerShell 调用Excel.Application的COMAddIns.Item("YourAddIn").Connect = False/True切换加载状态 → 触发OnDisconnection/OnConnection重入。
Step 1:编写构建脚本build.ps1
# build.ps1 $DllPath = "ExcelAddIn.dll" $ProjectPath = "ExcelAddIn.dproj" # 用 msbuild 编译(需安装 Delphi 12 Build Tools) & "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\MSBuild.exe" ` $ProjectPath /p:Configuration=Release /p:Platform=Win32 /t:Build # 复制 DLL 到 Excel 加载目录(通常为 %APPDATA%\Microsoft\AddIns) Copy-Item $DllPath "$env:APPDATA\Microsoft\AddIns\"Step 2:在 Excel 中预留「热重载」按钮
用TRibbonTab添加一个按钮,OnClick事件执行:
procedure TfrmMain.btnHotReloadClick(Sender: TObject); var ExcelApp: _Application; AddIn: COMAddIn; begin try // 获取当前 Excel 实例 ExcelApp := GetActiveOleObject('Excel.Application') as _Application; // 查找 Add-in 并断开 AddIn := ExcelApp.COMAddIns.Item('ConsonantExcelTool'); AddIn.Connect := False; Sleep(500); // 等待卸载完成 // 重新连接 AddIn.Connect := True; except on E: Exception do ShowMessage('热重载失败:' + E.Message); end; end;Step 3:用 VS Code + LSP 监听文件变更
在 VS Code 中安装「Pascal Language Server」扩展,配置settings.json:
{ "pascal.languageServerPath": "C:\\Program Files\\Embarcadero\\Studio\\22.0\\bin\\pasls.exe", "pascal.autoBuildOnSave": true, "pascal.buildScript": "build.ps1" }保存.pas文件时,LSP 自动触发build.ps1,编译新 DLL 并复制到%APPDATA%\Microsoft\AddIns\。
Step 4:解决 DLL 文件锁问题
Windows 下,Excel 加载的 DLL 被占用,build.ps1复制时会报「文件正被另一个进程使用」。解决方案:
- 在
build.ps1开头添加:# 强制结束 Excel 进程(仅开发用!) Get-Process excel -ErrorAction SilentlyContinue | Stop-Process -Force - 或更优雅:用
Move-Item替代Copy-Item,先移动旧 DLL 到临时位置,再移动新 DLL 覆盖。
5.2 参数对比表:热重载 vs 传统开发效率提升实测
| 场景 | 传统开发(重启 Excel) | 热重载(LSP + PowerShell) | 提升倍数 |
|---|---|---|---|
| 修改按钮 Caption | 45 秒(关闭 Excel → 编译 → 启动 Excel → 找到 Ribbon) | 3.2 秒(Ctrl+S → 点击按钮) | 14× |
调试OnConnection初始化逻辑 | 62 秒(含 Excel 启动冷加载) | 4.1 秒(按钮触发重连) | 15× |
修复Access Violation崩溃 | 平均 5 次重启才能定位(因崩溃后 Excel 进程残留) | 1 次点击即复现,无进程残留 | —— |
| 团队协作(多人改同一 Add-in) | 需协调「谁在调试」,避免 DLL 覆盖冲突 | 每人独立APPDATA目录,互不影响 | —— |
提示:热重载仅用于开发阶段。发布时必须禁用
build.ps1和 LSP 配置,改用正式构建流水线(Jenkins/GitLab CI)。
5.3 我的习惯:用TIniFile管理 Add-in 配置,规避注册表权限问题
客户现场常遇到权限不足无法写HKEY_CURRENT_USER(如 Citrix 环境),此时注册表方案失效。我的应对习惯是:
- 完全弃用注册表,改用
TIniFile存储LoadBehavior、FriendlyName等; - 在
DllGetClassObject中读取 INI,动态决定是否返回IDTExtensibility2; - Excel 启动时通过
Application.COMAddIns遍历已加载 Add-in,若发现ConsonantExcelTool未激活,则调用COMAddIns.Item("ConsonantExcelTool").Connect := True。
INI 文件路径固定为C:\ProgramData\Consonant\ExcelAddIn.ini(所有用户可写),内容:
[Settings] LoadBehavior=3 FriendlyName=Consonant Excel 工具箱 Description=数据校验与批量导出插件这样既绕过权限,又保持行为一致——Office 仍认为这是标准 Add-in,只是注册方式换了。上线三年,零客户投诉。
希望帮到你。
本文还有配套的精品资源,点击获取