Menu in ActiveX Controls

Environment: VC6, Windows 2000
It took me some time to figure out how to enable menu in an ATL/MFC ActiveX control and I think the result is simple but instructive. You simply have to change the style of the window of the AX control. ActiveX is the 3rd generation of COM (Basic COM and Automation are the 1st and 2nd) and it added support to the following weeknesses of its predeccessors: lack of user interface, standardized storage, custom events, optimization for the Internet. Basic COM and Automation servers could display and use dialog-boxes but not through the COM system. Being an elementary thing in a user interface, menu is very important.
ATL
Let's create a simple ATL AX Control:
Start Visual C++ and select File/New/ATL COM AppWizard, specify a location and let the project name be ATLMenu. Click OK then click Finish then OK. Now you will insert a Full Control through the menu items Insert/New ATL Object. Select Controls and Full Control, click Next. In the 'Short Name' box enter MyMenu then click on the Miscellaneous tab and click 'Windowed only' then click OK. Now select Insert/Resource/Menu from the VC's menu and click New. Type 'File' then 'MsgBox' in the menu items and ID_MSGBOX as the identifier for the 'MsgBox' menuitem. Choose the ClassView tab of th Workspace window and right click on CMyMenu and select 'Add Windows Message Handler'. Expand the tree if necessary. Select WM_CREATE then click on Add Handler, and OK. Now select the FileView tab of the Workspace window and expand the tree until MyMenu.h. Double click on it and locate the OnCreate function and type:
LRESULT OnCreate( UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
long lStyle;
HMENU hMenu;
lStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
lStyle &= WS_DISABLED;
lStyle |= WS_CAPTION;
//lStyle |= WS_OVERLAPPEDWINDOW;
::SetWindowLong(m_hWnd, GWL_STYLE, lStyle);
hMenu = ::LoadMenu( _Module.GetModuleInstance(),
MAKEINTRESOURCE(IDR_MENU1));
::SetMenu(m_hWnd, hMenu);
return 0;
}
Now you will add the code to handle the message sent by the menu item. Locate the BEGIN_MSG_MAP macro and alter it like this (COMMAND_ID_HANDLER):
BEGIN_MSG_MAP(CMyMenu) CHAIN_MSG_MAP(CComControl<CMyMenu>) DEFAULT_REFLECTION_HANDLER() MESSAGE_HANDLER(WM_CREATE, OnCreate) COMMAND_ID_HANDLER(ID_MSGBOX, OnMsgBox) END_MSG_MAP()
Now add the handler function too and you are ready to compile:
LRESULT OnMsgBox( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { ::MessageBox( m_hWnd, "Hello World!", "From Menu", MB_OK); return 0; }Select Build/Set Active Configuration and set it to Release MinDependency and click OK. Now Build your AX Control by selecting Build/Build ATLMenu.dll. The Wizard automatically generated a MyMenu.html file in your project's folder, double click on it and test your work.
It's interesting that you can drag your AX Control by its caption and move it. You can prevent dragging by overriding WM_NCLBUTTONDOWN:
LRESULT OnNcLButtonDown( UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
// TODO : Add Code for message handler.
// Call DefWindowProc if necessary.
if (HTCAPTION == (INT)wParam)
{
::SetActiveWindow(m_hWnd);
return 1;
}
::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
return 0;
}
You can manipulate your Control by using the interfaces derived from IOleWindow. Add IOleInPlaceObject::SetObjectRects to your Control's class because this will be called by the Container as a response to call to IOleInPlaceSite::OnPosRectChange by your Control or when the user makes changes to the Container's window. When neccessary call OnPosRectChange which is implemented by the Container from your Control(m_spInPlaceSite->OnPosRectChange(&rc) where m_spInPlaceSite is a pointer to the Container's IOleInplaceSite interface).
STDMETHODIMP SetObjectRects( LPCRECT prcPos,
LPCRECT prcClip)
{
//Call ::SetWindowPos Win32 API function
return NOERROR;
}
MFC
It's almost the same as in ATL but it's much easier because of the powerful ClassWizard:
Select File/New/MFC ActiveX Control Wizard and just click next and OK everywhere. Insert menu resource and add menu items. Use ClassWizard to add WM_CREATE, and the menu item handler code to the project. Add the code needed to OnCreate function: see the ATL way above but change from HMENU to CMenu etc or use the Win32 API functions just like in the case of ATL above. Finally add AfxMessageBox("Hello World!") to your menuitem handler code. Build and Register your AX Control(Tools/Register Control menu). The Wizard won't generate .html file this time, so you have to write it or create an MFC AppWizard(exe) container project and test it there.
It's interesting that if you test your MFC control in IE then the window acts like a child of the Control(You can drag it only in the Control's client area), but it has a menu. It's strange because as far as I know a child window can't have a menu. But if you test it in a dialog-based MFC container it works fine.
You should override the WM_NCLBUTTONDOWN message like this in case of MFC:
void CMFCMenuCtrl::OnNcLButtonDown( UINT nHitTest, CPoint point) { if (HTCAPTION == nHitTest) return; COleControl::OnNcLButtonDown(nHitTest, point); }
The pointer to an IOleInPlaceSite interface is m_pInPlaceSite in case of MFC.
Comments
CFontdialog problem
Posted by boda on 09/16/2006 01:08pmI've a problem with how to get the style of the font selected by the CFontDialog plz help
ReplyHOUXIAN
Posted by houxianyong on 07/23/2006 10:26amVery Good
Posted by MurtuzaArif on 08/10/2004 06:16amI like the way it is explained
Replyadding a dialog box and Db addition
Posted by Legacy on 11/13/2003 12:00amOriginally posted by: dharani
hello auther and all
Replyits a nice article . I have a outlook plugin which when registered will enable two buttons to be added to the Outlook application's toolbar . but when i click the buttons there is a message box fired but when i tried to fire a dialog boxfrom within the OnButtonClick() function of my app it simply does nt execute dlg.DoModal() .Bfeore adding this i recreated the whole plugin with MFC support still the problem is there . replies welcome
thanks in advance
dharanibabus@hotmail.com
how to implement accelerator keys for menu items
Posted by Legacy on 01/23/2003 12:00amOriginally posted by: bhavani
Hi Gurus,
ReplyThis concept is ok.But i want to know how I can place accelerator keys in menu items.I have taken another active-x control in one dialogbox.I placed menu.But the accelerator keys are not working in my component.In previous time otherthan menu accelerator keys are working fine.Can anyone guide me or give me some code.
Thanks....
Menu in Active X Controls
Posted by Legacy on 11/30/2002 12:00amOriginally posted by: Mohammed Yacoob
I tried out a simple active x control which works out great in TestContainer but not in IE. When a message box or dialog is used inside the exported method (not in OnCreate), the WWW service crashes.
ReplyPlz help!!!
Succesful in IE, but not in Testcontainer
Posted by Legacy on 07/29/2002 12:00amOriginally posted by: Matthias
Thank you very much for the very helpful sourcecode.
I tried the ATL and MFC version and both worked corretly in the Internet Explorer.
But when I try to start them in the Testcontainer (TSTCON32.EXE) the execution totally fails.
Has someone made similar experiences?
Are ActiveX-Conrols with menus conform to the MS-specifications or are they just a work-around, which are not advised to be used in a professional environment.
Greetings from Germany
Matthias
ReplyHow about in Windows 98
Posted by Legacy on 06/09/2002 12:00amOriginally posted by: Minh Tam
Thank you!
How can I test it in Windows 98.
Reply
Menus are disabled
Posted by Legacy on 06/06/2002 12:00amOriginally posted by: Sanjay
How can I make a menu having many changeable language?
Posted by Legacy on 05/22/2002 12:00amOriginally posted by: Heros
I'm very interested in your ActiveX. You are a man of great talent. Can you help me a way for creating an ActiveX Menu having may changeable language.
ReplyThanks for yor help
Yours sincerely
Heros
Loading, Please Wait ...