Building a product which suits to every customers requirement is every Companies dream. But in practice this may not be the case. This is because in most of the cases the requirement keep on changing drastically so that we have to make changes in the code level , recompile it, test it and ship it as another version. This way of development is not efficient in terms of project cost and developmental effort. This is where the Addin / Plugin architecture wins. In this article I have written a ATL COM Addin / Plugin Framework with dynamic toolbars and menu support . This framework is actually based on the VC++ 6.0 Addin Architecture which Microsoft used in every MS Office based applications (not sure of the exact implementation , just a guess work, because I followed the same path of VC++ Addin wizard generated code ). One difference, instead of adding menus , their description and other details in a new line delimited fashion in VC++ Addin , I used XML format for adding the Plugin details (Don't know why Microsoft didn't use XML?, perhaps at that time XML was not standardized , or is there any other specific reason??) along with Component Category for categorizing the plugins. Click here for seeing the XML format which I used in this project. You can add more properties as leaf nodes if you want (I followed the Idea of putting menu properties as nodes. Alternatively you can put the properties in some other fashion too).
This article assumes that you have a basic understanding of COM and MFC. This article is actually a continuation of the excellent article written by Zac Howland Pluggable Components using Component Categories - Part 1 . So the user is advised to go through this article first before coming to my article.
Using the code
The demo project attached contains 3 project workspaces written in VC++ 6.0. The application ProjectFramework is the one which loads all the addins , their menus, toolbars and other details. This application uses one core class called CAddinManager for various addin manipulations. The main header file of CAddinManager class is given below.
HRESULT LoadAllAdins(BSTR strAddinLoadingInfo,
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,
BOOL SetAddinCount(long lCount);
CAddinInfo GetAddinInfo(long iAddinIndex);
BOOL SetAddinInfo(long iAddinIndex,CAddinInfo AddinInfo);
void SetLoadAllAddinStatus(BOOL bLoadAllAddins);
virtual BOOL GetLoadAllAddinStatus();
CAddinInfo GetAddinIffo(CLSID clsID);
This class uses a lot of other related classes like
which contains information's about each addin,
which is the interface exposed by the ProjectFramework application and
interface which every pluggin should implement. Please see the source code for more details.The important blocks of codes in which the application built up is given below.
In CProjectFrameworkApp declare a variable of
static CAddinManager m_AddinManager;
static CProjectFrameworkView* m_pView;
ON_COMMAND_RANGE(PF_ADDIN_CMD_MIN_MSG_ID, PF_ADDIN_CMD_MAX_MSG_ID, <BR> OnAddinMenuItems)
ON_UPDATE_COMMAND_UI_RANGE(PF_ADDIN_CMD_MIN_MSG_ID, PF_ADDIN_CMD_MAX_MSG_ID, <BR> 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)
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |
WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY
TRACE0("Failed to create toolbar\n");
return -1; }
if (!m_wndStatusBar.Create(this) ||
TRACE0("Failed to create status bar\n");
return -1; }
Points of Interest
In this version features implemented are.
- Dynamic Menus.
- Dynamic Toolbars.
- Help string and tool tip support.
- Invoking of methods in plugins from addin menu and toolbar.
- Automation support explained using a dialog box invoked from one of the plugins (Report Addin -> Sales report -> Todays Sales Report Ctrl + B menu ).
- Hiding of Menus and toolbar buttons (eg : File ->New and Open ).
- Key Board accelerator support for plugin.
- Loading / Unloading of addins.
- Connection point support for getting notification events from addins.
- Initial Release : Dec 2, 2004
- Added Connection Point support : Dec 10, 2004 <!------------------------------- That's it! --------------------------->