HOWTO: Write a Dialog-based ActiveX Control Using ATL
ID: Q175503
|
The information in this article applies to:
-
The Microsoft Active Template Library (ATL), versions 2.0, 2.1, 3.0
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 clicking New ATL Object
on the Insert menu, and then 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- 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
}
};
- Derive your control from this new class, instead of CComControl. For
example:
class ATL_NO_VTABLE CMyDlgCtrl :
...
public CComDlgCtrl<CMyDlgCtrl>, // Replaced CComControl
...
- 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 box by clicking Resource on the Insert
menu.
Update class definition to identify this resource. For example:
class ATL_NO_VTABLE CMyDlgCtrl :
...
{
public:
enum { IDD = IDD_MYDIALOG };
...
- 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)
// The next 3 lines are only for Visual C++ 6.0, and should
// replace the CHAIN_MSG_MAP() entry.
MESSAGE_HANDLER(WM_SETFOCUS, CComControlBase::OnSetFocus)
MESSAGE_HANDLER(WM_KILLFOCUS, CComControlBase::OnKillFocus)
MESSAGE_HANDLER(WM_MOUSEACTIVATE,
CComControlBase::OnMouseActivate)
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;
}
- Remove the OnDraw declaration and implementation.
- If you want 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;
}
This step is required only for Visual C++ 5.0 and earlier. The
MESSAGE_HANDLER entry in step 4 above for WM_MOUSEACTIVATE calls
CComControlBase::OnMouseActivate(), which UI activates your control.
- If you want 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;
}
- 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.
© Microsoft Corporation 1997, All Rights Reserved. Contributions by Mark Davis, Microsoft Corporation
Additional query words:
Keywords : kbActiveX kbATL200 kbATL210 kbCOMt kbCtrlCreate kbDlg kbATL300 kbGrpMFCATL
Version : WINDOWS:2.0,2.1,3.0
Platform : WINDOWS
Issue type : kbhowto
|