ATL COM 插件/插件框架,支持动态工具栏和菜单






4.86/5 (32投票s)
2004 年 12 月 3 日
3分钟阅读

170845

3185
一篇关于 ATL COM 插件/插件框架,支持动态工具栏和菜单的文章,基于 VC++ 插件架构。
链接
- Len Holgate's 编写可扩展应用程序
- Len Holgate's 组件类别管理器包装器类
- 使用组件类别构建可插入组件 - 第一部分 (作者:Zac Howland)
- 使用组件类别构建可插入组件 - 第二部分 (作者:Zac Howland)
- Roger Allen's 一个 MFC 扩展库,用于通过 MESSAGE_MAPs 为您的应用程序启用 DLL 插件技术
引言
为每个客户的需求量身定制产品是每个公司的梦想。但在实践中可能并非如此。这是因为在大多数情况下,需求会发生剧烈变化,以至于我们必须在代码级别进行更改,重新编译,测试,然后作为新版本发布。这种开发方式在项目成本和开发工作量方面效率不高。这就是 **Addin / Plugin** 架构的优势所在。在这篇文章中,我编写了一个 ATL COM Addin / Plugin Framework,**支持动态工具栏和菜单**。该框架实际上基于 VC++ 6.0 Addin Architecture,这是 Microsoft 在所有 MS Office 应用程序中使用的(不确定确切实现,只是猜测,因为我遵循了 VC++ Addin 向导生成的代码相同的路径)。一个不同之处在于,VC++ Addin 在添加菜单、其描述和其他详细信息时使用新行分隔的方式,而我使用 XML 格式来添加插件详细信息(不知道为什么 Microsoft 没有使用 XML?也许那时 **XML** 还没有标准化?或者有其他特定原因?),并使用 **Component Category** 对插件进行分类。点击**此处**查看我在本项目中使用的 XML 格式。如果您愿意,可以添加更多的属性作为叶节点(我遵循了将菜单属性作为节点放置的思路。或者您也可以以其他方式放置属性)。
背景
本文假设您对 COM 和 MFC 有基本了解。本文实际上是对 **Zac Howland** 撰写的精彩文章 使用组件类别构建可插入组件 - 第一部分 的延续。因此,建议用户在阅读我的文章之前先阅读这篇文章。
使用代码
随附的演示项目包含 3 个用 VC++ 6.0 编写的项目工作区。 **ProjectFramework** 应用程序负责加载所有插件、其菜单、工具栏和其他详细信息。该应用程序使用一个名为 **CAddinManager** 的核心类来进行各种插件操作。 **CAddinManager** 类的主要头文件如下所示。
class CAddinManager { private: BOOL m_bLoadAllAdins; CArray<CAddinInfo,CAddinInfo> m_AddinInfoArray; CComPtr<IProjectFramework> m_ProjectFrameworkObject; HRESULT LoadAllAdins(BSTR strAddinLoadingInfo, IProjectFramework* pProjectFramework); public: BOOL InvokeAddinMenuItem(UINT iCommandID); BOOL SetAddinVisible(CString strAddinName, BOOL bVisible); const CAddinInfo& GetAddinInformation(UINT iCommandID); const CAddinCommadInfo& GetAddinCommadInfo(UINT iCommandID); CAddinCommadInfo GetAddinCommadInfo(long iAddinIndex,long lIndex); BOOL AddAddinCommandInfo(long iAddinIndex, CAddinCommadInfo AddinCommadInfo); BOOL SetAddinCount(long lCount); BOOL UnloadAllAddins(); CAddinInfo GetAddinInfo(long iAddinIndex); BOOL SetAddinInfo(long iAddinIndex,CAddinInfo AddinInfo); long GetAddinCount(); void SetLoadAllAddinStatus(BOOL bLoadAllAddins); virtual BOOL GetLoadAllAddinStatus(); CAddinInfo GetAddinIffo(CLSID clsID); BOOL LoadAllAddins(); BOOL SaveAddinDefaultSettings(); BOOL LoadAddinDefaultSettings(); CAddinManager(); virtual ~CAddinManager(); };此类使用许多其他相关类,例如 `CAddinInfo`,它包含每个插件的信息; `IProjectFramework`,这是 ProjectFramework 应用程序公开的接口;以及 `IProjectFrameworkAddin` 接口,这是每个插件都应该实现的。请参阅源代码以获取更多详细信息。应用程序构建所用的重要代码块如下所示。
在 CProjectFrameworkApp 中,静态声明一个 `CAddinManager` 变量。
static CAddinManager m_AddinManager; static CProjectFrameworkView* m_pView;
in
BOOL CProjectFrameworkApp::InitInstance() { ... if (!ProcessShellCommand(cmdInfo)) return FALSE; ((CMainFrame*)m_pMainWnd)->LoadAditionalAccelerators(); }
在 `CMainFrame` 中
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(ID_ADDIN_ADDINSETTINGS, OnAddinAddinsettings) ON_WM_CLOSE() ON_WM_MENUSELECT() ON_WM_INITMENUPOPUP() //}}AFX_MSG_MAP ON_COMMAND_RANGE(PF_ADDIN_CMD_MIN_MSG_ID, PF_ADDIN_CMD_MAX_MSG_ID,
OnAddinMenuItems) ON_UPDATE_COMMAND_UI_RANGE(PF_ADDIN_CMD_MIN_MSG_ID, PF_ADDIN_CMD_MAX_MSG_ID,
OnUpdateAddinMenuItems) ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_NEW, ID_APP_ABOUT, OnUpdateMenuItems) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, PF_MIN_MSG, PF_MAX_MSG, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, PF_MIN_MSG, PF_MAX_MSG, OnToolTipText) END_MESSAGE_MAP()
和
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; //Load all addins if(CProjectFrameworkApp::m_AddinManager.LoadAddinDefaultSettings()) { if(CProjectFrameworkApp::m_AddinManager.GetLoadAllAddinStatus()) { CProjectFrameworkApp::m_AddinManager.LoadAllAddins(); } } LoadAllAddinCommands(); if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); //Remove File new and Open Commands RemoveCommands(ID_FILE_NEW); RemoveCommands(ID_FILE_OPEN); return 0; }
关注点
此版本实现的功能有。
- 动态菜单。
- 动态工具栏。
- 帮助字符串和工具提示支持。
- 从插件菜单和工具栏调用插件中的方法。
- 通过从某个插件调用的对话框解释自动化支持(报表插件 -> 销售报表 -> 今日销售报表 Ctrl + B 菜单)。
- 隐藏菜单和工具栏按钮(例如:文件 -> 新建和打开)。
- 插件的键盘加速器支持。
- 加载/卸载插件。
- 连接点支持,用于从插件获取通知事件。
历史
- 初始发布:2004 年 12 月 2 日
- 添加了连接点支持:2004 年 12 月 10 日