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:08pm

    I've a problem with how to get the style of the font selected by the CFontDialog plz help

    Reply
  • HOUXIAN

    Posted by houxianyong on 07/23/2006 10:26am

    This is very good Ex

    Reply
  • Very Good

    Posted by MurtuzaArif on 08/10/2004 06:16am

    I like the way it is explained

    Reply
  • adding a dialog box and Db addition

    Posted by Legacy on 11/13/2003 12:00am

    Originally posted by: dharani

    hello auther and all
    its 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

    Reply
  • how to implement accelerator keys for menu items

    Posted by Legacy on 01/23/2003 12:00am

    Originally posted by: bhavani

    Hi Gurus,
    This 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....

    Reply
  • Menu in Active X Controls

    Posted by Legacy on 11/30/2002 12:00am

    Originally 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.
    Plz help!!!

    Reply
  • Succesful in IE, but not in Testcontainer

    Posted by Legacy on 07/29/2002 12:00am

    Originally 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

    Reply
  • How about in Windows 98

    Posted by Legacy on 06/09/2002 12:00am

    Originally 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:00am

    Originally posted by: Sanjay

    Hi! I have written an activex control that contains an active document (MSWORD). I tried to generate a menu in the active x control (using MFC) and my code is as follows:
    
    

    long lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
    lStyle &= WS_DISABLED;
    lStyle |= WS_CAPTION;
    SetWindowLong(m_hWnd, GWL_STYLE, lStyle);

    //== Loading in the main menu ==\\
    CMenu menu;
    menu.LoadMenu(IDR_TESTMENU);
    OnActivateInPlace (TRUE, NULL);

    The menu does appear and you click on the buttons but they appear grayed out and do nothing. And yes I have set the menu items to run simple functions.

    Note the menu appears when I run the activex control in IE whereas in the activex test container (VC++) it doesnt even appear.

    Any help is ***DEEPLY*** appreciated,

    Sanjay

    Reply
  • How can I make a menu having many changeable language?

    Posted by Legacy on 05/22/2002 12:00am

    Originally 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.
    Thanks for yor help
    Yours sincerely
    Heros

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds