Discussion:
Dynamic menus
(too old to reply)
Janiv Ratson
2006-03-07 08:54:42 UTC
Permalink
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree
control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste and
Properties menu items.
I want to enable an MFC extension to add its own menu items to this context
menu, for example: Select, Set Host and Rename.
I also want that the handlers of thoses added menu items to reside in the
MFC Extension dll.

What is the best way to implement this kind of mechanism.

Thanks,
Janiv Ratson.
Voidcoder
2006-03-07 09:33:36 UTC
Permalink
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
exported functions in each plugin. For example:

1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)

You can save pointers to those functions somewhere
during the plugin loading process, eg:

while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule, _T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}

Now before you track the context menu:

CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...

for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}

menu.TrackPopupMenu(...);

And your OnCommand handler:

BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();

for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}

return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste and Properties menu items.
I want to enable an MFC extension to add its own menu items to this context menu, for example: Select, Set Host and
Rename.
I also want that the handlers of thoses added menu items to reside in the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Janiv Ratson
2006-03-07 12:17:33 UTC
Permalink
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that were
added by the plugin dll, are disabled (grayed) (I think becuase the system
does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule, _T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree
control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste and
Properties menu items.
I want to enable an MFC extension to add its own menu items to this
context menu, for example: Select, Set Host and Rename.
I also want that the handlers of thoses added menu items to reside in the
MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Scott McPhillips [MVP]
2006-03-07 13:16:31 UTC
Permalink
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that were
added by the plugin dll, are disabled (grayed) (I think becuase the system
does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
You decide ahead of time how many addon menu commands you might need and
you reserve the IDs to be used. #define min and max IDs for a range of
menu commands, and then put ON_COMMAND_RANGE in your message map. Your
handler will be called for any of the specified IDs, and will be passed
the selected menu command's ID.
--
Scott McPhillips [VC++ MVP]
Voidcoder
2006-03-07 13:23:13 UTC
Permalink
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that were added by the plugin dll, are disabled
(grayed) (I think becuase the system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule, _T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste and Properties menu items.
I want to enable an MFC extension to add its own menu items to this context menu, for example: Select, Set Host and
Rename.
I also want that the handlers of thoses added menu items to reside in the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Janiv Ratson
2006-03-07 14:33:41 UTC
Permalink
Thanks,

//////////////////////////////////////load
plugins///////////////////////////////////////////////

m_plugIn.m_hModule = LoadLibrary("HostControlBox.dll");

m_plugIn.m_pFuncAddMenuItems =
(pFuncAddMenuItems)GetProcAddress(m_plugIn.m_hModule,_T("AddMenuItems"));

m_plugIn.m_pFuncOnCommand =
(pFuncOnCommand)GetProcAddress(m_plugIn.m_hModule,_T("OnCommands"));

m_plugIn.m_pFuncUpdateUICmd =
(pFuncUpdateUICmd)GetProcAddress(m_plugIn.m_hModule,_T("UpdateUICmd"));

////////////////////////////////////////////////////////////////////////////////////////////////////////

BOOL CConfigNetPaneContacts::OnCommand(WPARAM wParam, LPARAM lParam)

{

if(m_plugIn.m_pFuncOnCommand(wParam,lParam))

{

return TRUE;

}

return CXTPShortcutBarPane::OnCommand(wParam, lParam);

}



/////////////////////////////////////////////////////////////////////////////////////

void CConfigNetPaneContacts::OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/)

{

CPoint point;

GetCursorPos(&point);

CMenu menu;

VERIFY(menu.LoadMenu(IDR_MENU_GENERIC));

CMenu* pPopup = menu.GetSubMenu(0);

ASSERT(pPopup != NULL);

CWnd* pWndPopupOwner = this;

while (pWndPopupOwner->GetStyle() & WS_CHILD)

pWndPopupOwner = pWndPopupOwner->GetParent();

m_plugIn.m_pFuncAddMenuItems(pPopup);

pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);

}
Post by Voidcoder
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that were
added by the plugin dll, are disabled (grayed) (I think becuase the
system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule, _T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree
control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste
and Properties menu items.
I want to enable an MFC extension to add its own menu items to this
context menu, for example: Select, Set Host and Rename.
I also want that the handlers of thoses added menu items to reside in
the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Voidcoder
2006-03-07 15:39:05 UTC
Permalink
Well, now is clear what happens there. The items are disabled
because you are tracking the menu in context of the frame
window:

while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();

Note all windows derived from the CFrameWnd class
are handling WM_INITMENUPOPUP message in a
special way. They do iterate through the menu items
looking for the command handlers and calling command
UI update handlers. The following trick should help
you:


BOOL fSave = ((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable;

((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = FALSE;

pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);

((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = fSave;



Come back if still not working.
Post by Janiv Ratson
Thanks,
//////////////////////////////////////load plugins///////////////////////////////////////////////
m_plugIn.m_hModule = LoadLibrary("HostControlBox.dll");
m_plugIn.m_pFuncAddMenuItems = (pFuncAddMenuItems)GetProcAddress(m_plugIn.m_hModule,_T("AddMenuItems"));
m_plugIn.m_pFuncOnCommand = (pFuncOnCommand)GetProcAddress(m_plugIn.m_hModule,_T("OnCommands"));
m_plugIn.m_pFuncUpdateUICmd = (pFuncUpdateUICmd)GetProcAddress(m_plugIn.m_hModule,_T("UpdateUICmd"));
////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CConfigNetPaneContacts::OnCommand(WPARAM wParam, LPARAM lParam)
{
if(m_plugIn.m_pFuncOnCommand(wParam,lParam))
{
return TRUE;
}
return CXTPShortcutBarPane::OnCommand(wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////////////
void CConfigNetPaneContacts::OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/)
{
CPoint point;
GetCursorPos(&point);
CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU_GENERIC));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
m_plugIn.m_pFuncAddMenuItems(pPopup);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,pWndPopupOwner);
}
Post by Voidcoder
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that were added by the plugin dll, are disabled
(grayed) (I think becuase the system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule, _T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste and Properties menu items.
I want to enable an MFC extension to add its own menu items to this context menu, for example: Select, Set Host
and Rename.
I also want that the handlers of thoses added menu items to reside in the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Janiv Ratson
2006-03-08 14:30:25 UTC
Permalink
Hello thanks,
Now all my handlers are enabled (which is not good, because I want only
those that have handlers).
Also, the handlers are not called on pressing the commands.
Also, the tooltip is not shown in status bar for the commands from my
extension DLL, but are shown in the status bar for local commands.
Thanks,
Janiv Ratson.
Post by Voidcoder
Well, now is clear what happens there. The items are disabled
because you are tracking the menu in context of the frame
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
Note all windows derived from the CFrameWnd class
are handling WM_INITMENUPOPUP message in a
special way. They do iterate through the menu items
looking for the command handlers and calling command
UI update handlers. The following trick should help
BOOL fSave = ((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable;
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = FALSE;
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = fSave;
Come back if still not working.
Post by Janiv Ratson
Thanks,
//////////////////////////////////////load
plugins///////////////////////////////////////////////
m_plugIn.m_hModule = LoadLibrary("HostControlBox.dll");
m_plugIn.m_pFuncAddMenuItems =
(pFuncAddMenuItems)GetProcAddress(m_plugIn.m_hModule,_T("AddMenuItems"));
m_plugIn.m_pFuncOnCommand =
(pFuncOnCommand)GetProcAddress(m_plugIn.m_hModule,_T("OnCommands"));
m_plugIn.m_pFuncUpdateUICmd =
(pFuncUpdateUICmd)GetProcAddress(m_plugIn.m_hModule,_T("UpdateUICmd"));
////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CConfigNetPaneContacts::OnCommand(WPARAM wParam, LPARAM lParam)
{
if(m_plugIn.m_pFuncOnCommand(wParam,lParam))
{
return TRUE;
}
return CXTPShortcutBarPane::OnCommand(wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////////////
void CConfigNetPaneContacts::OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/)
{
CPoint point;
GetCursorPos(&point);
CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU_GENERIC));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
m_plugIn.m_pFuncAddMenuItems(pPopup);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,pWndPopupOwner);
}
Post by Voidcoder
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that
were added by the plugin dll, are disabled (grayed) (I think becuase
the system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule,
_T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree
control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste
and Properties menu items.
I want to enable an MFC extension to add its own menu items to this
context menu, for example: Select, Set Host and Rename.
I also want that the handlers of thoses added menu items to reside in
the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Voidcoder
2006-03-08 16:03:26 UTC
Permalink
Hey, no panic! If you want a complete command handling
with CComandUI etc then you have to play a little. No one
is going to write the code for you, you can only get some
basic idea here and all the rest is just your imagination ...

Well, where did we stop at? :)

1. Do not hack the m_bAutoMenuEnable field.

2. Reserve a range of command IDs.

Example

#define ID_PLUGIN_CMD_FIRST 5001
#define ID_PLUGIN_CMD_LAST 5100

Your plugins must use only commands in this
range.


3. Change your message map

BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)

// << Some entries >>

ON_COMMAND_RANGE(ID_PLUGIN_CMD_FIRST, ID_PLUGIN_CMD_LAST, OnPluginCommand)
ON_UPDATE_COMMAND_UI_RANGE(ID_PLUGIN_CMD_FIRST, ID_PLUGIN_CMD_LAST, OnPluginUpdateCommandUI)

END_MESSAGE_MAP()


4. Add handlers

void CMyFrameWnd::OnPluginCommand(UINT nID)
{
// Let the plugin to handle command

PluginCommandHandler(nID);
}

void CMyFrameWnd::OnPluginCommand(CCmdUI* pCmdUI)
{
// Let the plugin to handle update UI event

PluginUpdateUIHandler(pCmdUI);
}
Post by Janiv Ratson
Hello thanks,
Now all my handlers are enabled (which is not good, because I want only those that have handlers).
Also, the handlers are not called on pressing the commands.
Also, the tooltip is not shown in status bar for the commands from my extension DLL, but are shown in the status bar
for local commands.
Thanks,
Janiv Ratson.
Post by Voidcoder
Well, now is clear what happens there. The items are disabled
because you are tracking the menu in context of the frame
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
Note all windows derived from the CFrameWnd class
are handling WM_INITMENUPOPUP message in a
special way. They do iterate through the menu items
looking for the command handlers and calling command
UI update handlers. The following trick should help
BOOL fSave = ((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable;
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = FALSE;
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = fSave;
Come back if still not working.
Post by Janiv Ratson
Thanks,
//////////////////////////////////////load plugins///////////////////////////////////////////////
m_plugIn.m_hModule = LoadLibrary("HostControlBox.dll");
m_plugIn.m_pFuncAddMenuItems = (pFuncAddMenuItems)GetProcAddress(m_plugIn.m_hModule,_T("AddMenuItems"));
m_plugIn.m_pFuncOnCommand = (pFuncOnCommand)GetProcAddress(m_plugIn.m_hModule,_T("OnCommands"));
m_plugIn.m_pFuncUpdateUICmd = (pFuncUpdateUICmd)GetProcAddress(m_plugIn.m_hModule,_T("UpdateUICmd"));
////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CConfigNetPaneContacts::OnCommand(WPARAM wParam, LPARAM lParam)
{
if(m_plugIn.m_pFuncOnCommand(wParam,lParam))
{
return TRUE;
}
return CXTPShortcutBarPane::OnCommand(wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////////////
void CConfigNetPaneContacts::OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/)
{
CPoint point;
GetCursorPos(&point);
CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU_GENERIC));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
m_plugIn.m_pFuncAddMenuItems(pPopup);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,pWndPopupOwner);
}
Post by Voidcoder
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that were added by the plugin dll, are disabled
(grayed) (I think becuase the system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule, _T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule, _T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application tree control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut, Paste and Properties menu items.
I want to enable an MFC extension to add its own menu items to this context menu, for example: Select, Set Host
and Rename.
I also want that the handlers of thoses added menu items to reside in the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Janiv Ratson
2006-03-09 13:48:14 UTC
Permalink
Hi and thanks,
In that case, how do I ensure that there are no conflicts with the IDz.
i.e., there may be a case when 2 3rd party companies will write plugins to
my application.
They will never know, what Idz to use ?
I don't think the keeping Idz idea is the best way in my case, is it?
Is there any other way?

How does Microsoft implement the Add-ins in Visual Studio, Outlook, etc. ?
Post by Voidcoder
Hey, no panic! If you want a complete command handling
with CComandUI etc then you have to play a little. No one
is going to write the code for you, you can only get some
basic idea here and all the rest is just your imagination ...
Well, where did we stop at? :)
1. Do not hack the m_bAutoMenuEnable field.
2. Reserve a range of command IDs.
Example
#define ID_PLUGIN_CMD_FIRST 5001
#define ID_PLUGIN_CMD_LAST 5100
Your plugins must use only commands in this
range.
3. Change your message map
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
// << Some entries >>
ON_COMMAND_RANGE(ID_PLUGIN_CMD_FIRST, ID_PLUGIN_CMD_LAST, OnPluginCommand)
ON_UPDATE_COMMAND_UI_RANGE(ID_PLUGIN_CMD_FIRST, ID_PLUGIN_CMD_LAST,
OnPluginUpdateCommandUI)
END_MESSAGE_MAP()
4. Add handlers
void CMyFrameWnd::OnPluginCommand(UINT nID)
{
// Let the plugin to handle command
PluginCommandHandler(nID);
}
void CMyFrameWnd::OnPluginCommand(CCmdUI* pCmdUI)
{
// Let the plugin to handle update UI event
PluginUpdateUIHandler(pCmdUI);
}
Post by Janiv Ratson
Hello thanks,
Now all my handlers are enabled (which is not good, because I want only
those that have handlers).
Also, the handlers are not called on pressing the commands.
Also, the tooltip is not shown in status bar for the commands from my
extension DLL, but are shown in the status bar for local commands.
Thanks,
Janiv Ratson.
Post by Voidcoder
Well, now is clear what happens there. The items are disabled
because you are tracking the menu in context of the frame
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
Note all windows derived from the CFrameWnd class
are handling WM_INITMENUPOPUP message in a
special way. They do iterate through the menu items
looking for the command handlers and calling command
UI update handlers. The following trick should help
BOOL fSave = ((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable;
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = FALSE;
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = fSave;
Come back if still not working.
Post by Janiv Ratson
Thanks,
//////////////////////////////////////load
plugins///////////////////////////////////////////////
m_plugIn.m_hModule = LoadLibrary("HostControlBox.dll");
m_plugIn.m_pFuncAddMenuItems =
(pFuncAddMenuItems)GetProcAddress(m_plugIn.m_hModule,_T("AddMenuItems"));
m_plugIn.m_pFuncOnCommand =
(pFuncOnCommand)GetProcAddress(m_plugIn.m_hModule,_T("OnCommands"));
m_plugIn.m_pFuncUpdateUICmd =
(pFuncUpdateUICmd)GetProcAddress(m_plugIn.m_hModule,_T("UpdateUICmd"));
////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CConfigNetPaneContacts::OnCommand(WPARAM wParam, LPARAM lParam)
{
if(m_plugIn.m_pFuncOnCommand(wParam,lParam))
{
return TRUE;
}
return CXTPShortcutBarPane::OnCommand(wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////////////
void CConfigNetPaneContacts::OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/)
{
CPoint point;
GetCursorPos(&point);
CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU_GENERIC));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
m_plugIn.m_pFuncAddMenuItems(pPopup);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);
}
Post by Voidcoder
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that
were added by the plugin dll, are disabled (grayed) (I think becuase
the system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule,
_T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule,
_T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application
tree control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut,
Paste and Properties menu items.
I want to enable an MFC extension to add its own menu items to this
context menu, for example: Select, Set Host and Rename.
I also want that the handlers of thoses added menu items to reside
in the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Ajay Kalra
2006-03-09 13:55:56 UTC
Permalink
Post by Janiv Ratson
In that case, how do I ensure that there are no conflicts with the IDz.
That is correct. This model will not work because of that reason alone
unless you give a block of IDs to every plugIn(not a good idea).

Instead of letting the plug In use message maps, you can simply call
some method in plugIns DLL for updating the command or when the command
is executed.

It will help you a lot if you look at the *object model* of an existing
commercial application. Look at Office products. They have very rich
object model. It will give you ideas about how to go about it.

-------
Ajay Kalra
***@yahoo.com
Janiv Ratson
2006-03-16 11:01:34 UTC
Permalink
Do u have any web site to direct me to?
Something?
Where can I read about the Object Model concept and how to implement it
within my application.
Thanks,
j.
Post by Ajay Kalra
Post by Janiv Ratson
In that case, how do I ensure that there are no conflicts with the IDz.
That is correct. This model will not work because of that reason alone
unless you give a block of IDs to every plugIn(not a good idea).
Instead of letting the plug In use message maps, you can simply call
some method in plugIns DLL for updating the command or when the command
is executed.
It will help you a lot if you look at the *object model* of an existing
commercial application. Look at Office products. They have very rich
object model. It will give you ideas about how to go about it.
-------
Ajay Kalra
Ajay Kalra
2006-03-16 13:24:53 UTC
Permalink
One of richest object model is Office products by Microsoft. Devstudio
itself has object model. These are all available at msdn site. To get into
it, you can start by looking at Jeff Prosise's book (2nd edition) where
Application and Document objects are exposed. You can build an automation
server in MFC with great ease (Thats what Prosise's book shows). These
things are not trivial and can test you especially if you are not
comfortable in COM. I would look at Codeproject/Codeguru for some other
examples.

--
Ajay Kalra [MVP - VC++]
Post by Janiv Ratson
Do u have any web site to direct me to?
Something?
Where can I read about the Object Model concept and how to implement it
within my application.
Thanks,
j.
Post by Ajay Kalra
Post by Janiv Ratson
In that case, how do I ensure that there are no conflicts with the IDz.
That is correct. This model will not work because of that reason alone
unless you give a block of IDs to every plugIn(not a good idea).
Instead of letting the plug In use message maps, you can simply call
some method in plugIns DLL for updating the command or when the command
is executed.
It will help you a lot if you look at the *object model* of an existing
commercial application. Look at Office products. They have very rich
object model. It will give you ideas about how to go about it.
-------
Ajay Kalra
Ben Voigt
2006-03-16 22:25:20 UTC
Permalink
Provide an AddPopupCommand() function which returns (or fills in output
parameter) the ID. Each plugin calls the function to get as many IDs as
they need, then saves the resulting values to compare to the commands
pressed....

See the Win32 API RegisterWindowMessage which uses a similar approach. Or
think of binding TCP client ports... you let the OS give you free ports and
never refer to hardcoded numbers.
Post by Janiv Ratson
Hi and thanks,
In that case, how do I ensure that there are no conflicts with the IDz.
i.e., there may be a case when 2 3rd party companies will write plugins to
my application.
They will never know, what Idz to use ?
I don't think the keeping Idz idea is the best way in my case, is it?
Is there any other way?
How does Microsoft implement the Add-ins in Visual Studio, Outlook, etc. ?
Post by Voidcoder
Hey, no panic! If you want a complete command handling
with CComandUI etc then you have to play a little. No one
is going to write the code for you, you can only get some
basic idea here and all the rest is just your imagination ...
Well, where did we stop at? :)
1. Do not hack the m_bAutoMenuEnable field.
2. Reserve a range of command IDs.
Example
#define ID_PLUGIN_CMD_FIRST 5001
#define ID_PLUGIN_CMD_LAST 5100
Your plugins must use only commands in this
range.
3. Change your message map
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
// << Some entries >>
ON_COMMAND_RANGE(ID_PLUGIN_CMD_FIRST, ID_PLUGIN_CMD_LAST,
OnPluginCommand)
ON_UPDATE_COMMAND_UI_RANGE(ID_PLUGIN_CMD_FIRST, ID_PLUGIN_CMD_LAST,
OnPluginUpdateCommandUI)
END_MESSAGE_MAP()
4. Add handlers
void CMyFrameWnd::OnPluginCommand(UINT nID)
{
// Let the plugin to handle command
PluginCommandHandler(nID);
}
void CMyFrameWnd::OnPluginCommand(CCmdUI* pCmdUI)
{
// Let the plugin to handle update UI event
PluginUpdateUIHandler(pCmdUI);
}
Post by Janiv Ratson
Hello thanks,
Now all my handlers are enabled (which is not good, because I want only
those that have handlers).
Also, the handlers are not called on pressing the commands.
Also, the tooltip is not shown in status bar for the commands from my
extension DLL, but are shown in the status bar for local commands.
Thanks,
Janiv Ratson.
Post by Voidcoder
Well, now is clear what happens there. The items are disabled
because you are tracking the menu in context of the frame
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
Note all windows derived from the CFrameWnd class
are handling WM_INITMENUPOPUP message in a
special way. They do iterate through the menu items
looking for the command handlers and calling command
UI update handlers. The following trick should help
BOOL fSave = ((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable;
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = FALSE;
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);
((CFrameWnd*)pWndPopupOwner)->m_bAutoMenuEnable = fSave;
Come back if still not working.
Post by Janiv Ratson
Thanks,
//////////////////////////////////////load
plugins///////////////////////////////////////////////
m_plugIn.m_hModule = LoadLibrary("HostControlBox.dll");
m_plugIn.m_pFuncAddMenuItems =
(pFuncAddMenuItems)GetProcAddress(m_plugIn.m_hModule,_T("AddMenuItems"));
m_plugIn.m_pFuncOnCommand =
(pFuncOnCommand)GetProcAddress(m_plugIn.m_hModule,_T("OnCommands"));
m_plugIn.m_pFuncUpdateUICmd =
(pFuncUpdateUICmd)GetProcAddress(m_plugIn.m_hModule,_T("UpdateUICmd"));
////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CConfigNetPaneContacts::OnCommand(WPARAM wParam, LPARAM lParam)
{
if(m_plugIn.m_pFuncOnCommand(wParam,lParam))
{
return TRUE;
}
return CXTPShortcutBarPane::OnCommand(wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////////////
void CConfigNetPaneContacts::OnContextMenu(CWnd* /*pWnd*/, CPoint /*point*/)
{
CPoint point;
GetCursorPos(&point);
CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU_GENERIC));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
m_plugIn.m_pFuncAddMenuItems(pPopup);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x,
point.y,pWndPopupOwner);
}
Post by Voidcoder
Hm, interesting. I think it has nothing to do with the message handlers
or UpdateCmdUI handlers. Please show your code, how do you
add the menu items in your plugin, and especially what item IDs
are you using there.
Post by Janiv Ratson
Hello and thanks,
trying your solution I've encountered a problem that I cannot solve.
There is no message map for the messages, so all the menu item that
were added by the plugin dll, are disabled (grayed) (I think becuase
the system does not know any handler for the messages).
How do I solve it ?
Thanks,
Janiv Ratson.
Post by Voidcoder
An easiest way is to iterate through the plugin DLLs
allowing them to add their own items and proccess
their own commands. You will need at least two
1. void AddMenuItems(CMenu *pMenu)
2. BOOL OnCommand(UINT nCommandID, CMyTreeItemInfo *pItemInfo)
You can save pointers to those functions somewhere
while (FindNextPlugin())
{
plugins[ i ].hModule = LoadLibrary(PluginPath);
plugins[ i ].AddMenuItems = GetProcAddress(plugins[ i ].hModule,
_T("AddMenuItems"));
plugins[ i ].OnCommand = GetProcAddress(plugins[ i ].hModule,
_T("OnCommand"));
}
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(...);
menu.AppendMenu(...);
...
for (i = 0, i < LoadedPlugins; i ++)
{
plugins[ i ].AddMenuItems(&menu);
}
menu.TrackPopupMenu(...);
BOOL CMyView::OnCommand(WPARAM wParam, LPARAM lParam)
{
CMyTreeItemInfo *pItemInfo = GetMyTreeSelectedItem();
for (i = 0, i < LoadedPlugins; i ++)
{
if (plugins[ i ].OnCommand(LOWORD(wParam), pItemInfo))
return TRUE;
}
return FALSE;
}
Post by Janiv Ratson
Hello,
I have an mdi application.
It holds my derived tree control.
I'm trying to write a plugins mechansim.
I want to enable an MFC extension dll, to add to the application
tree control its own menu items.
i.e. My derived tree control context menu consist of Copy, Cut,
Paste and Properties menu items.
I want to enable an MFC extension to add its own menu items to
this context menu, for example: Select, Set Host and Rename.
I also want that the handlers of thoses added menu items to reside
in the MFC Extension dll.
What is the best way to implement this kind of mechanism.
Thanks,
Janiv Ratson.
Ajay Kalra
2006-03-07 15:00:33 UTC
Permalink
The fact that this is done from a plug-in is irrelevant. What matters
is that you want to update/modify your view(treecontrol) from a
Extension DLL. If you can accomplish it by exporting relevant methods
in your module, this can be achieved from within your module or another
Extension DLL. As far as handlers etc are concerned, put all the
methods/callbacks in your module and publish the interface. Typically,
you use Interfaces to communicate between plug-in and the host
application.

--------
Ajay Kalra
***@yahoo.com
Janiv Ratson
2006-03-08 14:24:06 UTC
Permalink
Thanks,
What do you mean by interfaces?
thanks,
Janiv Ratson.
Post by Ajay Kalra
The fact that this is done from a plug-in is irrelevant. What matters
is that you want to update/modify your view(treecontrol) from a
Extension DLL. If you can accomplish it by exporting relevant methods
in your module, this can be achieved from within your module or another
Extension DLL. As far as handlers etc are concerned, put all the
methods/callbacks in your module and publish the interface. Typically,
you use Interfaces to communicate between plug-in and the host
application.
--------
Ajay Kalra
Ajay Kalra
2006-03-08 14:35:58 UTC
Permalink
Interface as in C++ interface. You have been using GetProcAddress etc.
which is not the way you want your clients to do development. YOu
should publish some interface or base classes, which your clients(plug
in developers) can consume. You then communicate with plug-ins thru
these interfaces. This is the basis of an extensible application(app
with plug ins).

------
Ajay Kalra
***@yahoo.com
Janiv Ratson
2006-03-09 13:51:49 UTC
Permalink
Thanks,
What you are saying is obvious.
There will be an interface or SDK or something else, but my problem is
related to the GUI.
I want 3rd party users to be able to add menu items, toolbars adn event
handlers to my application, dynamically. I don't know how to do it, so I'm
asking your help.
It will be appreciated ...
Thanks in advance,
j.
Post by Ajay Kalra
Interface as in C++ interface. You have been using GetProcAddress etc.
which is not the way you want your clients to do development. YOu
should publish some interface or base classes, which your clients(plug
in developers) can consume. You then communicate with plug-ins thru
these interfaces. This is the basis of an extensible application(app
with plug ins).
------
Ajay Kalra
Continue reading on narkive:
Loading...