HOWTO: Write a Dialog-based ActiveX Control Using ATL

Last reviewed: November 17, 1997
Article ID: Q175503
The information in this article applies to:
  • The Microsoft Active Template Library (ATL), versions 2.0, 2.1

SUMMARY

When writing ActiveX controls with the Active Template Library (ATL), it may be useful to create your control based on a dialog box template. This allows you to take advantage of the Visual C++ resource editor to lay out contained controls or to reuse existing MFC dialog box templates and Visual Basic forms.

You add an ActiveX control to your ATL project by selecting the Insert- >'New ATL Object' menu item and clicking either Full Control or Internet Explorer Control. On completion, the ATL Object Wizard generates code that includes a class derived from CComControl, which further derives from CWindowImpl.

This article demonstrates how to derive your control class from CDialogImpl and associate a dialog box template with this class. This article also demonstrates providing support for UI activation and navigation keys.

MORE INFORMATION

  1. Declare your own class, based on CComControl, which is derived from CDialogImpl instead of CWindowImpl. The original definition of CComControl can be found in ATLCTL.H. For example:

          template <class T>
          class ATL_NO_VTABLE CComDlgCtrl : public CComControlBase,
    
             public CDialogImpl<T>
          {
          public:
             CComDlgCtrl() : CComControlBase(m_hWnd) {}
             HRESULT FireOnRequestEdit(DISPID dispID)
             {
                T* pT = static_cast<T*>(this);
                return T::__ATL_PROP_NOTIFY_EVENT_CLASS::FireOnRequestEdit
                   (pT->GetUnknown(), dispID);
             }
             HRESULT FireOnChanged(DISPID dispID)
             {
                T* pT = static_cast<T*>(this);
                return T::__ATL_PROP_NOTIFY_EVENT_CLASS::FireOnChanged
                   (pT->GetUnknown(), dispID);
             }
             virtual HRESULT ControlQueryInterface(const IID& iid, void** ppv)
             {
                T* pT = static_cast<T*>(this);
                return pT->_InternalQueryInterface(iid, ppv);
             }
             virtual HWND CreateControlWindow(HWND hWndParent, RECT& rcPos)
             {
                T* pT = static_cast<T*>(this);
                return pT->Create(hWndParent);
                // CDialogImpl::Create differs from CWindowImpl
             }
          };
    
    

  2. Derive your control from this new class, instead of CComControl. For example:

          class ATL_NO_VTABLE CMyDlgCtrl :
          ...
    
             public CComDlgCtrl<CMyDlgCtrl>, // Replaced CComControl
          ...
    
    

  3. Create your dialog template and make sure it is marked as a "Child" template. This will set up correctly if you use the IDD_FORMVIEW dialog subtype when creating the dialog using the Insert->Resource menu item.

    Update class definition to identify this resource. For example:

          class ATL_NO_VTABLE CMyDlgCtrl :
          ...
          {
          public:
    
             enum { IDD = IDD_MYDIALOG };
          ...
    
    

  4. Declare and implement a message handler for WM_INITDIALOG and any required message, command, and notify handlers. For example:

          BEGIN_MSG_MAP(CMyDlgCtrl)
    
             MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
             COMMAND_ID_HANDLER(IDC_SOMECOMMAND, OnSomeCommand)
          END_MSG_MAP()
    
          ...
          LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,
             BOOL&bHandled)
          {
             InPlaceActivate( OLEIVERB_UIACTIVATE );
             // Perform any dialog initialization
             return FALSE;
          }
          LRESULT OnSomeCommand(WORD wNotifyCode,WORD wID,HWND hWndCtl,
             BOOL&bHandled)
          {
             // Perform operation for this command.
             return 0;
          }
    
    

  5. Remove the OnDraw declaration and implementation.

  6. If you wish to handle UI activation of your control correctly, add a WM_MOUSEACTIVATE message handler to call CComControl::InPlaceActivate. For example:

          BEGIN_MSG_MAP(CMyDlgCtrl)
    
             ...
             MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
          END_MSG_MAP()
          ...
          LRESULT OnMouseActivate(UINT uMsg,WPARAM wParam,LPARAM lParam,
             BOOL&bHandled)
          {
             // UI-Activate control
             InPlaceActivate( OLEIVERB_UIACTIVATE );
             return FALSE;
          }
    
    

  7. If you wish to handle tabbing and other navigation keys correctly, override IOleInPlaceActiveObjectImpl::TranslateAccelerator. For example:

          STDMETHOD(TranslateAccelerator)(MSG *pMsg)
          {
    
             if ( ( pMsg->message < WM_KEYFIRST
                 || pMsg->message > WM_KEYLAST )
               && ( pMsg->message < WM_MOUSEFIRST
                 || pMsg->message > WM_MOUSELAST ) )
                return S_FALSE;
             return ( IsDialogMessage( m_hWnd, pMsg ) ) ? S_OK : S_FALSE;
          }
    
    

  8. Depending on how you created the control, you need to set the m_bWindowOnly variable to 1 in your control's constructor to force the control to be non-Windowless. For example:

          CMyDlgCtrl()
          {
    
             m_bWindowOnly = 1;
          }
    
    
(c) Microsoft Corporation 1997, All Rights Reserved. Contributions by Mark Davis, Microsoft Corporation
Keywords          : AtlControl AXSDKControls
Technology        : kbole
Version           : WINDOWS:2.0,2.1
Platform          : WINDOWS
Issue type        : kbhowto
Solution Type     : kbsample


================================================================================


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: November 17, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.